Exemple #1
0
void spell_changeHealth(Entity* entity, int amount)
{
	if (!entity)
	{
		return;
	}

	entity->modHP(amount);

	int player = -1;
	int i = 0;
	for (i = 0; i < MAXPLAYERS; ++i)
	{
		if (entity == players[i]->entity)
		{
			player = i;
		}
	}

	if (player > -1 && player < MAXPLAYERS)
	{
		if (amount > 0)
		{
			Uint32 color = SDL_MapRGB(mainsurface->format, 0, 255, 0);
			messagePlayerColor(player, color, language[443]);
		}
		else
		{
			Uint32 color = SDL_MapRGB(mainsurface->format, 255, 255, 0);
			if (amount == 0)
			{
				messagePlayerColor(player, color, language[444]);
			}
			else
			{
				messagePlayerColor(player, color, language[445]);
			}
		}

		if (multiplayer == SERVER)
		{
			strcpy((char*)net_packet->data, "UPHP");
			SDLNet_Write32((Uint32)stats[player]->HP, &net_packet->data[4]);
			SDLNet_Write32(0, &net_packet->data[8]);
			net_packet->address.host = net_clients[player - 1].host;
			net_packet->address.port = net_clients[player - 1].port;
			net_packet->len = 12;
			sendPacketSafe(net_sock, net_packet->channel, net_packet, player - 1);
		}
	}
}
void actMinotaurTrap(Entity* my)
{
	if ( !my->skill[28] )
	{
		return;
	}

	// received on signal
	if ( my->skill[28] == 2)
	{
		if ( !MINOTAURTRAP_FIRED )
		{
			Entity* monster = summonMonster(MINOTAUR, my->x, my->y);
			if ( monster )
			{
				MINOTAURTRAP_FIRED = 1;
				if ( strcmp(map.name, "Hell Boss") )
				{
					int c;
					for ( c = 0; c < MAXPLAYERS; c++ )
					{
						playSoundPlayer( c, 107 + rand() % 3, 128 );
						Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
						messagePlayerColor(c, color, language[1113]);
					}
				}
			}
		}
	}
}
Exemple #3
0
void actHeadstone(Entity* my)
{
	if ( my->flags[INVISIBLE] )
	{
		if ( multiplayer != CLIENT )
		{
			node_t* node;
			int goldbags = 0;
			bool artifact = false;
			for ( node = map.entities->first; node != nullptr; node = node->next )
			{
				Entity* entity = (Entity*)node->element;
				if ( entity->sprite == 130 )   // gold bag
				{
					++goldbags;
				}
				if ( entity->sprite == 508 )
				{
					artifact = true;
				}
			}
			if ( goldbags >= 9 && artifact )
			{
				return;
			}
			my->flags[INVISIBLE] = false;
			my->flags[PASSABLE] = false;
			serverUpdateEntityFlag(my, INVISIBLE);
			serverUpdateEntityFlag(my, PASSABLE);
		}
		else
		{
			return;
		}
	}

	HEADSTONE_AMBIENCE--;
	if ( HEADSTONE_AMBIENCE <= 0 )
	{
		HEADSTONE_AMBIENCE = TICKS_PER_SECOND * 30;
		playSoundEntityLocal( my, 149, 32 );
	}

	if ( multiplayer == CLIENT )
	{
		return;
	}

	if ( !HEADSTONE_INIT )
	{
		HEADSTONE_INIT = 1;
		HEADSTONE_MESSAGE = rand();
		HEADSTONE_GHOUL = (rand() % 4 == 0);
	}

	bool shouldspawn = false;

	// rightclick message
	int i;
	if ( multiplayer != CLIENT )
	{
		for (i = 0; i < MAXPLAYERS; i++)
		{
			if ( (i == 0 && selectedEntity == my) || (client_selected[i] == my) )
			{
				if (inrange[i])
				{
					messagePlayer(i, language[485 + HEADSTONE_MESSAGE % 17]);
					if ( HEADSTONE_GHOUL && !HEADSTONE_FIRED )
					{
						shouldspawn = true;
						Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
						messagePlayerColor(i, color, language[502]);
					}
				}
			}
		}
	}

	// received on signal
	if ( my->skill[28] == 2 || shouldspawn )
	{
		if ( !HEADSTONE_FIRED )
		{
			HEADSTONE_FIRED = 1;

			// make a ghoul
			Entity* monster = summonMonster(GHOUL, my->x, my->y);
			if ( monster )
			{
				monster->z = 13;
				if ( currentlevel >= 15 || !strncmp(map.name, "The Haunted Castle", 18) )
				{
					Stat* tmpStats = monster->getStats();
					if ( tmpStats )
					{
						strcpy(tmpStats->name, "enslaved ghoul");
					}
				}
			}
		}
	}
}
Exemple #4
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;
			}
		}
	}
}
Exemple #5
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;
			}
		}
	}
}
void actMinotaurTimer(Entity* my)
{
	node_t* node;

	MINOTAURTIMER_LIFE++;
	if (( (currentlevel < 25 && MINOTAURTIMER_LIFE == TICKS_PER_SECOND * 120)
			|| (currentlevel >= 25 && MINOTAURTIMER_LIFE == TICKS_PER_SECOND * 180)
		)
		&& rand() % 5 == 0 )   // two minutes if currentlevel < 25, else 3 minutes.
	{
		int c;
		bool spawnedsomebody = false;
		for ( c = 0; c < 9; c++ )
		{
			Uint32 zapLeaderUid = 0;
			Entity* monster = summonMonster(HUMAN, my->x, my->y);
			if ( monster )
			{
				monster->skill[29] = 1; // so we spawn a zap brigadier
				spawnedsomebody = true;
				if ( !zapLeaderUid )
				{
					zapLeaderUid = monster->getUID();
				}
				else
				{
					Stat* monsterStats = monster->getStats();
					monsterStats->leader_uid = zapLeaderUid;
				}
			}
		}

		if ( spawnedsomebody )
		{
#ifdef MUSIC
			fadein_increment = default_fadein_increment * 20;
			fadeout_increment = default_fadeout_increment * 5;
			playmusic( sounds[175], false, true, false);
#endif
			for ( c = 0; c < MAXPLAYERS; c++ )
			{
				Uint32 color = SDL_MapRGB(mainsurface->format, 0, 255, 255);
				if ( stats[c]->type == HUMAN )
				{
					messagePlayerColor(c, color, language[1114], stats[c]->name);
				}
				else
				{
					messagePlayerColor(c, color, language[3285]);
				}
			}
		}
	}
	else if (( (currentlevel < 25 && MINOTAURTIMER_LIFE >= TICKS_PER_SECOND * 150)
					|| (currentlevel >= 25 && MINOTAURTIMER_LIFE >= TICKS_PER_SECOND * 210)
				)
		&& !MINOTAURTIMER_ACTIVE )     // two and a half minutes if currentlevel < 25, else 3.5 minutes
	{
		Entity* monster = summonMonster(MINOTAUR, my->x, my->y);
		if ( monster )
		{
			int c;
			for ( c = 0; c < MAXPLAYERS; c++ )
			{
				playSoundPlayer( c, 107 + rand() % 3, 128 );
				Uint32 color = SDL_MapRGB(mainsurface->format, 255, 128, 0);
				messagePlayerColor(c, color, language[1115]);
			}
			MINOTAURTIMER_ACTIVE = MINOTAURTIMER_LIFE;
		}
	}
	if ( MINOTAURTIMER_ACTIVE && MINOTAURTIMER_LIFE >= MINOTAURTIMER_ACTIVE + TICKS_PER_SECOND * 3 )
	{
		int c;
		for ( c = 0; c < MAXPLAYERS; c++ )
		{
			if ( currentlevel < 25 )
			{
				playSoundPlayer(c, 120 + rand() % 3, 128);
				Uint32 color = SDL_MapRGB(mainsurface->format, 255, 0, 255);
				messagePlayerColor(c, color, language[1116]);
				messagePlayerColor(c, color, language[73]);
			}
			else
			{
				playSoundPlayer(c, 375, 128);
				playSoundPlayer(c, 379, 128);
				messagePlayerColor(c, uint32ColorOrange(*mainsurface), language[1116]);
				messagePlayerColor(c, uint32ColorOrange(*mainsurface), language[73]);
				messagePlayerColor(c, uint32ColorBaronyBlue(*mainsurface), language[73]);
			}
		}
		list_RemoveNode(my->mynode);
		return;
	}
}
Exemple #7
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;
}
Exemple #8
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;
}