void initHuman(Entity* my, Stat* myStats) { int c; node_t* node; my->initMonster(113); if ( multiplayer != CLIENT ) { MONSTER_SPOTSND = -1; MONSTER_SPOTVAR = 1; MONSTER_IDLESND = -1; MONSTER_IDLEVAR = 1; } if ( multiplayer != CLIENT && !MONSTER_INIT ) { if ( myStats != nullptr ) { if ( !myStats->leader_uid ) { myStats->leader_uid = 0; } my->createPathBoundariesNPC(); Stat baseStats(HUMAN); bool isDefaultStats = isMonsterStatsDefault(*myStats); // apply random stat increases if set in stat_shared.cpp or editor setRandomMonsterStats(myStats); // generate 6 items max, less if there are any forced items from boss variants int customItemsToGenerate = ITEM_CUSTOM_SLOT_LIMIT; // special human variant (named or Zap Brigadier), do not generate any other items int specialMonsterVariant = 0; // boss variants // generate special loadout if ( my->monsterSpecialTimer == 0 ) { if ( rand() % 25 == 0 ) { specialMonsterVariant = 1; int specialMonsterType = rand() % 10; if ( !strncmp(map.name, "Hamlet", 6) ) { while ( specialMonsterType == 6 ) // 2 spiders that spawn cause aggro issues in Hamlet. { specialMonsterType = rand() % 10; } } switch ( rand() % 10 ) { case 0: // red riding hood strcpy(myStats->name, "Red Riding Hood"); myStats->appearance = 2; myStats->sex = FEMALE; myStats->LVL = 1; myStats->HP = 10; myStats->MAXHP = myStats->HP; myStats->MP = 10; myStats->MAXMP = myStats->MP; myStats->STR = 0; myStats->DEX = 0; myStats->CON = 0; myStats->INT = -2; myStats->PER = -2; myStats->CHR = 4; myStats->helmet = newItem(HAT_PHRYGIAN, EXCELLENT, 1, 1, rand(), false, nullptr); myStats->cloak = newItem(CLOAK, EXCELLENT, 1, 1, 2, false, nullptr); myStats->weapon = newItem(QUARTERSTAFF, EXCELLENT, 1, 1, rand(), false, nullptr); break; case 1: // king arthur strcpy(myStats->name, "King Arthur"); myStats->appearance = 0; myStats->sex = MALE; myStats->LVL = 10; myStats->HP = 100; myStats->MAXHP = myStats->HP; myStats->MP = 100; myStats->MAXMP = myStats->MP; myStats->STR = 5; myStats->DEX = 5; myStats->CON = 5; myStats->INT = 5; myStats->PER = 5; myStats->CHR = 5; myStats->breastplate = newItem(STEEL_BREASTPIECE, EXCELLENT, 1, 1, 1, true, nullptr); myStats->gloves = newItem(GAUNTLETS, EXCELLENT, 1, 1, 1, true, nullptr); myStats->shoes = newItem(STEEL_BOOTS, EXCELLENT, 1, 1, 1, true, nullptr); myStats->cloak = newItem(CLOAK, EXCELLENT, 2, 1, 2, true, nullptr); myStats->weapon = newItem(ARTIFACT_SWORD, EXCELLENT, 1, 1, rand(), true, nullptr); myStats->shield = newItem(STEEL_SHIELD_RESISTANCE, EXCELLENT, 1, 1, 1, true, nullptr); break; case 2: // merlin strcpy(myStats->name, "Merlin"); myStats->appearance = 5; myStats->sex = MALE; myStats->LVL = 10; myStats->HP = 60; myStats->MAXHP = myStats->HP; myStats->MP = 200; myStats->MAXMP = myStats->MP; myStats->STR = 2; myStats->DEX = 2; myStats->CON = 3; myStats->INT = 11; myStats->PER = 10; myStats->CHR = 2; myStats->helmet = newItem(HAT_WIZARD, EXCELLENT, 2, 1, 2, false, nullptr); myStats->shoes = newItem(LEATHER_BOOTS_SPEED, EXCELLENT, 2, 1, 2, false, nullptr); myStats->cloak = newItem(CLOAK_PROTECTION, EXCELLENT, 5, 1, 3, false, nullptr); myStats->weapon = newItem(MAGICSTAFF_LIGHTNING, EXCELLENT, 2, 1, 2, false, nullptr); myStats->amulet = newItem(AMULET_MAGICREFLECTION, EXCELLENT, 2, 1, 2, false, nullptr); break; case 3: // robin hood strcpy(myStats->name, "Robin Hood"); myStats->appearance = 1; myStats->sex = MALE; myStats->LVL = 5; myStats->HP = 70; myStats->MAXHP = myStats->HP; myStats->MP = 50; myStats->MAXMP = myStats->MP; myStats->STR = 3; myStats->DEX = 5; myStats->CON = 3; myStats->INT = 2; myStats->PER = 3; myStats->CHR = 5; myStats->gloves = newItem(GLOVES, EXCELLENT, 1, 1, 3, true, nullptr); myStats->shoes = newItem(LEATHER_BOOTS, SERVICABLE, 1, 1, 3, true, nullptr); myStats->cloak = newItem(CLOAK, EXCELLENT, 1, 1, 0, true, nullptr); myStats->weapon = newItem(SHORTBOW, EXCELLENT, 1, 1, 3, true, nullptr); break; case 4: // conan strcpy(myStats->name, "Conan the Barbarian"); myStats->appearance = 7; myStats->sex = MALE; myStats->LVL = 10; myStats->HP = 100; myStats->MAXHP = myStats->HP; myStats->MP = 20; myStats->MAXMP = myStats->MP; myStats->STR = 10; myStats->DEX = 5; myStats->CON = 10; myStats->INT = 3; myStats->PER = 3; myStats->CHR = 20; myStats->helmet = newItem(LEATHER_HELM, EXCELLENT, 2, 1, rand(), false, nullptr); myStats->shield = newItem(WOODEN_SHIELD, EXCELLENT, 2, 1, rand(), false, nullptr); myStats->weapon = newItem(STEEL_AXE, EXCELLENT, 2, 1, rand(), false, nullptr); break; case 5: // othello strcpy(myStats->name, "Othello"); myStats->appearance = 14; myStats->sex = MALE; myStats->LVL = 10; myStats->HP = 50; myStats->MAXHP = myStats->HP; myStats->MP = 20; myStats->MAXMP = myStats->MP; myStats->STR = 3; myStats->DEX = 3; myStats->CON = 3; myStats->INT = 3; myStats->PER = 0; myStats->CHR = 30; myStats->gloves = newItem(BRACERS, EXCELLENT, -1, 1, rand(), false, nullptr); myStats->breastplate = newItem(IRON_BREASTPIECE, EXCELLENT, 1, 1, rand(), false, nullptr); myStats->weapon = newItem(STEEL_SWORD, EXCELLENT, 2, 1, rand(), false, nullptr); myStats->cloak = newItem(CLOAK, EXCELLENT, 0, 1, 2, false, nullptr); break; case 6: // anansi strcpy(myStats->name, "Anansi"); myStats->appearance = 15; myStats->sex = MALE; myStats->LVL = 20; myStats->HP = 100; myStats->MAXHP = myStats->HP; myStats->MP = 100; myStats->MAXMP = myStats->MP; myStats->STR = 5; myStats->DEX = 8; myStats->CON = 5; myStats->INT = 20; myStats->PER = 20; myStats->CHR = 10; myStats->helmet = newItem(HAT_JESTER, EXCELLENT, 5, 1, rand(), false, nullptr); myStats->weapon = newItem(ARTIFACT_MACE, EXCELLENT, 1, 1, rand(), false, nullptr); int c; for ( c = 0; c < 2; c++ ) { Entity* entity = summonMonster(SPIDER, my->x, my->y); if ( entity ) { entity->parent = my->getUID(); entity->flags[USERFLAG2] = true; } } break; case 7: // oya strcpy(myStats->name, "Oya"); myStats->appearance = 13; myStats->sex = FEMALE; myStats->LVL = 20; myStats->HP = 100; myStats->MAXHP = myStats->HP; myStats->MP = 100; myStats->MAXMP = myStats->MP; myStats->STR = 4; myStats->DEX = 10; myStats->CON = 2; myStats->INT = 20; myStats->PER = 10; myStats->CHR = 10; myStats->cloak = newItem(CLOAK_PROTECTION, EXCELLENT, 3, 1, 1, false, nullptr); myStats->helmet = newItem(HAT_HOOD, EXCELLENT, 3, 1, 1, false, nullptr); break; case 8: // vishpala strcpy(myStats->name, "Vishpala"); myStats->appearance = 17; myStats->sex = FEMALE; myStats->LVL = 10; myStats->HP = 70; myStats->MAXHP = myStats->HP; myStats->MP = 20; myStats->MAXMP = myStats->MP; myStats->STR = 5; myStats->DEX = 5; myStats->CON = 5; myStats->INT = 5; myStats->PER = 5; myStats->CHR = 10; myStats->cloak = newItem(CLOAK, EXCELLENT, 0, 1, 2, false, nullptr); myStats->breastplate = newItem(IRON_BREASTPIECE, EXCELLENT, 0, 1, rand(), false, nullptr); myStats->shoes = newItem(IRON_BOOTS, EXCELLENT, 0, 1, rand(), false, nullptr); myStats->weapon = newItem(ARTIFACT_SPEAR, EXCELLENT, 1, 1, rand(), false, nullptr); myStats->shield = newItem(BRONZE_SHIELD, EXCELLENT, 1, 1, rand(), false, nullptr); break; case 9: // kali strcpy(myStats->name, "Kali"); myStats->appearance = 15; myStats->sex = FEMALE; myStats->LVL = 20; myStats->HP = 200; myStats->MAXHP = myStats->HP; myStats->MP = 200; myStats->MAXMP = myStats->MP; myStats->STR = 5; myStats->DEX = 5; myStats->CON = 5; myStats->INT = 20; myStats->PER = 20; myStats->CHR = 20; myStats->cloak = newItem(CLOAK_MAGICREFLECTION, EXCELLENT, 1, 1, 2, false, nullptr); myStats->shoes = newItem(LEATHER_BOOTS_SPEED, EXCELLENT, 1, 1, rand(), false, nullptr); myStats->weapon = newItem(SPELLBOOK_FIREBALL, EXCELLENT, 1, 1, rand(), false, nullptr); break; default: break; } } } else { specialMonsterVariant = 1; // zap brigadier strcpy(myStats->name, "ZAP Brigadier"); myStats->appearance = 1; myStats->sex = static_cast<sex_t>(rand() % 2); myStats->LVL = 10; myStats->HP = 100; myStats->MAXHP = myStats->HP; myStats->MP = 200; myStats->MAXMP = myStats->MP; myStats->STR = 3; myStats->DEX = 3; myStats->CON = 3; myStats->INT = 3; myStats->PER = 10; myStats->CHR = 10; myStats->helmet = newItem(HAT_HOOD, EXCELLENT, 2, 1, 3, false, nullptr); myStats->gloves = newItem(GLOVES, EXCELLENT, 0, 1, 2, false, nullptr); myStats->shoes = newItem(LEATHER_BOOTS_SPEED, EXCELLENT, 0, 1, 2, false, nullptr); myStats->breastplate = newItem(LEATHER_BREASTPIECE, EXCELLENT, 0, 1, 2, false, nullptr); myStats->cloak = newItem(CLOAK_PROTECTION, EXCELLENT, 2, 1, 3, false, nullptr); myStats->weapon = newItem(MAGICSTAFF_LIGHTNING, EXCELLENT, 1, 1, 2, false, nullptr); myStats->amulet = newItem(AMULET_MAGICREFLECTION, EXCELLENT, 1, 1, 2, false, nullptr); } // random effects if ( rand() % 10 == 0 ) { myStats->EFFECTS[EFF_ASLEEP] = true; myStats->EFFECTS_TIMERS[EFF_ASLEEP] = 1800 + rand() % 1800; } // generates equipment and weapons if available from editor createMonsterEquipment(myStats); // create any custom inventory items from editor if available createCustomInventory(myStats, customItemsToGenerate); // count if any custom inventory items from editor int customItems = countCustomItems(myStats); //max limit of 6 custom items per entity. // count any inventory items set to default in edtior int defaultItems = countDefaultItems(myStats); if ( specialMonsterVariant == 0 && my->monsterStoreType > 0 && isDefaultStats ) { myStats->EXP += 100 * my->monsterStoreType; // apply experience to level up the humans with floor depth. } // generate the default inventory items for the monster, provided the editor sprite allowed enough default slots switch ( defaultItems ) { case 6: case 5: case 4: case 3: case 2: case 1: break; default: break; } if ( specialMonsterVariant == 0 ) { // generate random equipment if not a named special human //give shield if ( myStats->shield == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_SHIELD] == 1 ) { switch ( rand() % 10 ) { case 0: case 1: case 2: myStats->shield = newItem(TOOL_TORCH, SERVICABLE, 0, 1, rand(), false, nullptr); break; case 3: case 4: break; case 5: case 6: myStats->shield = newItem(WOODEN_SHIELD, WORN, 0, 1, rand(), false, nullptr); break; case 7: case 8: myStats->shield = newItem(BRONZE_SHIELD, WORN, 0, 1, rand(), false, nullptr); break; case 9: myStats->shield = newItem(IRON_SHIELD, WORN, 0, 1, rand(), false, nullptr); break; } } //give weapon if ( myStats->weapon == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_WEAPON] == 1 ) { switch ( rand() % 10 ) { case 0: case 1: myStats->weapon = newItem(SHORTBOW, WORN, 0, 1, rand(), false, nullptr); break; case 2: case 3: myStats->weapon = newItem(BRONZE_AXE, WORN, 0, 1, rand(), false, nullptr); break; case 4: case 5: myStats->weapon = newItem(BRONZE_SWORD, WORN, 0, 1, rand(), false, nullptr); break; case 6: myStats->weapon = newItem(IRON_SPEAR, WORN, 0, 1, rand(), false, nullptr); break; case 7: myStats->weapon = newItem(IRON_AXE, WORN, 0, 1, rand(), false, nullptr); break; case 8: myStats->weapon = newItem(IRON_SWORD, WORN, 0, 1, rand(), false, nullptr); break; case 9: myStats->weapon = newItem(CROSSBOW, WORN, 0, 1, rand(), false, nullptr); break; } } // give helmet if ( myStats->helmet == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_HELM] == 1 ) { switch ( rand() % 10 ) { case 0: case 1: case 2: break; case 3: myStats->helmet = newItem(HAT_HOOD, WORN, 0, 1, rand() % 4, false, nullptr); break; case 4: myStats->helmet = newItem(HAT_PHRYGIAN, WORN, 0, 1, rand(), false, nullptr); break; case 5: myStats->helmet = newItem(HAT_WIZARD, WORN, 0, 1, rand(), false, nullptr); break; case 6: case 7: myStats->helmet = newItem(LEATHER_HELM, WORN, 0, 1, rand(), false, nullptr); break; case 8: case 9: myStats->helmet = newItem(IRON_HELM, WORN, 0, 1, rand(), false, nullptr); break; } } // give cloak if ( myStats->cloak == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_CLOAK] == 1 ) { switch ( rand() % 10 ) { case 0: case 1: case 2: case 3: case 4: case 5: break; case 6: case 7: case 8: myStats->cloak = newItem(CLOAK, WORN, 0, 1, rand(), false, nullptr); break; case 9: myStats->cloak = newItem(CLOAK_MAGICREFLECTION, WORN, 0, 1, rand(), false, nullptr); break; } } // give armor if ( myStats->breastplate == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_ARMOR] == 1 ) { switch ( rand() % 10 ) { case 0: case 1: case 2: case 3: case 4: break; case 5: case 6: case 7: myStats->breastplate = newItem(LEATHER_BREASTPIECE, WORN, 0, 1, rand(), false, nullptr); break; case 8: case 9: myStats->breastplate = newItem(IRON_BREASTPIECE, WORN, 0, 1, rand(), false, nullptr); break; } } // give gloves if ( myStats->gloves == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_GLOVES] == 1 ) { switch ( rand() % 10 ) { case 0: case 1: case 2: case 3: case 4: break; case 5: case 6: case 7: myStats->gloves = newItem(GLOVES, WORN, 0, 1, rand(), false, nullptr); break; case 8: case 9: myStats->gloves = newItem(GAUNTLETS, WORN, 0, 1, rand(), false, nullptr); break; } } // give boots if ( myStats->shoes == nullptr && myStats->EDITOR_ITEMS[ITEM_SLOT_BOOTS] == 1 ) { switch ( rand() % 10 ) { case 0: case 1: case 2: case 3: case 4: break; case 5: case 6: case 7: myStats->shoes = newItem(LEATHER_BOOTS, WORN, 0, 1, rand(), false, nullptr); break; case 8: case 9: myStats->shoes = newItem(IRON_BOOTS, WORN, 0, 1, rand(), false, nullptr); break; } } } } } // torso Entity* entity = newEntity(106, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][1][0]; // 0 entity->focaly = limbs[HUMAN][1][1]; // 0 entity->focalz = limbs[HUMAN][1][2]; // 0 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); // right leg entity = newEntity(107, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][2][0]; // 0 entity->focaly = limbs[HUMAN][2][1]; // 0 entity->focalz = limbs[HUMAN][2][2]; // 2 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); // left leg entity = newEntity(108, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][3][0]; // 0 entity->focaly = limbs[HUMAN][3][1]; // 0 entity->focalz = limbs[HUMAN][3][2]; // 2 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); // right arm entity = newEntity(109, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][4][0]; // 0 entity->focaly = limbs[HUMAN][4][1]; // 0 entity->focalz = limbs[HUMAN][4][2]; // 1.5 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); // left arm entity = newEntity(110, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][5][0]; // 0 entity->focaly = limbs[HUMAN][5][1]; // 0 entity->focalz = limbs[HUMAN][5][2]; // 1.5 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); // world weapon entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][6][0]; // 1.5 entity->focaly = limbs[HUMAN][6][1]; // 0 entity->focalz = limbs[HUMAN][6][2]; // -.5 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); entity->pitch = .25; node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); // shield entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][7][0]; // 2 entity->focaly = limbs[HUMAN][7][1]; // 0 entity->focalz = limbs[HUMAN][7][2]; // 0 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); // cloak entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->scalex = 1.01; entity->scaley = 1.01; entity->scalez = 1.01; entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][8][0]; // 0 entity->focaly = limbs[HUMAN][8][1]; // 0 entity->focalz = limbs[HUMAN][8][2]; // 4 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); // helmet entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->scalex = 1.01; entity->scaley = 1.01; entity->scalez = 1.01; entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][9][0]; // 0 entity->focaly = limbs[HUMAN][9][1]; // 0 entity->focalz = limbs[HUMAN][9][2]; // -1.75 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); // mask entity = newEntity(-1, 0, map.entities, nullptr); //Limb entity. entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->getUID(); entity->scalex = .99; entity->scaley = .99; entity->scalez = .99; entity->flags[PASSABLE] = true; entity->flags[NOUPDATE] = true; entity->flags[USERFLAG2] = my->flags[USERFLAG2]; entity->focalx = limbs[HUMAN][10][0]; // 0 entity->focaly = limbs[HUMAN][10][1]; // 0 entity->focalz = limbs[HUMAN][10][2]; // .5 entity->behavior = &actHumanLimb; entity->parent = my->getUID(); node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity*); my->bodyparts.push_back(entity); if ( multiplayer == CLIENT ) { my->sprite = 113; // human head model return; } // set head model if ( myStats->appearance < 5 ) { my->sprite = 113 + 12 * myStats->sex + myStats->appearance; } else if ( myStats->appearance == 5 ) { my->sprite = 332 + myStats->sex; } else if ( myStats->appearance >= 6 && myStats->appearance < 12 ) { my->sprite = 341 + myStats->sex * 13 + myStats->appearance - 6; } else if ( myStats->appearance >= 12 ) { my->sprite = 367 + myStats->sex * 13 + myStats->appearance - 12; } else { my->sprite = 113; // default } }
void initShopkeeper(Entity *my, stat_t *myStats) { int c; node_t *node; my->sprite = 217; //my->flags[GENIUS]=TRUE; my->flags[UPDATENEEDED]=TRUE; my->flags[BLOCKSIGHT]=TRUE; my->flags[INVISIBLE]=FALSE; if( multiplayer!=CLIENT ) { MONSTER_SPOTSND = -1; MONSTER_SPOTVAR = 1; MONSTER_IDLESND = -1; MONSTER_IDLEVAR = 1; } if( multiplayer!=CLIENT && !MONSTER_INIT ) { if( myStats ) { for( c=0; c<std::max(NUMPROFICIENCIES,NUMEFFECTS); c++ ) { if( c<NUMPROFICIENCIES ) myStats->PROFICIENCIES[c]=0; if( c<NUMEFFECTS ) { myStats->EFFECTS[c]=FALSE; myStats->EFFECTS_TIMERS[c]=0; } } } int x, y; MONSTER_SHOPXS = my->x/16; MONSTER_SHOPXE = my->x/16; MONSTER_SHOPYS = my->y/16; MONSTER_SHOPYE = my->y/16; for( x=my->x; x>=0; x-=16 ) { if( !checkObstacle(x,my->y,my,NULL) ) MONSTER_SHOPXS = x; else break; } for( x=my->x; x<map.width<<4; x+=16 ) { if( !checkObstacle(x,my->y,my,NULL) ) MONSTER_SHOPXE = x; else break; } for( y=my->y; y>=0; y-=16 ) { if( !checkObstacle(my->x,y,my,NULL) ) MONSTER_SHOPYS = y; else break; } for( y=my->y; y<map.height<<4; y+=16 ) { if( !checkObstacle(my->x,y,my,NULL) ) MONSTER_SHOPYE = y; else break; } for( x=MONSTER_SHOPXS-16; x<=MONSTER_SHOPXE+16; x+=16 ) { for( y=MONSTER_SHOPYS-16; y<=MONSTER_SHOPYE+16; y+=16 ) { if( x/16>=0 && x/16<map.width && y/16>=0 && y/16<map.height ) shoparea[y/16+(x/16)*map.height] = TRUE; } } myStats->sex = MALE; myStats->appearance = rand(); strcpy(myStats->name,language[158+rand()%26]); myStats->inventory.first = NULL; myStats->inventory.last = NULL; myStats->HP = 300; myStats->MAXHP = 300; myStats->MP = 200; myStats->MAXMP = 200; myStats->OLDHP = myStats->HP; myStats->STR = 10; myStats->DEX = 4; myStats->CON = 10; myStats->INT = 7; myStats->PER = 7; myStats->CHR = 3+rand()%4; myStats->EXP = 0; myStats->LVL = 10; myStats->GOLD = 300+rand()%200; myStats->HUNGER = 900; if( !myStats->leader_uid ) myStats->leader_uid = 0; myStats->FOLLOWERS.first=NULL; myStats->FOLLOWERS.last=NULL; myStats->PROFICIENCIES[PRO_MAGIC]=50; myStats->PROFICIENCIES[PRO_SPELLCASTING]=50; myStats->PROFICIENCIES[PRO_TRADING]=75; myStats->PROFICIENCIES[PRO_APPRAISAL]=75; myStats->helmet = NULL; myStats->breastplate = NULL; myStats->gloves = NULL; myStats->shoes = NULL; myStats->shield = NULL; myStats->weapon = NULL; myStats->cloak = NULL; myStats->amulet = NULL; myStats->ring = NULL; myStats->mask = NULL; myStats->weapon = newItem(SPELLBOOK_MAGICMISSILE,EXCELLENT,0,1,0,FALSE,NULL); if( rand()%20==0 ) { myStats->EFFECTS[EFF_ASLEEP] = TRUE; myStats->EFFECTS_TIMERS[EFF_ASLEEP] = 1800+rand()%3600; } // give shopkeeper items MONSTER_STORETYPE = rand()%9; if( MONSTER_STORETYPE==8 ) MONSTER_STORETYPE++; int numitems = 10+rand()%5; switch( MONSTER_STORETYPE ) { case 0: // arms & armor store for( c=0; c<numitems; c++ ) { if( rand()%2 ) { newItem( static_cast<ItemType>(rand()%20), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%4, rand(), FALSE, &myStats->inventory ); } else { int i=rand()%21; if( i<18 ) newItem( static_cast<ItemType>(GLOVES+i), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%4, rand(), FALSE, &myStats->inventory ); else newItem( static_cast<ItemType>(GLOVES+i+4), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%6, rand(), FALSE, &myStats->inventory ); } } break; case 1: // hat store for( c=0; c<numitems; c++ ) { newItem( static_cast<ItemType>(HAT_PHRYGIAN+rand()%7), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%6, rand(), FALSE, &myStats->inventory ); } break; case 2: // jewelry store for( c=0; c<numitems; c++ ) { switch( rand()%3 ) { case 0: newItem( static_cast<ItemType>(AMULET_SEXCHANGE+rand()%6), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), FALSE, &myStats->inventory ); break; case 1: newItem( static_cast<ItemType>(RING_ADORNMENT+rand()%12), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), FALSE, &myStats->inventory ); break; case 2: newItem( static_cast<ItemType>(GEM_GARNET+rand()%16), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), FALSE, &myStats->inventory ); break; } } break; case 3: // bookstore for( c=0; c<numitems; c++ ) { switch( rand()%3 ) { case 0: newItem( static_cast<ItemType>(SPELLBOOK_FORCEBOLT+rand()%22), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), TRUE, &myStats->inventory ); break; case 1: newItem( static_cast<ItemType>(SCROLL_MAIL+rand()%14), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), TRUE, &myStats->inventory ); break; case 2: newItem( READABLE_BOOK, static_cast<Status>(WORN+rand()%3), 0, 1+rand()%3, rand(), FALSE, &myStats->inventory ); break; } } break; case 4: // apothecary for( c=0; c<numitems; c++ ) { newItem( static_cast<ItemType>(POTION_WATER+rand()%15), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%5, rand(), TRUE, &myStats->inventory ); } break; case 5: // staff shop for( c=0; c<numitems; c++ ) { newItem( static_cast<ItemType>(MAGICSTAFF_LIGHT+rand()%10), static_cast<Status>(WORN+rand()%3), 0, 1, 1, TRUE, &myStats->inventory ); } break; case 6: // food store for( c=0; c<numitems; c++ ) { newItem( static_cast<ItemType>(FOOD_BREAD+rand()%7), static_cast<Status>(SERVICABLE+rand()%2), 0, 1+rand()%3, rand(), FALSE, &myStats->inventory ); } break; case 7: // hardware store for( c=0; c<numitems; c++ ) { newItem( static_cast<ItemType>(TOOL_PICKAXE+rand()%11), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%3, rand(), FALSE, &myStats->inventory ); } break; case 8: // lighting store for( c=0; c<numitems; c++ ) { newItem( static_cast<ItemType>(TOOL_TORCH+rand()%2), EXCELLENT, 0, 1, 7, FALSE, &myStats->inventory ); } break; case 9: // general store for( c=0; c<numitems; c++ ) { newItem( static_cast<ItemType>(rand()%(NUMITEMS-(NUMITEMS-SPELL_ITEM))), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%3, rand(), FALSE, &myStats->inventory ); } break; } } // torso Entity *entity = newEntity(218, 0, map.entities); entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->uid; entity->flags[PASSABLE]=TRUE; entity->flags[NOUPDATE]=TRUE; entity->flags[USERFLAG2]=my->flags[USERFLAG2]; entity->focalx = limbs[SHOPKEEPER][1][0]; // 0 entity->focaly = limbs[SHOPKEEPER][1][1]; // 0 entity->focalz = limbs[SHOPKEEPER][1][2]; // 0 entity->behavior=&actShopkeeperLimb; entity->parent=my->uid; node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity *); // right leg entity = newEntity(222, 0, map.entities); entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->uid; entity->flags[PASSABLE]=TRUE; entity->flags[NOUPDATE]=TRUE; entity->flags[USERFLAG2]=my->flags[USERFLAG2]; entity->focalx = limbs[SHOPKEEPER][2][0]; // 0 entity->focaly = limbs[SHOPKEEPER][2][1]; // 0 entity->focalz = limbs[SHOPKEEPER][2][2]; // 2 entity->behavior=&actShopkeeperLimb; entity->parent=my->uid; node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity *); // left leg entity = newEntity(221, 0, map.entities); entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->uid; entity->flags[PASSABLE]=TRUE; entity->flags[NOUPDATE]=TRUE; entity->flags[USERFLAG2]=my->flags[USERFLAG2]; entity->focalx = limbs[SHOPKEEPER][3][0]; // 0 entity->focaly = limbs[SHOPKEEPER][3][1]; // 0 entity->focalz = limbs[SHOPKEEPER][3][2]; // 2 entity->behavior=&actShopkeeperLimb; entity->parent=my->uid; node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity *); // right arm entity = newEntity(220, 0, map.entities); entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->uid; entity->flags[PASSABLE]=TRUE; entity->flags[NOUPDATE]=TRUE; entity->flags[USERFLAG2]=my->flags[USERFLAG2]; entity->focalx = limbs[SHOPKEEPER][4][0]; // 0 entity->focaly = limbs[SHOPKEEPER][4][1]; // 0 entity->focalz = limbs[SHOPKEEPER][4][2]; // 1.5 entity->behavior=&actShopkeeperLimb; entity->parent=my->uid; node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity *); // left arm entity = newEntity(219, 0, map.entities); entity->sizex = 4; entity->sizey = 4; entity->skill[2] = my->uid; entity->flags[PASSABLE]=TRUE; entity->flags[NOUPDATE]=TRUE; entity->flags[USERFLAG2]=my->flags[USERFLAG2]; entity->focalx = limbs[SHOPKEEPER][5][0]; // 0 entity->focaly = limbs[SHOPKEEPER][5][1]; // 0 entity->focalz = limbs[SHOPKEEPER][5][2]; // 1.5 entity->behavior=&actShopkeeperLimb; entity->parent=my->uid; node = list_AddNodeLast(&my->children); node->element = entity; node->deconstructor = &emptyDeconstructor; node->size = sizeof(Entity *); }
Entity* castSpell(Uint32 caster_uid, spell_t *spell, bool using_magicstaff, bool trap) { Entity *caster = uidToEntity(caster_uid); if (!caster || !spell) { //Need a spell and caster to cast a spell. return NULL; } Entity *result = NULL; //If the spell spawns an entity (like a magic light ball or a magic missile), it gets stored here and returned. #define spellcasting std::min(std::max(0,stat->PROFICIENCIES[PRO_SPELLCASTING]+statGetINT(stat)),100) //Shortcut! if (clientnum != 0 && multiplayer == CLIENT) { strcpy( (char *)net_packet->data, "SPEL" ); net_packet->data[4] = clientnum; SDLNet_Write32(spell->ID, &net_packet->data[5]); net_packet->address.host = net_server.host; net_packet->address.port = net_server.port; net_packet->len = 9; sendPacketSafe(net_sock, -1, net_packet, 0); return NULL; } if (!spell->elements.first) { return NULL; } //node_t *node = spell->types->first; #define PROPULSION_MISSILE 1 int i = 0; int chance = 0; int propulsion = 0; int traveltime = 0; int magiccost = 0; int extramagic = 0; //Extra magic drawn in from the caster being a newbie. int extramagic_to_use = 0; //Instead of doing element->mana (which causes bugs), this is an extra factor in the mana equations. Pumps extra mana into elements from extramagic. Entity *entity = NULL; spell_t *channeled_spell=NULL; //Pointer to the spell if it's a channeled spell. For the purpose of giving it its node in the channeled spell list. node_t *node = spell->elements.first; stat_t *stat = caster->getStats(); int player = -1; for (i = 0; i < numplayers; ++i) { if (caster == players[i]) { player = i; //Set the player. } } bool newbie = FALSE; if( !using_magicstaff && !trap) { if (stat->PROFICIENCIES[PRO_SPELLCASTING] < SPELLCASTING_BEGINNER) { newbie = TRUE; //The caster has lower spellcasting skill. Cue happy fun times. } /*magiccost = getCostOfSpell(spell); if (magiccost < 0) { if (player >= 0) messagePlayer(player, "Error: Invalid spell. Mana cost is negative?"); return NULL; }*/ if (multiplayer == SINGLE) { magiccost = cast_animation.mana_left; caster->drainMP(magiccost); } else { magiccost = getCostOfSpell(spell); caster->drainMP(magiccost); } } if (newbie) { //So This wizard is a newbie. //First, drain some extra mana maybe. int chance = rand()%10; if (chance >= spellcasting/10) { //At skill 20, there's an 80% chance you'll use extra mana. At 70, there's a 30% chance. extramagic = rand()%(300/(spellcasting+1)); //Use up extra mana. More mana used the lower your spellcasting skill. extramagic = std::min(extramagic, stat->MP / 10); //To make sure it doesn't draw, say, 5000 mana. Cause dammit, if you roll a 1 here...you're doomed. caster->drainMP(extramagic); } //Now, there's a chance they'll fumble the spell. chance = rand()%10; if (chance >= spellcasting/10) { if (rand()%3 == 1) { //Fizzle the spell. //TODO: Cool effects. playSoundEntity(caster,163,128); if (player >= 0) messagePlayer(player, language[409]); return NULL; } } } //Check if the bugger is levitating. bool levitating = FALSE; if (!trap) { if (stat->EFFECTS[EFF_LEVITATING] == TRUE ) levitating=TRUE; if (stat->ring != NULL ) if (stat->ring->type == RING_LEVITATION ) levitating = TRUE; if (stat->shoes != NULL) if (stat->shoes->type == STEEL_BOOTS_LEVITATION ) levitating = TRUE; } //Water walking boots bool waterwalkingboots = FALSE; if (!trap) { if (stat->shoes != NULL) if (stat->shoes->type == IRON_BOOTS_WATERWALKING ) waterwalkingboots = TRUE; } node_t *node2; //For traversing the map looking for...liquids? //Check if swimming. if (!waterwalkingboots && !levitating && !trap && player>=0) { bool swimming=FALSE; if( players[player] ) { int x = std::min<int>(std::max(0.0,floor(caster->x/16)),map.width-1); int y = std::min<int>(std::max(0.0,floor(caster->y/16)),map.height-1); if( animatedtiles[map.tiles[y*MAPLAYERS+x*MAPLAYERS*map.height]] ) swimming=TRUE; } if( swimming ) { //Can't cast spells while swimming if not levitating or water walking. if (player >= 0) messagePlayer(player, language[410]); return NULL; } } //Right. First, grab the root element, which is what determines the delivery system. //spellElement_t *element = (spellElement_t *)spell->elements->first->element; spellElement_t *element = (spellElement_t *)node->element; if (element) { extramagic_to_use = 0; /*if (magiccost > stat->MP) { if (player >= 0) messagePlayer(player, "Insufficient mana!"); //TODO: Allow overexpending at the cost of extreme danger? (maybe an immensely powerful tree of magic actually likes this -- using your life-force to power spells instead of mana) return NULL; }*/ if (extramagic > 0) { //Extra magic. Pump it in here? chance = rand()%5; if (chance == 1) { //Use some of that extra magic in this element. int amount = rand()%extramagic; extramagic -= amount; extramagic_to_use += amount; } } if (!strcmp(element->name, spellElement_missile.name)) { //Set the propulsion to missile. propulsion = PROPULSION_MISSILE; traveltime = element->duration; if (newbie) { //This guy's a newbie. There's a chance they've screwed up and negatively impacted the efficiency of the spell. chance = rand()%10; if (chance >= spellcasting/10) traveltime -= rand()%(1000/(spellcasting+1)); if (traveltime < 30) traveltime = 30; //Range checking. } traveltime += (((element->mana + extramagic_to_use) - element->base_mana) / element->overload_multiplier) * element->duration; } else if (!strcmp(element->name, spellElement_light.name)) { entity = newEntity(175, 1, map.entities); // black magic ball entity->parent = caster->uid; entity->x = caster->x; entity->y = caster->y; entity->z = -5.5 + ((-6.5f + -4.5f) / 2) * sin(0); entity->skill[7] = -5.5; //Base z. entity->sizex = 1; entity->sizey = 1; entity->yaw = caster->yaw; entity->flags[UPDATENEEDED]=TRUE; entity->flags[PASSABLE]=TRUE; entity->flags[BRIGHT]=TRUE; entity->behavior=&actMagiclightBall; entity->skill[4] = entity->x; //Store what x it started shooting out from the player at. entity->skill[5] = entity->y; //Store what y it started shooting out from the player at. entity->skill[12] = (element->duration * (((element->mana + extramagic_to_use) / element->base_mana) * element->overload_multiplier)); //How long this thing lives. node_t *spellnode = list_AddNodeLast(&entity->children); spellnode->element = copySpell(spell); //We need to save the spell since this is a channeled spell. channeled_spell = (spell_t*)(spellnode->element); spellnode->size = sizeof(spell_t); ((spell_t *)spellnode->element)->caster = caster->uid; if( using_magicstaff ) ((spell_t *)spellnode->element)->magicstaff = TRUE; spellnode->deconstructor = &spellDeconstructor; if (newbie) { //This guy's a newbie. There's a chance they've screwed up and negatively impacted the efficiency of the spell. chance = rand()%10; if (chance >= spellcasting/10) { // lifespan of the lightball entity->skill[12] -= rand()%(2000/(spellcasting+1)); if (entity->skill[12] < 180) entity->skill[12] = 180; //Range checking. } } if (using_magicstaff || trap) { entity->skill[12] = MAGICSTAFF_LIGHT_DURATION; //TODO: Grab the duration from the magicstaff or trap? ((spell_t *)spellnode->element)->sustain = FALSE; } else { entity->skill[12] /= getCostOfSpell((spell_t *)spellnode->element); } ((spell_t *)spellnode->element)->channel_duration = entity->skill[12]; //Tell the spell how long it's supposed to last so that it knows what to reset its timer to. result = entity; playSoundEntity(entity, 165, 128 ); } else if (!strcmp(element->name, spellElement_invisible.name)) { int duration = element->duration; duration += (((element->mana + extramagic_to_use) - element->base_mana) / element->overload_multiplier) * element->duration; node_t *spellnode = list_AddNodeLast(&caster->getStats()->magic_effects); spellnode->element = copySpell(spell); //We need to save the spell since this is a channeled spell. channeled_spell = (spell_t*)(spellnode->element); channeled_spell->magic_effects_node = spellnode; spellnode->size = sizeof(spell_t); ((spell_t *)spellnode->element)->caster = caster->uid; spellnode->deconstructor = &spellDeconstructor; if (newbie) { //This guy's a newbie. There's a chance they've screwed up and negatively impacted the efficiency of the spell. chance = rand()%10; if (chance >= spellcasting/10) duration -= rand()%(1000/(spellcasting+1)); if (duration < 180) duration = 180; //Range checking. } duration /= getCostOfSpell((spell_t *)spellnode->element); channeled_spell->channel_duration = duration; //Tell the spell how long it's supposed to last so that it knows what to reset its timer to. stat->EFFECTS[EFF_INVISIBLE] = TRUE; stat->EFFECTS_TIMERS[EFF_INVISIBLE] = duration; for (i = 0; i < numplayers; ++i) { if (caster == players[i]) { serverUpdateEffects(i); } } playSoundEntity(caster, 166, 128 ); spawnMagicEffectParticles(caster->x,caster->y,caster->z,174); } else if (!strcmp(element->name, spellElement_levitation.name)) { int duration = element->duration; duration += (((element->mana + extramagic_to_use) - element->base_mana) / element->overload_multiplier) * element->duration; node_t *spellnode = list_AddNodeLast(&caster->getStats()->magic_effects); spellnode->element = copySpell(spell); //We need to save the spell since this is a channeled spell. channeled_spell = (spell_t*)(spellnode->element); channeled_spell->magic_effects_node = spellnode; spellnode->size = sizeof(spell_t); ((spell_t *)spellnode->element)->caster = caster->uid; spellnode->deconstructor = &spellDeconstructor; if (newbie) { //This guy's a newbie. There's a chance they've screwed up and negatively impacted the efficiency of the spell. chance = rand()%10; if (chance >= spellcasting/10) duration -= rand()%(1000/(spellcasting+1)); if (duration < 180) duration = 180; //Range checking. } duration /= getCostOfSpell((spell_t *)spellnode->element); channeled_spell->channel_duration = duration; //Tell the spell how long it's supposed to last so that it knows what to reset its timer to. stat->EFFECTS[EFF_LEVITATING] = TRUE; stat->EFFECTS_TIMERS[EFF_LEVITATING] = duration; for (i = 0; i < numplayers; ++i) { if (caster == players[i]) { serverUpdateEffects(i); } } playSoundEntity(caster, 178, 128 ); spawnMagicEffectParticles(caster->x,caster->y,caster->z,170); } else if (!strcmp(element->name, spellElement_teleportation.name)) { caster->teleportRandom(); } else if (!strcmp(element->name, spellElement_identify.name)) { for (i = 0; i < numplayers; ++i) { if (caster == players[i]) { spawnMagicEffectParticles(caster->x,caster->y,caster->z,171); if (i != 0) { //Tell the client to identify an item. strcpy((char *)net_packet->data,"IDEN"); net_packet->address.host = net_clients[i - 1].host; net_packet->address.port = net_clients[i - 1].port; net_packet->len = 4; sendPacketSafe(net_sock, -1, net_packet, i-1); } else { //Identify an item. shootmode = FALSE; gui_mode = GUI_MODE_INVENTORY; //Reset the GUI to the inventory. identifygui_active = TRUE; identifygui_appraising = FALSE; //identifygui_mode = TRUE; } } } playSoundEntity(caster, 167, 128 ); } else if (!strcmp(element->name, spellElement_removecurse.name)) { for (i = 0; i < numplayers; ++i) { if (caster == players[i]) { spawnMagicEffectParticles(caster->x,caster->y,caster->z,169); if (i != 0) { //Tell the client to uncurse an item. strcpy((char *)net_packet->data,"RCUR"); net_packet->address.host = net_clients[i - 1].host; net_packet->address.port = net_clients[i - 1].port; net_packet->len = 4; sendPacketSafe(net_sock, -1, net_packet, i-1); } else { //Uncurse an item shootmode = FALSE; gui_mode = GUI_MODE_INVENTORY; //Reset the GUI to the inventory. removecursegui_active = TRUE; } } } playSoundEntity(caster, 167, 128 ); } else if (!strcmp(element->name, spellElement_magicmapping.name)) { for (i = 0; i < numplayers; ++i) { if (caster == players[i]) { spawnMagicEffectParticles(caster->x,caster->y,caster->z,171); spell_magicMap(i); } } playSoundEntity(caster, 167, 128 ); } else if (!strcmp(element->name, spellElement_heal.name)) { //TODO: Make it work for NPCs. for (i = 0; i < numplayers; ++i) { if (caster == players[i]) { int amount = element->damage * (((element->mana + extramagic_to_use) / element->base_mana) * element->overload_multiplier); //Amount to heal. if (newbie) { //This guy's a newbie. There's a chance they've screwed up and negatively impacted the efficiency of the spell. chance = rand()%10; if (chance >= spellcasting/10) amount -= rand()%(1000/(spellcasting+1)); if (amount < 8) amount = 8; //Range checking. } spell_changeHealth(players[i], amount); playSoundEntity(caster, 168, 128); for(node = map.entities->first; node->next; node = node->next) { entity = (Entity *)(node->element); if ( !entity || entity==caster ) continue; if( entity->behavior!=&actPlayer && entity->behavior!=&actMonster ) continue; if (entityDist(entity, caster) <= HEAL_RADIUS && entity->checkFriend(caster)) { spell_changeHealth(entity, amount); playSoundEntity(entity, 168, 128); spawnMagicEffectParticles(entity->x,entity->y,entity->z,169); } } break; } } playSoundEntity(caster, 168, 128); spawnMagicEffectParticles(caster->x,caster->y,caster->z,169); } else if (!strcmp(element->name, spellElement_cure_ailment.name)) { //TODO: Generalize it for NPCs too? for (i = 0; i < numplayers; ++i) { if (caster == players[i]) { Uint32 color = SDL_MapRGB(mainsurface->format,0,255,0); messagePlayerColor(i,color,language[411]); int c = 0; for (c = 0; c < NUMEFFECTS; ++c) { //This does a whole lot more than just cure ailments. stats[i].EFFECTS[c]=FALSE; stats[i].EFFECTS_TIMERS[c]=0; } serverUpdateEffects(player); playSoundEntity(entity, 168, 128); for(node = map.entities->first; node->next; node = node->next) { entity = (Entity *)(node->element); if( !entity || entity==caster ) continue; if( entity->behavior!=&actPlayer && entity->behavior!=&actMonster ) continue; stat_t *target_stat = entity->getStats(); if( target_stat ) { if (entityDist(entity, caster) <= HEAL_RADIUS && entity->checkFriend(caster)) { for (c = 0; c < NUMEFFECTS; ++c) { //This does a whole lot more than just cure ailments. target_stat->EFFECTS[c]=FALSE; target_stat->EFFECTS_TIMERS[c]=0; } if( entity->behavior==&actPlayer ) serverUpdateEffects(entity->skill[2]); if( entity->flags[BURNING] ) { entity->flags[BURNING] = FALSE; serverUpdateEntityFlag(entity,BURNING); } playSoundEntity(entity, 168, 128); spawnMagicEffectParticles(entity->x,entity->y,entity->z,169); } } } break; } } playSoundEntity(caster, 168, 128 ); spawnMagicEffectParticles(caster->x,caster->y,caster->z,169); } if (propulsion == PROPULSION_MISSILE) { entity = newEntity(168, 1, map.entities); // red magic ball entity->parent = caster->uid; entity->x = caster->x; entity->y = caster->y; entity->z = -1; entity->sizex = 1; entity->sizey = 1; entity->yaw = caster->yaw; entity->flags[UPDATENEEDED]=TRUE; entity->flags[PASSABLE]=TRUE; entity->flags[BRIGHT]=TRUE; entity->behavior = &actMagicMissile; double missile_speed = 4 * ((double)element->mana / element->overload_multiplier); //TODO: Factor in base mana cost? entity->vel_x = cos(entity->yaw) * (missile_speed); entity->vel_y = sin(entity->yaw) * (missile_speed); entity->skill[4] = 0; entity->skill[5] = traveltime; node = list_AddNodeFirst(&entity->children); node->element = copySpell(spell); ((spell_t *)node->element)->caster = caster->uid; node->deconstructor = &spellDeconstructor; node->size = sizeof(spell_t); if( !strcmp(spell->name, spell_fireball.name) ) playSoundEntity(entity, 164, 128 ); else if( !strcmp(spell->name, spell_lightning.name) ) playSoundEntity(entity, 171, 128 ); else if( !strcmp(spell->name, spell_cold.name) ) playSoundEntity(entity, 172, 128 ); else playSoundEntity(entity, 169, 128 ); result = entity; } extramagic_to_use = 0; if (extramagic > 0) { //Extra magic. Pump it in here? chance = rand()%5; if (chance == 1) { //Use some of that extra magic in this element. int amount = rand()%extramagic; extramagic -= amount; extramagic_to_use += amount; //TODO: Make the elements here use this? Looks like they won't, currently. Oh well. } } //TODO: Add the status/conditional elements/modifiers (probably best as elements) too. Like onCollision or something. //element = (spellElement_t *)element->elements->first->element; node = element->elements.first; if( node ) { element = (spellElement_t *)node->element; if (!strcmp(element->name, spellElement_force.name)) { //Give the spell force properties. if (propulsion == PROPULSION_MISSILE) { entity->sprite = 173; } if (newbie) { //This guy's a newbie. There's a chance they've screwed up and negatively impacted the efficiency of the spell. chance = rand()%10; if (chance >= spellcasting/10) element->damage -= rand()%(100/(spellcasting+1)); if (element->damage < 10) element->damage = 10; //Range checking. } } else if (!strcmp(element->name, spellElement_fire.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 168; //entity->skill[4] = entity->x; //Store what x it started shooting out from the player at. //entity->skill[5] = entity->y; //Store what y it started shooting out from the player at. //entity->skill[12] = (100 * stat->PROFICIENCIES[PRO_SPELLCASTING]) + (100 * stat->PROFICIENCIES[PRO_MAGIC]) + (100 * (rand()%10)) + (10 * (rand()%10)) + (rand()%10); //How long this thing lives. //playSoundEntity( entity, 59, 128 ); } if (newbie) { //This guy's a newbie. There's a chance they've screwed up and negatively impacted the efficiency of the spell. chance = rand()%10; if (chance >= spellcasting/10) element->damage -= rand()%(100/(spellcasting+1)); if (element->damage < 10) element->damage = 10; //Range checking. } } else if (!strcmp(element->name, spellElement_lightning.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 170; } if (newbie) { //This guy's a newbie. There's a chance they've screwed up and negatively impacted the efficiency of the spell. chance = rand()%10; if (chance >= spellcasting/10) element->damage -= rand()%(100/(spellcasting+1)); if (element->damage < 10) element->damage = 10; //Range checking. } } else if (!strcmp(element->name, spellElement_confuse.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 173; } } else if (!strcmp(element->name, spellElement_cold.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 172; } } else if (!strcmp(element->name, spellElement_dig.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 171; } } else if (!strcmp(element->name, spellElement_locking.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 171; } } else if (!strcmp(element->name, spellElement_opening.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 171; } } else if (!strcmp(element->name, spellElement_slow.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 171; } } else if (!strcmp(element->name, spellElement_sleep.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 172; } } else if (!strcmp(spell->name, spell_magicmissile.name)) { if (propulsion == PROPULSION_MISSILE) { entity->sprite = 173; } } } } //Random chance to level up spellcasting skill. if(rand()%4==0) { caster->increaseSkill(PRO_SPELLCASTING); } if(rand()%5==0) { caster->increaseSkill(PRO_MAGIC); // otherwise you will basically never be able to learn all the spells in the game... } if (spell_isChanneled(spell) && !using_magicstaff) { //TODO: What about magic traps and channeled spells? if (!channeled_spell) { printlog( "What. Spell is channeled but no channeled_spell pointer? What sorcery is this?\n"); } else { int target_client = 0; for (i = 0; i < numplayers; ++i) { if (players[i] == caster) { target_client = i; } } //printlog( "Client is: %d\n", target_client); if (multiplayer == SERVER && target_client != 0) { strcpy( (char *)net_packet->data, "CHAN" ); net_packet->data[4] = clientnum; SDLNet_Write32(spell->ID, &net_packet->data[5]); net_packet->address.host = net_clients[target_client - 1].host; net_packet->address.port = net_clients[target_client - 1].port; net_packet->len = 9; sendPacketSafe(net_sock, -1, net_packet, target_client-1); } //Add this spell to the list of channeled spells. node = list_AddNodeLast(&channeledSpells[target_client]); node->element = channeled_spell; node->size = sizeof(spell_t); node->deconstructor = &emptyDeconstructor; channeled_spell->sustain_node = node; } } return result; }
void addSpell(int spell, int player) { node_t *node = NULL; // this is a local function if( player != clientnum ) return; spell_t *new_spell = NULL; switch( spell ) { case SPELL_FORCEBOLT: new_spell = copySpell(&spell_forcebolt); break; case SPELL_MAGICMISSILE: new_spell = copySpell(&spell_magicmissile); break; case SPELL_COLD: new_spell = copySpell(&spell_cold); break; case SPELL_FIREBALL: new_spell = copySpell(&spell_fireball); break; case SPELL_LIGHTNING: new_spell = copySpell(&spell_lightning); break; case SPELL_REMOVECURSE: new_spell = copySpell(&spell_removecurse); break; case SPELL_LIGHT: new_spell = copySpell(&spell_light); break; case SPELL_IDENTIFY: new_spell = copySpell(&spell_identify); break; case SPELL_MAGICMAPPING: new_spell = copySpell(&spell_magicmapping); break; case SPELL_SLEEP: new_spell = copySpell(&spell_sleep); break; case SPELL_CONFUSE: new_spell = copySpell(&spell_confuse); break; case SPELL_SLOW: new_spell = copySpell(&spell_slow); break; case SPELL_OPENING: new_spell = copySpell(&spell_opening); break; case SPELL_LOCKING: new_spell = copySpell(&spell_locking); break; case SPELL_LEVITATION: new_spell = copySpell(&spell_levitation); break; case SPELL_INVISIBILITY: new_spell = copySpell(&spell_invisibility); break; case SPELL_TELEPORTATION: new_spell = copySpell(&spell_teleportation); break; case SPELL_HEALING: new_spell = copySpell(&spell_healing); break; case SPELL_EXTRAHEALING: new_spell = copySpell(&spell_extrahealing); break; case SPELL_CUREAILMENT: new_spell = copySpell(&spell_cureailment); break; case SPELL_DIG: new_spell = copySpell(&spell_dig); break; default: return; } if( spellInList(&spellList, new_spell) ) { messagePlayer(player, language[439],new_spell->name); spellDeconstructor((void *)new_spell); return; } if( stats[player]->PROFICIENCIES[PRO_MAGIC]+statGetINT(stats[player]) < new_spell->difficulty ) { messagePlayer(player, language[440]); spellDeconstructor((void *)new_spell); return; } messagePlayer(player,language[441],new_spell->name); node = list_AddNodeLast(&spellList); node->element = new_spell; node->size = sizeof(spell_t); node->deconstructor = &spellDeconstructor; players[player]->entity->increaseSkill(PRO_MAGIC); Item *item = newItem(SPELL_ITEM, SERVICABLE, 0, 1, spell, TRUE, NULL); itemPickup(player, item); free(item); }