示例#1
0
void slimeDie(Entity *my) {
	Entity *entity;
	int c = 0;
	for( c=0; c<5; c++ ) {
		Entity *gib = spawnGib(my);
		serverSpawnGibForClient(gib);
	}
	if (spawn_blood) {
		int x, y;
		x = std::min<unsigned int>(std::max<int>(0,my->x/16),map.width-1);
		y = std::min<unsigned int>(std::max<int>(0,my->y/16),map.height-1);
		if( map.tiles[y*MAPLAYERS+x*MAPLAYERS*map.height] ) {
			if( !checkObstacle(my->x,my->y,my,NULL) ) {
				if( my->sprite == 210 )
					entity = newEntity(212,1,map.entities);
				else
					entity = newEntity(214,1,map.entities);
				entity->x = my->x;
				entity->y = my->y;
				entity->z = 7.4+(rand()%20)/100.f;
				entity->parent = my->uid;
				entity->sizex = 2;
				entity->sizey = 2;
				entity->yaw = (rand()%360)*PI/180.0;
				entity->flags[UPDATENEEDED] = TRUE;
				entity->flags[PASSABLE] = TRUE;
			}
		}
	}
	playSoundEntity(my, 69, 64);
	list_RemoveNode(my->mynode);
	return;
}
示例#2
0
void actWallBuilder(Entity *my) {
	int c;

	if( !my->skill[28] )
		return;

	// received on signal
	if( my->skill[28] == 2) {
		playSoundEntity( my, 182, 64 );
		Uint16 x = std::min<Uint16>(std::max(0.0,my->x/16),map.width-1);
		Uint16 y = std::min<Uint16>(std::max(0.0,my->y/16),map.height-1);
		map.tiles[OBSTACLELAYER+y*MAPLAYERS+x*MAPLAYERS*map.height] = map.tiles[y*MAPLAYERS+x*MAPLAYERS*map.height];
		if( multiplayer==SERVER ) {
			for( c=0; c<MAXPLAYERS; c++ ) {
				if( client_disconnected[c]==TRUE )
					continue;
				strcpy((char *)net_packet->data,"WALC");
				SDLNet_Write16(x,&net_packet->data[4]);
				SDLNet_Write16(y,&net_packet->data[6]);
				net_packet->address.host = net_clients[c-1].host;
				net_packet->address.port = net_clients[c-1].port;
				net_packet->len = 8;
				sendPacketSafe(net_sock, -1, net_packet, c-1);
			}
		}
		list_RemoveNode(my->mynode);
	}
}
示例#3
0
void Entity::actSoundSource()
{
#ifdef SOUND
	if ( multiplayer == CLIENT )
	{
		return;
	}

	if ( soundSourceDelay > 0 && soundSourceDelayCounter == 0 )
	{
		soundSourceDelayCounter = soundSourceDelay;
	}

	if ( circuit_status == CIRCUIT_ON )
	{
		// received power
		if ( soundSourceDelayCounter > 0 )
		{
			--soundSourceDelayCounter;
			if ( soundSourceDelayCounter != 0 )
			{
				return;
			}
		}
		if ( !soundSourceFired )
		{
			soundSourceFired = 1;
			if ( soundSourceToPlay >= 0 && soundSourceToPlay < numsounds )
			{
				if ( soundSourceOrigin == 1 )
				{
					for ( int c = 0; c < MAXPLAYERS; ++c )
					{
						playSoundPlayer(c, soundSourceToPlay, soundSourceVolume);
					}
				}
				else
				{
					playSoundEntity(this, soundSourceToPlay, soundSourceVolume);
				}
			}
		}
	}
	else if ( circuit_status == CIRCUIT_OFF )
	{
		if ( soundSourceDelay > 0 )
		{
			soundSourceDelayCounter = soundSourceDelay;
		}
		if ( soundSourceFired && !soundSourceLatchOn )
		{
			soundSourceFired = 0;
		}
	}
#endif // SOUND
}
示例#4
0
void fireOffSpellAnimation(spellcasting_animation_manager_t* animation_manager, Uint32 caster_uid, spell_t *spell) {
	//This function triggers the spellcasting animation and sets up everything.

	if (!animation_manager) {
		return;
	}
	Entity *caster = uidToEntity(caster_uid);
	if (!caster) {
		return;
	}
	if (!spell) {
		return;
	}
	if (!magicLeftHand) {
		return;
	}
	if (!magicRightHand) {
		return;
	}

	playSoundEntity(caster, 170, 128 );
	stat_t *stat = caster->getStats();

	//Save these two very important pieces of data.
	animation_manager->caster = caster->uid;
	animation_manager->spell = spell;
	animation_manager->active = TRUE;
	animation_manager->stage = CIRCLE;

	//Make the HUDWEAPON disappear, or somesuch?
	magicLeftHand->flags[INVISIBLE] = FALSE;
	magicRightHand->flags[INVISIBLE] = FALSE;

	animation_manager->lefthand_angle = 0;
	animation_manager->lefthand_movex = 0;
	animation_manager->lefthand_movey = 0;

	animation_manager->circle_count = 0;
	animation_manager->times_to_circle = (getCostOfSpell(spell) / 10) + 1; //Circle once for every 10 mana the spell costs.
	animation_manager->mana_left = getCostOfSpell(spell);
	if (stat->PROFICIENCIES[PRO_SPELLCASTING] < SPELLCASTING_BEGINNER) { //There's a chance that caster is newer to magic (and thus takes longer to cast a spell).
		int chance = rand()%10;
		if (chance >= stat->PROFICIENCIES[PRO_SPELLCASTING]/15) {
			int amount = (rand()%50)/std::max(stat->PROFICIENCIES[PRO_SPELLCASTING]+statGetINT(stat),1);
			amount = std::min(amount, CASTING_EXTRA_TIMES_CAP);
			animation_manager->times_to_circle += amount;
		}
	}
	animation_manager->consume_interval = (animation_manager->times_to_circle * ((2 * PI) / HANDMAGIC_CIRCLE_SPEED)) / getCostOfSpell(spell);
	animation_manager->consume_timer = animation_manager->consume_interval;
}
示例#5
0
void skeletonDie(Entity *my) {
	node_t *node, *nextnode;
	int i = 0;
	for( node=my->children.first; node!=NULL; node=nextnode ) {
		nextnode = node->next;
		if( node->element != NULL && i >= 2 ) {
			Entity *entity=(Entity *)node->element;
			if( entity->light != NULL )
				list_RemoveNode(entity->light->node);
			entity->light = NULL;
			list_RemoveNode(entity->mynode);
		}
		list_RemoveNode(node);
		i++;
	}
	int c;
	for( c=0; c<6; c++ ) {
		Entity *entity = spawnGib(my);
		if( entity ) {
			switch( c ) {
				case 0:
					entity->sprite = 229;
					break;
				case 1:
					entity->sprite = 230;
					break;
				case 2:
					entity->sprite = 231;
					break;
				case 3:
					entity->sprite = 233;
					break;
				case 4:
					entity->sprite = 235;
					break;
				case 5:
					entity->sprite = 236;
					break;
			}
			serverSpawnGibForClient(entity);
		}
	}
	playSoundEntity(my, 94, 128);
	list_RemoveNode(my->mynode);
	return;
}
示例#6
0
void humanDie(Entity* my)
{
	int c;
	for ( c = 0; c < 5; c++ )
	{
		Entity* gib = spawnGib(my);
		serverSpawnGibForClient(gib);
	}

	my->spawnBlood();

	playSoundEntity(my, 28, 128);

	my->removeMonsterDeathNodes();

	list_RemoveNode(my->mynode);
	return;
}
示例#7
0
void gnomeDie(Entity *my) {
	node_t *node, *nextnode;
	int c;
	for( c=0; c<6; c++ ) {
		Entity *entity = spawnGib(my);
		if( entity )
			serverSpawnGibForClient(entity);
	}
	if (spawn_blood) {
		int x, y;
		x = std::min<unsigned int>(std::max<int>(0,my->x/16),map.width-1);
		y = std::min<unsigned int>(std::max<int>(0,my->y/16),map.height-1);
		if( map.tiles[y*MAPLAYERS+x*MAPLAYERS*map.height] ) {
			if( !checkObstacle(my->x,my->y,my,NULL) ) {
				Entity *entity = newEntity(160,1,map.entities);
				entity->x = my->x;
				entity->y = my->y;
				entity->z = 7.4+(rand()%20)/100.f;
				entity->parent = my->uid;
				entity->sizex = 2;
				entity->sizey = 2;
				entity->yaw = (rand()%360)*PI/180.0;
				entity->flags[UPDATENEEDED] = TRUE;
				entity->flags[PASSABLE] = TRUE;
			}
		}
	}
	int i = 0;
	for( node=my->children.first; node!=NULL; node=nextnode ) {
		nextnode = node->next;
		if( node->element != NULL && i >= 2 ) {
			Entity *entity=(Entity *)node->element;
			if( entity->light != NULL )
				list_RemoveNode(entity->light->node);
			entity->light = NULL;
			list_RemoveNode(entity->mynode);
		}
		list_RemoveNode(node);
		i++;
	}
	playSoundEntity(my,225+rand()%4,128);
	list_RemoveNode(my->mynode);
	return;
}
示例#8
0
void actGate(Entity *my) {
	int i;

	if( multiplayer!=CLIENT ) {
		if (!my->skill[28])
			return; //Gate needs the mechanism powered state variable to be set.

		if (my->skill[28] == 2) {
			//Raise gate if it's closed.
			if (!GATE_STATUS) {
				GATE_STATUS = 1;
				playSoundEntity(my, 81, 64);
				serverUpdateEntitySkill(my,3);
			}
		} else {
			//Close gate if it's open.
			if (GATE_STATUS) {
				GATE_STATUS = 0;
				playSoundEntity(my, 82, 64);
				serverUpdateEntitySkill(my,3);
			}
		}
	} else {
		my->flags[NOUPDATE] = TRUE;
	}
	if (!GATE_INIT ) {
		GATE_INIT = 1;
		GATE_STARTHEIGHT = my->z;
		my->scalex = 1.01;
		my->scaley = 1.01;
		my->scalez = 1.01;
	}
	
	// rightclick message
	if( multiplayer!=CLIENT ) {
		for(i=0;i<MAXPLAYERS;i++) {
			if( (i==0 && selectedEntity==my) || (client_selected[i]==my) ) {
				if(inrange[i]) {
					messagePlayer(i,language[475]);
				}
			}
		}
	}

	if( !GATE_STATUS ) {
		//Closing gate.
		if( my->z < GATE_STARTHEIGHT ) {
			GATE_VELZ += .25;
			my->z = std::min(GATE_STARTHEIGHT, my->z + GATE_VELZ);
		} else {
			GATE_VELZ = 0;
		}
	} else {
		//Opening gate.
		if( my->z > GATE_STARTHEIGHT-12 ) {
			my->z = std::max(GATE_STARTHEIGHT-12, my->z - 0.25);
			
			// rattle the gate
			GATE_RATTLE = (GATE_RATTLE==0);
			if( GATE_RATTLE ) {
				my->x += .05;
				my->y += .05;
			} else {
				my->x -= .05;
				my->y -= .05;
			}
		} else {
			// reset the gate's position
			if( GATE_RATTLE ) {
				GATE_RATTLE = 0;
				my->x -= .05;
				my->y -= .05;
			}
		}
	}
	
	//Setting collision
	node_t *node;
	bool somebodyinside = FALSE;
	if( my->z > GATE_STARTHEIGHT-6 && my->flags[PASSABLE] ) {
		for( node=map.entities->first; node!=NULL; node=node->next ) {
			Entity *entity = (Entity *)node->element;
			if( entity==my || entity->flags[PASSABLE] || entity->sprite == 1 )
				continue;
			if( entityInsideEntity(my,entity) ) {
				somebodyinside = TRUE;
				break;
			}
		}
		if( !somebodyinside )
			my->flags[PASSABLE] = FALSE;
	} else if( my->z < GATE_STARTHEIGHT-9 && !my->flags[PASSABLE] ) {
		my->flags[PASSABLE] = TRUE;
	}
}
示例#9
0
void actFountain(Entity* my)
{
	Entity* entity;

	//messagePlayer(0, "actFountain()");
	//TODO: Temporary mechanism testing code.
	/*
	if( multiplayer != CLIENT ) {
		if (my->skill[28]) {
			//All it does is change its sprite to sink if it's powered.
			if (my->skill[28] == 1) {
				my->sprite = 163;
			} else {
				my->sprite = 164;
			}
		}
	}*/
	//****************END TEST CODE***************

	//TODO: Sounds.

	// spray water
	if ( my->skill[0] > 0 )
	{
#define FOUNTAIN_AMBIENCE my->skill[7]
		FOUNTAIN_AMBIENCE--;
		if ( FOUNTAIN_AMBIENCE <= 0 )
		{
			FOUNTAIN_AMBIENCE = TICKS_PER_SECOND * 6;
			playSoundEntityLocal(my, 135, 32 );
		}
		entity = spawnGib(my);
		entity->flags[INVISIBLE] = false;
		entity->y -= 2;
		entity->z -= 8;
		entity->flags[SPRITE] = false;
		entity->flags[NOUPDATE] = true;
		entity->flags[UPDATENEEDED] = false;
		entity->skill[4] = 7;
		entity->sprite = 4;
		entity->yaw = (rand() % 360) * PI / 180.0;
		entity->pitch = (rand() % 360) * PI / 180.0;
		entity->roll = (rand() % 360) * PI / 180.0;
		entity->vel_x = 0;
		entity->vel_y = 0;
		entity->vel_z = .25;
		entity->fskill[3] = 0.03;
	}

	// the rest of the function is server-side.
	if ( multiplayer == CLIENT )
	{
		return;
	}

	//Using the fountain (TODO: Monsters using it?).
	int i;
	for (i = 0; i < MAXPLAYERS; ++i)
	{
		if ( (i == 0 && selectedEntity == my) || (client_selected[i] == my) )
		{
			if (inrange[i])   //Act on it only if the player (or monster, if/when this is changed to support monster interaction?) is in range.
			{
				//First check that it's not depleted.
				if (my->skill[0] == 0)
				{
					//Depleted
					messagePlayer(i, language[467]);
				}
				else
				{
					if (players[i]->entity->flags[BURNING])
					{
						messagePlayer(i, language[468]);
						players[i]->entity->flags[BURNING] = false;
						serverUpdateEntityFlag(players[i]->entity, BURNING);
						steamAchievementClient(i, "BARONY_ACH_HOT_SHOWER");
					}
					switch (my->skill[1])
					{
						case 0:
						{
							playSoundEntity(players[i]->entity, 52, 64);
							//Spawn succubus.
							Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
							Entity* spawnedMonster = nullptr;

							if ( !strncmp(map.name, "Underworld", 10) )
							{
								Monster creature = SUCCUBUS;
								if ( rand() % 2 )
								{
									creature = INCUBUS;
								}
								for ( int c = 0; spawnedMonster == nullptr && c < 5; ++c )
								{
									switch ( c )
									{
										case 0:
											spawnedMonster = summonMonster(creature, my->x, my->y);
											break;
										case 1:
											spawnedMonster = summonMonster(creature, my->x + 16, my->y);
											break;
										case 2:
											spawnedMonster = summonMonster(creature, my->x - 16, my->y);
											break;
										case 3:
											spawnedMonster = summonMonster(creature, my->x, my->y + 16);
											break;
										case 4:
											spawnedMonster = summonMonster(creature, my->x, my->y - 16);
											break;
									}
								}
								if ( spawnedMonster )
								{
									if ( creature == INCUBUS )
									{
										messagePlayerColor(i, color, language[2519]);
										Stat* tmpStats = spawnedMonster->getStats();
										if ( tmpStats )
										{
											strcpy(tmpStats->name, "lesser incubus");
										}
									}
									else
									{
										messagePlayerColor(i, color, language[469]);
									}
								}
							}
							else if ( currentlevel < 10 )
							{
								messagePlayerColor(i, color, language[469]);
								spawnedMonster = summonMonster(SUCCUBUS, my->x, my->y);
							}
							else if ( currentlevel < 20 )
							{
								if ( rand() % 2 )
								{
									spawnedMonster = summonMonster(INCUBUS, my->x, my->y);
									Stat* tmpStats = spawnedMonster->getStats();
									if ( tmpStats )
									{
										strcpy(tmpStats->name, "lesser incubus");
									}
									messagePlayerColor(i, color, language[2519]);
								}
								else
								{
									messagePlayerColor(i, color, language[469]);
									spawnedMonster = summonMonster(SUCCUBUS, my->x, my->y);
								}
							}
							else
							{
								messagePlayerColor(i, color, language[2519]);
								spawnedMonster = summonMonster(INCUBUS, my->x, my->y);
							}
							break;
						}
						case 1:
							messagePlayer(i, language[470]);
							messagePlayer(i, language[471]);
							playSoundEntity(players[i]->entity, 52, 64);
							stats[i]->HUNGER += 100;
							players[i]->entity->modHP(5);
							break;
						case 2:
						{
							//Potion effect. Potion effect is stored in my->skill[3], randomly chosen when the fountain is created.
							messagePlayer(i, language[470]);
							Item* item = newItem(static_cast<ItemType>(POTION_WATER + my->skill[3]), static_cast<Status>(4), 0, 1, 0, false, NULL);
							useItem(item, i);
							// Long live the mystical fountain of TODO.
							break;
						}
						case 3:
						{
							// bless all equipment
							playSoundEntity(players[i]->entity, 52, 64);
							Uint32 textcolor = SDL_MapRGB(mainsurface->format, 0, 255, 255);
							messagePlayerColor(i, textcolor, language[471]);
							messagePlayer(i, language[473]);
							if ( stats[i]->helmet )
							{
								stats[i]->helmet->beatitude++;
							}
							if ( stats[i]->breastplate )
							{
								stats[i]->breastplate->beatitude++;
							}
							if ( stats[i]->gloves )
							{
								stats[i]->gloves->beatitude++;
							}
							if ( stats[i]->shoes )
							{
								stats[i]->shoes->beatitude++;
							}
							if ( stats[i]->shield )
							{
								stats[i]->shield->beatitude++;
							}
							if ( stats[i]->weapon )
							{
								stats[i]->weapon->beatitude++;
							}
							if ( stats[i]->cloak )
							{
								stats[i]->cloak->beatitude++;
							}
							if ( stats[i]->amulet )
							{
								stats[i]->amulet->beatitude++;
							}
							if ( stats[i]->ring )
							{
								stats[i]->ring->beatitude++;
							}
							if ( stats[i]->mask )
							{
								stats[i]->mask->beatitude++;
							}
							if ( multiplayer == SERVER && i > 0 )
							{
								strcpy((char*)net_packet->data, "BLES");
								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);
							}
							break;
						}
						case 4:
						{
							// bless one piece of equipment
							playSoundEntity(players[i]->entity, 52, 64);
							Uint32 textcolor = SDL_MapRGB(mainsurface->format, 0, 255, 255);
							messagePlayerColor(i, textcolor, language[471]);
							//Choose only one piece of equipment to bless.

							//First, Figure out what equipment is available.
							std::vector<std::pair<Item*, Uint32>> items;
							if ( stats[i]->helmet )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->helmet, 0));
							}
							if ( stats[i]->breastplate )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->breastplate, 1));
							}
							if ( stats[i]->gloves )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->gloves, 2));
							}
							if ( stats[i]->shoes )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->shoes, 3));
							}
							if ( stats[i]->shield )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->shield, 4));
							}
							if ( stats[i]->weapon )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->weapon, 5));
							}
							if ( stats[i]->cloak )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->cloak, 6));
							}
							if ( stats[i]->amulet )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->amulet, 7));
							}
							if ( stats[i]->ring )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->ring, 8));
							}
							if ( stats[i]->mask )
							{
								items.push_back(std::pair<Item*,int>(stats[i]->mask, 9));
							}

							if ( items.size() )
							{
								messagePlayer(i, language[2592]); //"The fountain blesses a piece of equipment"
								//Randomly choose a piece of equipment.
								std::pair<Item*, Uint32> chosen = items[rand()%items.size()];
								chosen.first->beatitude++;

								if ( multiplayer == SERVER && i > 0 )
								{
									strcpy((char*)net_packet->data, "BLE1");
									SDLNet_Write32(chosen.second, &net_packet->data[4]);
									net_packet->address.host = net_clients[i - 1].host;
									net_packet->address.port = net_clients[i - 1].port;
									net_packet->len = 8;
									sendPacketSafe(net_sock, -1, net_packet, i - 1);
								}
							}
							//Does nothing if no valid items.
							break;
						}
						default:
							break;
					}
					messagePlayer(i, language[474]);
					my->skill[0] = 0; //Dry up fountain.
					serverUpdateEntitySkill(my, my->skill[0]);
					//TODO: messagePlayersInSight() instead.
				}
				//Then perform the effect randomly determined when the fountain was created.
				return;
			}
		}
	}
}
示例#10
0
void actFountain(Entity *my) {
	Entity *entity;

	//messagePlayer(0, "actFountain()");
	//TODO: Temporary mechanism testing code.
	/*
	if( multiplayer != CLIENT ) {
		if (my->skill[28]) {
			//All it does is change its sprite to sink if it's powered.
			if (my->skill[28] == 1) {
				my->sprite = 163;
			} else {
				my->sprite = 164;
			}
		}
	}*/
	//****************END TEST CODE***************

	//TODO: Sounds.
	
	// spray water
	if( my->skill[0] > 0 || ( !my->skill[2] && multiplayer == CLIENT ) ) {
		#define FOUNTAIN_AMBIENCE my->skill[7]
		FOUNTAIN_AMBIENCE--;
		if( FOUNTAIN_AMBIENCE<=0 ) {
			FOUNTAIN_AMBIENCE = TICKS_PER_SECOND*6;
			playSoundEntityLocal(my, 135, 32 );
		}
		entity = spawnGib(my);
		entity->flags[INVISIBLE] = FALSE;
		entity->y -= 2;
		entity->z -= 8;
		entity->flags[SPRITE] = FALSE;
		entity->flags[NOUPDATE] = TRUE;
		entity->flags[UPDATENEEDED] = FALSE;
		entity->skill[4] = 7;
		entity->sprite = 4;
		entity->yaw = (rand()%360)*PI/180.0;
		entity->pitch = (rand()%360)*PI/180.0;
		entity->roll = (rand()%360)*PI/180.0;
		entity->vel_x = 0;
		entity->vel_y = 0;
		entity->vel_z = .25;
		entity->fskill[3] = 0.03;
	}
	
	 // the rest of the function is server-side.
	if( multiplayer==CLIENT )
		return;
		
	// makes the fountain stop spraying water on clients
	if( my->skill[0] <= 0 )
		my->skill[2] = 1;
	else
		my->skill[2] = 0;

	//Using the fountain (TODO: Monsters using it?).
	int i;
	for (i = 0; i < MAXPLAYERS; ++i) {
		if ( (i==0 && selectedEntity==my) || (client_selected[i]==my) ) {
			if (inrange[i]) { //Act on it only if the player (or monster, if/when this is changed to support monster interaction?) is in range.
				//First check that it's not depleted.
				if (my->skill[0] == 0) {
					//Depleted
					messagePlayer(i, language[467]);
				} else {
					if (players[i]->entity->flags[BURNING])
					{
						messagePlayer(i, language[468]);
						players[i]->entity->flags[BURNING] = FALSE;
						if (i > 0)
							serverUpdateEntityFlag(players[i]->entity, BURNING);
					}
					switch (my->skill[1]) {
						case 0: {
							playSoundEntity(players[i]->entity, 52, 64);
							
							//Spawn succubus.
							Uint32 color = SDL_MapRGB(mainsurface->format,255,128,0);
							messagePlayerColor(i, color, language[469]);
							summonMonster(SUCCUBUS, my->x, my->y);
							break;
						}
						case 1:
							messagePlayer(i, language[470]);
							messagePlayer(i, language[471]);
							playSoundEntity(players[i]->entity, 52, 64);
							stats[i]->HUNGER += 50;
							break;
						case 2: {
							//Potion effect. Potion effect is stored in my->skill[3], randomly chosen when the fountain is created.
							messagePlayer(i, language[470]);
							Item *item = newItem(static_cast<ItemType>(POTION_WATER+my->skill[3]), static_cast<Status>(4), 0,1,0,FALSE,NULL);
							useItem(item,i);
							// Long live the mystical fountain of TODO.
							break;
						}
						case 3: {
							// bless equipment
							playSoundEntity(players[i]->entity, 52, 64);
							Uint32 textcolor = SDL_MapRGB(mainsurface->format,0,255,255);
							messagePlayerColor(i, textcolor, language[471]);
							messagePlayer(i, language[473]);
							if( stats[i]->helmet )
								stats[i]->helmet->beatitude++;
							if( stats[i]->breastplate )
								stats[i]->breastplate->beatitude++;
							if( stats[i]->gloves )
								stats[i]->gloves->beatitude++;
							if( stats[i]->shoes )
								stats[i]->shoes->beatitude++;
							if( stats[i]->shield )
								stats[i]->shield->beatitude++;
							if( stats[i]->weapon )
								stats[i]->weapon->beatitude++;
							if( stats[i]->cloak )
								stats[i]->cloak->beatitude++;
							if( stats[i]->amulet )
								stats[i]->amulet->beatitude++;
							if( stats[i]->ring )
								stats[i]->ring->beatitude++;
							if( stats[i]->mask )
								stats[i]->mask->beatitude++;
							if( multiplayer==SERVER && i>0 ) {
								strcpy((char *)net_packet->data,"BLES");
								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);
							}
							break;
						}
						default:
							break;
					}
					messagePlayer(i, language[474]);
					my->skill[0] = 0; //Dry up fountain.
					//TODO: messagePlayersInSight() instead.
				}
				//Then perform the effect randomly determined when the fountain was created.
				return;
			}
		}
	}
}
示例#11
0
void actBoulderTrap(Entity *my) {
	int x, y;
	int c;

	BOULDERTRAP_AMBIENCE--;
	if( BOULDERTRAP_AMBIENCE<=0 ) {
		BOULDERTRAP_AMBIENCE = TICKS_PER_SECOND*30;
		playSoundEntity( my, 149, 64 );
	}
	
	if( !my->skill[28] )
		return;

	// received on signal
	if( my->skill[28] == 2) {
		if( !BOULDERTRAP_FIRED ) {
			playSoundEntity(my, 150, 128);
			for( c=0; c<MAXPLAYERS; c++ )
				playSoundPlayer(c, 150, 64);
			BOULDERTRAP_FIRED = 1;
			for( c=0; c<4; c++ ) {
				switch( c ) {
					case 0:
						x = 16;
						y = 0;
						break;
					case 1:
						x = 0;
						y = 16;
						break;
					case 2:
						x = -16;
						y = 0;
						break;
					case 3:
						x = 0;
						y = -16;
						break;
				}
				x = ((int)(x+my->x))>>4;
				y = ((int)(y+my->y))>>4;
				if( x>=0 && y>=0 && x<map.width && y<map.height ) {
					if( !map.tiles[OBSTACLELAYER+y*MAPLAYERS+x*MAPLAYERS*map.height] ) {
						Entity *entity = newEntity(245, 1, map.entities); // boulder
						entity->parent = my->uid;
						entity->x = (x<<4)+8;
						entity->y = (y<<4)+8;
						entity->z = -64;
						entity->yaw = c*(PI/2.f);
						entity->sizex = 7;
						entity->sizey = 7;
						if( checkObstacle( entity->x+cos(entity->yaw)*16, entity->y+sin(entity->yaw)*16, entity, NULL ) ) {
							entity->yaw += PI*(rand()%2)-PI/2;
							if( entity->yaw >= PI*2 )
								entity->yaw -= PI*2;
							else if( entity->yaw < 0 )
								entity->yaw += PI*2;
						}
						entity->behavior = &actBoulder;
						entity->flags[UPDATENEEDED] = TRUE;
						entity->flags[PASSABLE] = TRUE;
					}
				}
			}
		}
	}
示例#12
0
void actMinotaurCeilingBuster(Entity* my)
{
	double x, y;

	// levitate particles
	int u = std::min<unsigned int>(std::max<int>(0, my->x / 16), map.width - 1);
	int v = std::min<unsigned int>(std::max<int>(0, my->y / 16), map.height - 1);
	if ( !map.tiles[v * MAPLAYERS + u * MAPLAYERS * map.height] )
	{
		int c;
		for ( c = 0; c < 2; c++ )
		{
			Entity* entity = newEntity(171, 1, map.entities, nullptr); //Particle entity.
			entity->x = my->x - 8 + rand() % 17;
			entity->y = my->y - 8 + rand() % 17;
			entity->z = 10 + rand() % 3;
			entity->scalex = 0.7;
			entity->scaley = 0.7;
			entity->scalez = 0.7;
			entity->sizex = 1;
			entity->sizey = 1;
			entity->yaw = (rand() % 360) * PI / 180.f;
			entity->flags[PASSABLE] = true;
			entity->flags[BRIGHT] = true;
			entity->flags[NOUPDATE] = true;
			entity->flags[UNCLICKABLE] = true;
			entity->behavior = &actMagicParticle;
			if ( multiplayer != CLIENT )
			{
				entity_uids--;
			}
			entity->setUID(-3);
		}
	}

	// bust ceilings
	for ( x = my->x - my->sizex - 1; x <= my->x + my->sizex + 1; x += 1 )
	{
		for ( y = my->y - my->sizey - 1; y <= my->y + my->sizey + 1; y += 1 )
		{
			if ( x >= 0 && y >= 0 && x < map.width << 4 && y < map.height << 4 )
			{
				int index = (MAPLAYERS - 1) + ((int)floor(y / 16)) * MAPLAYERS + ((int)floor(x / 16)) * MAPLAYERS * map.height;
				if ( map.tiles[index] )
				{
					if ( my->monsterAttack == 0 )
					{
						if ( multiplayer != CLIENT )
						{
							my->attack(MONSTER_POSE_MELEE_WINDUP2, 0, nullptr);
						}
						return;
					}
					else if ( my->monsterAttack == MONSTER_POSE_MELEE_WINDUP2 )
					{
						return;
					}
					map.tiles[index] = 0;
					if ( multiplayer != CLIENT )
					{
						playSoundEntity(my, 67, 128);
						//MONSTER_ATTACK = 1;
						Stat* myStats = my->getStats();
						if ( myStats )
						{
							// easy hack to stop the minotaur while he breaks stuff
							myStats->EFFECTS[EFF_PARALYZED] = true;
							myStats->EFFECTS_TIMERS[EFF_PARALYZED] = 10;
						}
					}

					// spawn several rock particles (NOT items)
					int c, i = 6 + rand() % 4;
					for ( c = 0; c < i; c++ )
					{
						Entity *entity = nullptr;
						if ( multiplayer == SERVER )
						{
							entity = spawnGib(my);
						}
						else
						{
							entity = spawnGibClient(my->x, my->y, my->z, 5);
						}
						if ( entity )
						{
							entity->x = ((int)(my->x / 16)) * 16 + rand() % 16;
							entity->y = ((int)(my->y / 16)) * 16 + rand() % 16;
							entity->z = -8;
							entity->flags[PASSABLE] = true;
							entity->flags[INVISIBLE] = false;
							entity->flags[NOUPDATE] = true;
							entity->flags[UPDATENEEDED] = false;
							entity->sprite = items[GEM_ROCK].index;
							entity->yaw = rand() % 360 * PI / 180;
							entity->pitch = rand() % 360 * PI / 180;
							entity->roll = rand() % 360 * PI / 180;
							entity->vel_x = (rand() % 20 - 10) / 10.0;
							entity->vel_y = (rand() % 20 - 10) / 10.0;
							entity->vel_z = -.25;
							entity->fskill[3] = 0.03;
						}
					}
				}
				node_t* node, *nextnode;
				std::vector<list_t*> entLists = TileEntityList.getEntitiesWithinRadiusAroundEntity(my, 2);
				for ( std::vector<list_t*>::iterator it = entLists.begin(); it != entLists.end(); ++it )
				{
					list_t* currentList = *it;
					for ( node = currentList->first; node != nullptr; node = nextnode )
					{
						nextnode = node->next;
						Entity* entity = (Entity*)node->element;
						if ( (int)(x / 16) == (int)(entity->x / 16) && (int)(y / 16) == (int)(entity->y / 16) )
						{
							if ( entity->behavior == &actDoorFrame )
							{
								// spawn several rock items
								int c, i = 8 + rand() % 4;
								for ( c = 0; c < i; c++ )
								{
									Entity *entity = nullptr;
									if ( multiplayer == SERVER )
									{
										entity = spawnGib(my);
									}
									else
									{
										entity = spawnGibClient(my->x, my->y, my->z, 5);
									}
									if ( entity )
									{
										entity->x = ((int)(my->x / 16)) * 16 + rand() % 16;
										entity->y = ((int)(my->y / 16)) * 16 + rand() % 16;
										entity->z = -8;
										entity->flags[PASSABLE] = true;
										entity->flags[INVISIBLE] = false;
										entity->flags[NOUPDATE] = true;
										entity->flags[UPDATENEEDED] = false;
										entity->sprite = items[GEM_ROCK].index;
										entity->yaw = rand() % 360 * PI / 180;
										entity->pitch = rand() % 360 * PI / 180;
										entity->roll = rand() % 360 * PI / 180;
										entity->vel_x = (rand() % 20 - 10) / 10.0;
										entity->vel_y = (rand() % 20 - 10) / 10.0;
										entity->vel_z = -.25;
										entity->fskill[3] = 0.03;
									}
								}
								list_RemoveNode(entity->mynode);
							}
							else if ( entity->behavior == &actDoor )
							{
								if ( multiplayer != CLIENT )
								{
									entity->skill[4] = 0; // destroy the door
								}
							}
							else if ( entity->behavior == &actGate )
							{
								if ( multiplayer != CLIENT )
								{
									playSoundEntity(entity, 76, 64);
									list_RemoveNode(entity->mynode);
								}
							}
							else if (	entity->behavior == &actStalagCeiling	||
										entity->behavior == &actStalagFloor		||
										entity->behavior == &actStalagColumn
									)
							{
								// spawn several rock items
								int c, i = rand() % 4;
								for ( c = 0; c < i; ++c )
								{
									//Entity* childEntity = spawnGib(my);
									Entity *childEntity = nullptr;
									if ( multiplayer == SERVER )
									{
										childEntity = spawnGib(my);
									}
									else
									{
										childEntity = spawnGibClient(my->x, my->y, my->z, 5);
									}
									if ( entity )
									{
										childEntity->x = ((int)(my->x / 16)) * 16 + rand() % 16;
										childEntity->y = ((int)(my->y / 16)) * 16 + rand() % 16;
										childEntity->z = -8;
										childEntity->flags[PASSABLE] = true;
										childEntity->flags[INVISIBLE] = false;
										childEntity->flags[NOUPDATE] = true;
										childEntity->flags[UPDATENEEDED] = false;
										childEntity->sprite = items[GEM_ROCK].index;
										childEntity->yaw = rand() % 360 * PI / 180;
										childEntity->pitch = rand() % 360 * PI / 180;
										childEntity->roll = rand() % 360 * PI / 180;
										childEntity->vel_x = (rand() % 20 - 10) / 10.0;
										childEntity->vel_y = (rand() % 20 - 10) / 10.0;
										childEntity->vel_z = -.25;
										childEntity->fskill[3] = 0.03;
									}
								}
								list_RemoveNode(entity->mynode);
							}
						}
					}
				}
			}
		}
	}
}
示例#13
0
int boulderCheckAgainstEntity(Entity *my, Entity *entity) {
	if (!my || !entity)
		return 0;

	if( entity->behavior == &actPlayer || entity->behavior == &actMonster ) {
		if( entityInsideEntity( my, entity ) ) {
			Stat *stats = entity->getStats();
			if( stats ) {
				if( entity->behavior==&actPlayer ) {
					Uint32 color = SDL_MapRGB(mainsurface->format,255,0,0);
					messagePlayerColor(entity->skill[2],color,language[455]);
					if( entity->skill[2] == clientnum ) {
						camera_shakex += .1;
						camera_shakey += 10;
					} else {
						strcpy((char *)net_packet->data,"SHAK");
						net_packet->data[4]=10; // turns into .1
						net_packet->data[5]=10;
						net_packet->address.host = net_clients[entity->skill[2]-1].host;
						net_packet->address.port = net_clients[entity->skill[2]-1].port;
						net_packet->len = 6;
						sendPacketSafe(net_sock, -1, net_packet, entity->skill[2]-1);
					}
				}
				playSoundEntity(my,181,128);
				playSoundEntity(entity,28,64);
				spawnGib(entity);
				entity->modHP(-80);
				entity->setObituary(language[1505]);
				if( entity->behavior==&actPlayer )
					if( stats->HP<=0 )
						steamAchievementClient(entity->skill[2],"BARONY_ACH_THROW_ME_THE_WHIP");
				if( stats->HP > 0 ) {
					// spawn several rock items
					int i = 8+rand()%4;
					
					int c;
					for( c=0; c<i; c++ ) {
						Entity *entity = newEntity(-1,1,map.entities);
						entity->flags[INVISIBLE]=TRUE;
						entity->flags[UPDATENEEDED]=TRUE;
						entity->x = my->x - 4 + rand()%8;
						entity->y = my->y - 4 + rand()%8;
						entity->z = -6+rand()%12;
						entity->sizex = 4;
						entity->sizey = 4;
						entity->yaw = rand()%360 * PI/180;
						entity->vel_x = (rand()%20-10)/10.0;
						entity->vel_y = (rand()%20-10)/10.0;
						entity->vel_z = -.25 - (rand()%5)/10.0;
						entity->flags[PASSABLE] = TRUE;
						entity->behavior = &actItem;
						entity->flags[USERFLAG1] = TRUE; // no collision: helps performance
						entity->skill[10] = GEM_ROCK;    // type
						entity->skill[11] = WORN;        // status
						entity->skill[12] = 0;           // beatitude
						entity->skill[13] = 1;           // count
						entity->skill[14] = 0;           // appearance
						entity->skill[15] = FALSE;       // identified
					}

					double ox = my->x;
					double oy = my->y;
					
					// destroy the boulder
					playSoundEntity(my,67,128);
					list_RemoveNode(my->mynode);

					// on sokoban, destroying boulders spawns scorpions
					if( !strcmp(map.name,"Sokoban") ) {
						Entity *monster = summonMonster(SCORPION,ox,oy);
						if( monster ) {
							int c;
							for( c=0; c<MAXPLAYERS; c++ ) {
								Uint32 color = SDL_MapRGB(mainsurface->format,255,128,0);
								messagePlayerColor(c,color,language[406]);
							}
						}
					}

					return 1;
				}
			}
		}
	} else if( entity->behavior == &actGate || entity->behavior == &actBoulder || entity->behavior==&actChest || entity->behavior==&actHeadstone || entity->behavior==&actFountain || entity->behavior==&actSink ) {
		if( !entity->flags[PASSABLE] ) {
			if( entityInsideEntity( my, entity ) ) {
				// stop the boulder
				BOULDER_STOPPED=1;
				BOULDER_ROLLING=0;
				playSoundEntity(my,181,128);
				if( my->flags[PASSABLE] ) {
					my->flags[PASSABLE] = FALSE;
					if( multiplayer==SERVER )
						serverUpdateEntityFlag(my,PASSABLE);
				}
			}
		}
	} else if( entity->behavior == &actDoor ) {
		if( entityInsideEntity( my, entity ) ) {
			playSoundEntity(entity,28,64);
			entity->skill[4] = 0;
			if( !entity->skill[0] )
				entity->skill[6] = (my->x > entity->x);
			else
				entity->skill[6] = (my->y < entity->y);
			playSoundEntity(my,181,128);
		}
	}
	return 0;
}
示例#14
0
void actGoldBag(Entity *my) {
	int i;

	if( my->flags[INVISIBLE] ) {
		if( multiplayer!=CLIENT ) {
			node_t *node;
			for( node=map.entities->first; node!=NULL; node=node->next ) {
				Entity *entity = (Entity *)node->element;
				if( entity->sprite == 245 ) // boulder.vox
					return;
			}
			my->flags[INVISIBLE] = FALSE;
			serverUpdateEntityFlag(my,INVISIBLE);
			if( !strcmp(map.name,"Sokoban") ) {
				for( i=0; i<MAXPLAYERS; i++ )
					steamAchievementClient(i,"BARONY_ACH_PUZZLE_MASTER");
			}
		} else {
			return;
		}
	}

	GOLDBAG_AMBIENCE--;
	if( GOLDBAG_AMBIENCE<=0 ) {
		GOLDBAG_AMBIENCE = TICKS_PER_SECOND*30;
		playSoundEntityLocal( my, 149, 16 );
	}
	
	// pick up gold
	if( multiplayer!=CLIENT ) {
		for(i=0;i<MAXPLAYERS;i++) {
			if( (i==0 && selectedEntity==my) || (client_selected[i]==my) ) {
				if(inrange[i]) {
					if (players[i] && players[i]->entity)
						playSoundEntity(players[i]->entity, 242+rand()%4, 64 );
					stats[i]->GOLD += GOLDBAG_AMOUNT;
					if( i!=0 ) {
						if( multiplayer==SERVER ) {
							// send the client info on the gold it picked up
							strcpy((char *)net_packet->data,"GOLD");
							SDLNet_Write32(stats[i]->GOLD,&net_packet->data[4]);
							net_packet->address.host = net_clients[i-1].host;
							net_packet->address.port = net_clients[i-1].port;
							net_packet->len = 8;
							sendPacketSafe(net_sock, -1, net_packet, i-1);
						}
					}

					// message for item pickup
					if( GOLDBAG_AMOUNT==1 )
						messagePlayer(i,language[483]);
					else
						messagePlayer(i,language[484],GOLDBAG_AMOUNT);

					// remove gold entity
					list_RemoveNode(my->mynode);
					return;
				}
			}
		}
	} else {
		my->flags[NOUPDATE] = TRUE;
	}
}
示例#15
0
void actSwitch(Entity* my)
{
	//TODO: If powered on, and it detects a depowered neighbor, it should pulse that neighbor to turn on.
	//Thus, this function needs to be called periodically.
	//This is so that if a switch goes off and there's another switch on the network, the entire network shuts off regardless of the other switch's status.
	//So then when that second switch's actSwitch() comes up, and if it's on, it'll repower the entire network -- which will stay powered until ALL connected switches go off.
	my->flags[PASSABLE] = true; // these should ALWAYS be passable. No exceptions

	if ( multiplayer != CLIENT )
	{
		int i = 0;
		for (i = 0; i < MAXPLAYERS; ++i)
		{
			if ( (i == 0 && selectedEntity == my) || (client_selected[i] == my) )
			{
				if (inrange[i])   //Act on it only if the player (or monster, if/when this is changed to support monster interaction?) is in range.
				{
					messagePlayer(i, language[1110]);
					playSoundEntity(my, 56, 64);
					my->toggleSwitch();
				}
			}
		}
		if ( my->isInteractWithMonster() )
		{
			my->toggleSwitch();
			my->clearMonsterInteract();
		}

		if (my->skill[0])
		{
			//Power on any neighbors that don't have power.
			my->switchUpdateNeighbors();
			//TODO: Alternatively, instead of using CPU cycles on this, have the recursive network shutdown alert any switches connected to it that are powered on that it's shutting down, so that they can repower the network come next frame.
		}
	}
	else
	{
		my->flags[NOUPDATE] = true;
	}

	// Rotate the switch when it is on/off.
	if ( my->skill[0] )
	{
		if ( my->roll > -PI / 4 )
		{
			my->roll -= std::max<real_t>((my->roll + PI / 4) / 2, .05);
		}
		else
		{
			my->roll = -PI / 4;
		}
	}
	else
	{
		if ( my->roll < PI / 4 )
		{
			my->roll += std::max<real_t>(-(my->roll - PI / 4) / 2, .05);
		}
		else
		{
			my->roll = PI / 4;
		}
	}
}
示例#16
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;
}
示例#17
0
void actSwitchWithTimer(Entity* my)
{
	my->flags[PASSABLE] = true; // these should ALWAYS be passable. No exceptions

	if ( multiplayer != CLIENT )
	{
		int i = 0;
		for ( i = 0; i < MAXPLAYERS; ++i )
		{
			if ( (i == 0 && selectedEntity == my) || (client_selected[i] == my) )
			{
				// server/client has clicked on the entity.
				if ( inrange[i] )   //Act on it only if the player (or monster, if/when this is changed to support monster interaction?) is in range.
				{
					switch ( my->leverStatus )
					{
						case 0:
							messagePlayer(i, language[2360]);
							break;
						case 1:
							messagePlayer(i, language[2361]);
							break;
						case 2:
							messagePlayer(i, language[2362]);
							break;
						default:
							messagePlayer(i, language[2363]);
							break;
					}

					if ( my->leverStatus < 3 )
					{
						++my->leverStatus;
						playSoundEntity(my, 248, 64);
						serverUpdateEntitySkill(my, 1);
						if ( my->leverStatus == 3 )
						{
							playSoundEntity(my, 56, 64);
							my->toggleSwitch();
						}
					}
				}
			}
		}

		if ( my->leverStatus == 4 )
		{
			//Power on any neighbors that don't have power.
			my->switchUpdateNeighbors();
			//TODO: Alternatively, instead of using CPU cycles on this, have the recursive network shutdown alert any switches connected to it that are powered on that it's shutting down, so that they can repower the network come next frame.
		}
	}
	else
	{
		my->flags[NOUPDATE] = true;
	}

	// Rotate the switch when it is on/off.
	if ( my->leverStatus == 0 )
	{
		if ( my->roll > -PI / 4 )
		{
			my->roll -= std::max<real_t>((my->roll + PI / 4) / 2, .05);
		}
		else
		{
			my->roll = -PI / 4;
		}
	}
	else if (my->leverStatus == 1 ) // 1/3 of the way up
	{
		if ( my->roll < -PI / 12 )
		{
			my->roll += std::max<real_t>(-(my->roll + PI / 12) / 8, .02);
		}
		else
		{
			my->roll = -PI / 12;
		}
	}
	else if ( my->leverStatus == 2 ) // 2/3 of the way up
	{
		if ( my->roll < PI / 12 )
		{
			my->roll += std::max<real_t>(-(my->roll - PI / 12) / 8, .02);
		}
		else
		{
			my->roll = PI / 12;
		}
	}
	else if ( my->leverStatus == 3 ) // all the way up
	{
		if ( my->roll < PI / 4 )
		{
			my->roll += std::max<real_t>(-(my->roll - PI / 4) / 4, .02);
		}
		else
		{
			my->roll = PI / 4;
			if ( multiplayer != CLIENT )
			{
				my->leverStatus = 4;
				serverUpdateEntitySkill(my, 1);
			}
		}
	}
	else if ( my->leverStatus == 4 ) // ticking down
	{
		if ( my->roll > -PI / 12 )
		{
			my->roll -= (PI / 3) / static_cast<real_t>(my->leverTimerTicks); // move slowly towards 2/3rds of the resting point
			if ( my->ticks % 10 == 0 )
			{
				playSoundEntityLocal(my, 247, 32);
			}
		}
		else
		{
			my->roll = -PI / 12;
			if ( multiplayer != CLIENT )
			{
				playSoundEntity(my, 56, 64);
				my->leverStatus = 0;
				serverUpdateEntitySkill(my, 1);
				my->toggleSwitch();
			}
		}
	}
}
示例#18
0
void actBoulder(Entity *my) {
	int i;
	
	my->skill[2]=-7; // invokes actEmpty() on clients
	my->flags[UPDATENEEDED] = TRUE;

	bool noground=FALSE;
	int x = std::min<int>(std::max(0,(int)(my->x/16)),map.width);
	int y = std::min<int>(std::max(0,(int)(my->y/16)),map.height);
	Uint32 index = y*MAPLAYERS+x*MAPLAYERS*map.height;
	if( !map.tiles[index] || animatedtiles[map.tiles[index]] )
		noground = TRUE;

	// gravity
	bool nobounce=TRUE;
	if( !BOULDER_NOGROUND )
		if( noground )
			BOULDER_NOGROUND = TRUE;
	if( my->z < 0 || BOULDER_NOGROUND ) {
		my->vel_z = std::min(my->vel_z+.1,3.0);
		nobounce = TRUE;
		if( my->z >= 128 ) {
			list_RemoveNode(my->mynode);
			return;
		}
		if( !BOULDER_NOGROUND ) {
			if( my->z >= -8 && fabs(my->vel_z) > 2 ) {
				node_t *node;
				for( node=map.entities->first; node!=NULL; node=node->next ) {
					Entity *entity = (Entity *)node->element;
					if( entity == my )
						continue;
					if( boulderCheckAgainstEntity(my,entity) )
						return;
				}
			}
		}
	} else {
		if( fabs(my->vel_z) > 1 ) {
			playSoundEntity(my,182,128);
			my->vel_z = -(my->vel_z/2);
			nobounce = TRUE;
		} else {
			if( my->vel_z )
				playSoundEntity(my,182,128);
			my->vel_z = 0;
			nobounce = FALSE;
		}
		my->z = 0;
	}
	my->z += my->vel_z;
	if( nobounce ) {
		if( !my->flags[PASSABLE] ) {
			my->flags[PASSABLE] = TRUE;
			if( multiplayer==SERVER )
				serverUpdateEntityFlag(my,PASSABLE);
		}
		if( !BOULDER_STOPPED ) {
			my->x += my->vel_x;
			my->y += my->vel_y;
			double dist = sqrt(pow(my->vel_x,2)+pow(my->vel_y,2));
			my->pitch += dist*.06;
			my->roll = PI/2;
		}
	} else if( !BOULDER_STOPPED ) {
		if( my->flags[PASSABLE] ) {
			my->flags[PASSABLE] = FALSE;
			if( multiplayer==SERVER )
				serverUpdateEntityFlag(my,PASSABLE);
		}
		
		// horizontal velocity
		my->vel_x += cos(my->yaw)*.1;
		my->vel_y += sin(my->yaw)*.1;
		if( my->vel_x > 1.5 )
			my->vel_x = 1.5;
		if( my->vel_x < -1.5 )
			my->vel_x = -1.5;
		if( my->vel_y > 1.5 )
			my->vel_y = 1.5;
		if( my->vel_y < -1.5 )
			my->vel_y = -1.5;
		int x = std::min<int>(std::max(0.0,(my->x+cos(my->yaw)*8)/16),map.width-1);
		int y = std::min<int>(std::max(0.0,(my->y+sin(my->yaw)*8)/16),map.height-1);
		if( map.tiles[OBSTACLELAYER+y*MAPLAYERS+x*MAPLAYERS*map.height] ) {
			playSoundEntity(my,181,128);
			BOULDER_STOPPED = 1;
		} else {
			my->x += my->vel_x;
			my->y += my->vel_y;
			double dist = sqrt(pow(my->vel_x,2)+pow(my->vel_y,2));
			my->pitch += dist*.06;
			my->roll = PI/2;
		
			// crush objects
			if( dist && !BOULDER_NOGROUND ) {
				node_t *node;
				for( node=map.entities->first; node!=NULL; node=node->next ) {
					Entity *entity = (Entity *)node->element;
					if( entity == my )
						continue;
					if( boulderCheckAgainstEntity(my,entity) )
						return;
				}
			}
		}
	}
	
	// pushing boulders
	if( BOULDER_STOPPED ) {
		if( !BOULDER_ROLLING ) {
			for(i=0;i<MAXPLAYERS;i++) {
				if( (i==0 && selectedEntity==my) || (client_selected[i]==my) ) {
					if(inrange[i]) {
						if( statGetSTR(stats[i])<5 ) {
							messagePlayer(i,language[456]);
						} else {
							if( players[i] ) {
								playSoundEntity(my, 151, 128);
								BOULDER_ROLLING=1;
								my->x = floor(my->x/16)*16+8;
								my->y = floor(my->y/16)*16+8;
								BOULDER_DESTX=(int)(my->x/16)*16+8;
								BOULDER_DESTY=(int)(my->y/16)*16+8;
								if( (int)(players[i]->x/16) < (int)(my->x/16) ) {
									BOULDER_ROLLDIR=0; // east
								} else if( (int)(players[i]->y/16) < (int)(my->y/16) ) {
									BOULDER_ROLLDIR=1; // south
								} else if( (int)(players[i]->x/16) > (int)(my->x/16) ) {
									BOULDER_ROLLDIR=2; // west
								} else if( (int)(players[i]->y/16) > (int)(my->y/16) ) {
									BOULDER_ROLLDIR=3; // north
								}
								switch( BOULDER_ROLLDIR ) {
									case 0:
										BOULDER_DESTX += 16;
										break;
									case 1:
										BOULDER_DESTY += 16;
										break;
									case 2:
										BOULDER_DESTX -= 16;
										break;
									case 3:
										BOULDER_DESTY -= 16;
										break;
								}
							}
						}
					}
				}
			}
		} else {
			switch( BOULDER_ROLLDIR ) {
				case 0:
					my->vel_x=1;
					my->vel_y=0;
					break;
				case 1:
					my->vel_x=0;
					my->vel_y=1;
					break;
				case 2:
					my->vel_x=-1;
					my->vel_y=0;
					break;
				case 3:
					my->vel_x=0;
					my->vel_y=-1;
					break;
			}
			int x = (my->x+my->vel_x*8)/16;
			int y = (my->y+my->vel_y*8)/16;
			x = std::min<unsigned int>(std::max(0,x),map.width-1);
			y = std::min<unsigned int>(std::max(0,y),map.height-1);
			if( map.tiles[OBSTACLELAYER+y*MAPLAYERS+x*MAPLAYERS*map.height] ) {
				BOULDER_ROLLING = 0;
			} else {
				my->x += my->vel_x;
				my->y += my->vel_y;
				double dist = sqrt(pow(my->vel_x,2)+pow(my->vel_y,2));
				my->pitch += dist*.06;

				if( BOULDER_ROLLDIR==0 ) {
					if( my->x>=BOULDER_DESTX ) {
						my->x=BOULDER_DESTX;
						BOULDER_ROLLING=0;
					}
				} else if( BOULDER_ROLLDIR==1 ) {
					if( my->y>=BOULDER_DESTY ) {
						my->y=BOULDER_DESTY;
						BOULDER_ROLLING=0;
					}
				} else if( BOULDER_ROLLDIR==2 ) {
					if( my->x<=BOULDER_DESTX ) {
						my->x=BOULDER_DESTX;
						BOULDER_ROLLING=0;
					}
				} else if( BOULDER_ROLLDIR==3 ) {
					if( my->y<=BOULDER_DESTY ) {
						my->y=BOULDER_DESTY;
						BOULDER_ROLLING=0;
					}
				}
				double dir = my->yaw - BOULDER_ROLLDIR*PI/2;
				while( dir >= PI )
					dir -= PI*2;
				while( dir < -PI )
					dir += PI*2;
				my->yaw -= dir/16;
				while( my->yaw < 0 )
					my->yaw += 2*PI;
				while( my->yaw >= 2*PI )
					my->yaw -= 2*PI;
		
				// crush objects
				if( dist && !BOULDER_NOGROUND ) {
					node_t *node;
					for( node=map.entities->first; node!=NULL; node=node->next ) {
						Entity *entity = (Entity *)node->element;
						if( entity == my )
							continue;
						if( boulderCheckAgainstEntity(my,entity) )
							return;
					}
				}
			}
		}
	}

	// wrap around angles
	while( my->pitch >= PI*2 )
		my->pitch -= PI*2;
	while( my->pitch < 0 )
		my->pitch += PI*2;
	while( my->roll >= PI*2 )
		my->roll -= PI*2;
	while( my->roll < 0 )
		my->roll += PI*2;
	
	// rolling sound
	if( !BOULDER_STOPPED && (fabs(my->vel_x)>0 || fabs(my->vel_y)>0) ) {
		BOULDER_AMBIENCE++;
		if( BOULDER_AMBIENCE>=TICKS_PER_SECOND/3 ) {
			BOULDER_AMBIENCE=0;
			playSoundEntity(my, 151, 128);
		}
	}
}
示例#19
0
void actItem(Entity* my)
{
	Item* item;
	int i;

	if ( multiplayer == CLIENT )
	{
		my->flags[NOUPDATE] = true;
		if ( ITEM_LIFE == 0 )
		{
			Entity* tempEntity = uidToEntity(clientplayer);
			if ( tempEntity )
			{
				if ( entityInsideEntity(my, tempEntity) )
				{
					my->parent = tempEntity->getUID();
				}
				else
				{
					node_t* node;
					for ( node = map.creatures->first; node != nullptr; node = node->next )
					{
						Entity* entity = (Entity*)node->element;
						if ( entity->behavior == &actPlayer || entity->behavior == &actMonster )
						{
							if ( entityInsideEntity(my, entity) )
							{
								my->parent = entity->getUID();
								break;
							}
						}
					}
				}
			}
			else
			{
				node_t* node;
				for ( node = map.creatures->first; node != nullptr; node = node->next )
				{
					Entity* entity = (Entity*)node->element;
					if ( entity->behavior == &actPlayer || entity->behavior == &actMonster )
					{
						if ( entityInsideEntity(my, entity) )
						{
							my->parent = entity->getUID();
							break;
						}
					}
				}
			}
		}

		// request entity update (check if I've been deleted)
		if ( ticks % (TICKS_PER_SECOND * 5) == my->getUID() % (TICKS_PER_SECOND * 5) )
		{
			strcpy((char*)net_packet->data, "ENTE");
			net_packet->data[4] = clientnum;
			SDLNet_Write32(my->getUID(), &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);
		}
	}
	else
	{
		// select appropriate model
		my->skill[2] = -5;
		if ( my->itemSokobanReward != 1 )
		{
			my->flags[INVISIBLE] = false;
		}
		item = newItemFromEntity(my);
		my->sprite = itemModel(item);
		free(item);
	}
	//if( ITEM_LIFE==0 )
	//	playSoundEntityLocal( my, 149, 64 );
	ITEM_LIFE++;
	/*ITEM_AMBIENCE++;
	if( ITEM_AMBIENCE>=TICKS_PER_SECOND*30 ) {
		ITEM_AMBIENCE=0;
		playSoundEntityLocal( my, 149, 64 );
	}*/

	// pick up item
	if (multiplayer != CLIENT)
	{
		if ( my->isInteractWithMonster() )
		{
			Entity* monsterInteracting = uidToEntity(my->interactedByMonster);
			if ( monsterInteracting )
			{
				if ( my->skill[10] >= 0 && my->skill[10] < NUMITEMS )
				{
					if ( items[my->skill[10]].category == Category::FOOD && monsterInteracting->getMonsterTypeFromSprite() != SLIME )
					{
						monsterInteracting->monsterConsumeFoodEntity(my, monsterInteracting->getStats());
					}
					else
					{
						monsterInteracting->monsterAddNearbyItemToInventory(monsterInteracting->getStats(), 24, 9, my);
					}
				}
				my->clearMonsterInteract();
				return;
			}
			my->clearMonsterInteract();
		}
		for ( i = 0; i < MAXPLAYERS; i++)
		{
			if ((i == 0 && selectedEntity == my) || (client_selected[i] == my))
			{
				if (inrange[i])
				{
					if (players[i] != nullptr && players[i]->entity != nullptr)
					{
						playSoundEntity( players[i]->entity, 35 + rand() % 3, 64 );
					}
					Item* item2 = newItemFromEntity(my);
					if ( players[i] && players[i]->entity )
					{
						if ( my->itemStolen == 1 && item2 && (static_cast<Uint32>(item2->ownerUid) == players[i]->entity->getUID()) )
						{
							steamAchievementClient(i, "BARONY_ACH_REPOSSESSION");
						}
					}
					//messagePlayer(i, "old owner: %d", item2->ownerUid);
					if (item2)
					{
						item = itemPickup(i, item2);
						if (item)
						{
							if (i == 0)
							{
								free(item2);
							}
							int oldcount = item->count;
							item->count = 1;
							messagePlayer(i, language[504], item->description());
							item->count = oldcount;
							if (i != 0)
							{
								free(item);
							}
							my->removeLightField();
							list_RemoveNode(my->mynode);
							return;
						}
					}
				}
			}
		}
	}

	if ( my->itemNotMoving )
	{
		switch ( my->sprite )
		{
			case 610:
			case 611:
			case 612:
			case 613:
				my->spawnAmbientParticles(80, my->sprite - 4, 10 + rand() % 40, 1.0, false);
				if ( !my->light )
				{
					my->light = lightSphereShadow(my->x / 16, my->y / 16, 3, 192);
				}
				break;
			default:
				break;
		}
		if ( multiplayer == CLIENT )
		{
			// let the client process some more gravity and make sure it isn't stopping early at an awkward angle.
			if ( my->itemNotMovingClient == 1 )
			{
				return;
			}
		}
		else
		{
			return;
		}
	}

	// gravity
	bool onground = false;
	if ( my->z < 7.5 - models[my->sprite]->sizey * .25 )
	{
		// fall
		// chakram and shuriken lie flat, needs to use sprites for client
		if ( my->sprite == 567 || my->sprite == 569 )
		{
			// todo: adjust falling rates for thrown items if need be
			ITEM_VELZ += 0.04;
			my->z += ITEM_VELZ;
			my->roll += 0.08;
		}
		else
		{
			ITEM_VELZ += 0.04;
			my->z += ITEM_VELZ;
			my->roll += 0.04;
		}
	}
	else
	{
		if ( my->x >= 0 && my->y >= 0 && my->x < map.width << 4 && my->y < map.height << 4 )
		{
			if ( map.tiles[(int)(my->y / 16)*MAPLAYERS + (int)(my->x / 16)*MAPLAYERS * map.height] 
				|| (my->sprite >= 610 && my->sprite <= 613) )
			{
				// land
				ITEM_VELZ *= -.7;
				if ( ITEM_VELZ > -.35 )
				{
					// chakram and shuriken lie flat, needs to use sprites for client
					if ( my->sprite == 567 || my->sprite == 569 )
					{
						my->roll = PI;
						my->pitch = 0;
						if ( my->sprite == 569 )
						{
							my->z = 8.5 - models[my->sprite]->sizey * .25;
						}
						else
						{
							my->z = 8.75 - models[my->sprite]->sizey * .25;
						}
					}
					else
					{
						my->roll = PI / 2.0;
						my->z = 7.5 - models[my->sprite]->sizey * .25;
					}
					ITEM_VELZ = 0;
					onground = true;
				}
				else
				{
					onground = true;
					my->z = 7.5 - models[my->sprite]->sizey * .25 - .0001;
				}
			}
			else
			{
				// fall
				ITEM_VELZ += 0.04;
				my->z += ITEM_VELZ;
				my->roll += 0.04;
			}
		}
		else
		{
			// fall
			ITEM_VELZ += 0.04;
			my->z += ITEM_VELZ;
			my->roll += 0.04;
		}
	}

	// falling out of the map
	if ( my->z > 128 )
	{
		if ( ITEM_TYPE == ARTIFACT_MACE && my->parent != 0 )
		{
			steamAchievementEntity(uidToEntity(my->parent), "BARONY_ACH_STFU");
		}
		list_RemoveNode(my->mynode);
		return;
	}

	// don't perform unneeded computations on items that have basically no velocity
	double groundheight;
	if ( my->sprite == 569 )
	{
		groundheight = 8.5 - models[my->sprite]->sizey * .25;
	}
	else if ( my->sprite == 567 )
	{
		groundheight = 8.75 - models[my->sprite]->sizey * .25;
	}
	else
	{
		groundheight = 7.5 - models[my->sprite]->sizey * .25;
	}

	if ( onground && my->z > groundheight - .0001 && my->z < groundheight + .0001 && fabs(ITEM_VELX) < 0.02 && fabs(ITEM_VELY) < 0.02 )
	{
		my->itemNotMoving = 1;
		my->flags[UPDATENEEDED] = false;
		if ( multiplayer != CLIENT )
		{
			serverUpdateEntitySkill(my, 18); //update itemNotMoving flag
		}
		else
		{
			my->itemNotMovingClient = 1;
		}
		return;
	}

	// horizontal motion
	if ( ITEM_NOCOLLISION )
	{
		double newx = my->x + ITEM_VELX;
		double newy = my->y + ITEM_VELY;
		if ( !checkObstacle( newx, newy, my, NULL ) )
		{
			my->x = newx;
			my->y = newy;
			my->yaw += sqrt( ITEM_VELX * ITEM_VELX + ITEM_VELY * ITEM_VELY ) * .05;
		}
	}
	else
	{
		double result = clipMove(&my->x, &my->y, ITEM_VELX, ITEM_VELY, my);
		my->yaw += result * .05;
		if ( result != sqrt( ITEM_VELX * ITEM_VELX + ITEM_VELY * ITEM_VELY ) )
		{
			if ( !hit.side )
			{
				ITEM_VELX *= -.5;
				ITEM_VELY *= -.5;
			}
			else if ( hit.side == HORIZONTAL )
			{
				ITEM_VELX *= -.5;
			}
			else
			{
				ITEM_VELY *= -.5;
			}
		}
	}
	ITEM_VELX = ITEM_VELX * .925;
	ITEM_VELY = ITEM_VELY * .925;
}