Beispiel #1
0
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
	}
}
Beispiel #2
0
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 *);
}
Beispiel #3
0
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;
}
Beispiel #4
0
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);
}