Exemple #1
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;
			}
		}
	}
}
Exemple #2
0
//This is called when the switch is toggled by the player.
void Entity::toggleSwitch()
{
	//If off, power on and send poweron signal. If on, power off and send poweroff signal.

	switch_power = (switch_power == SWITCH_UNPOWERED);
	serverUpdateEntitySkill(this, 0);

	//(my->skill[0]) ? my->sprite = 171 : my->sprite = 168;

	list_t* neighbors = getPowerableNeighbors(); //Grab a list of all neighboring circuits and mechanisms.

	if (neighbors)
	{
		node_t* node = NULL;
		for (node = neighbors->first; node != NULL; node = node->next)
		{
			if (node->element)
			{
				Entity* powerable = (Entity*)(node->element);

				if (powerable)
				{
					if (powerable->behavior == actCircuit)
					{
						(switch_power) ? powerable->circuitPowerOn() : powerable->circuitPowerOff();
					}
					else if ( powerable->behavior == &::actSignalTimer )
					{
						int x1 = static_cast<int>(this->x / 16);
						int x2 = static_cast<int>(powerable->x / 16);
						int y1 = static_cast<int>(this->y / 16);
						int y2 = static_cast<int>(powerable->y / 16);
						//messagePlayer(0, "%d, %d, %d, %d", x1, x2, y1, y2);
						switch ( powerable->signalInputDirection )
						{
							case 0: // west
								if ( (x1 + 1) == x2 )
								{
									(switch_power) ? powerable->mechanismPowerOn() : powerable->mechanismPowerOff();
								}
								break;
							case 1: // south
								if ( (y1 - 1) == y2 )
								{
									(switch_power) ? powerable->mechanismPowerOn() : powerable->mechanismPowerOff();
								}
								break;
							case 2: // east
								if ( (x1 - 1) == x2 )
								{
									(switch_power) ? powerable->mechanismPowerOn() : powerable->mechanismPowerOff();
								}
								break;
							case 3: // north
								if ( (y1 + 1) == y2 )
								{
									(switch_power) ? powerable->mechanismPowerOn() : powerable->mechanismPowerOff();
								}
								break;
							default:
								break;
						}
					}
					else
					{
						(switch_power) ? powerable->mechanismPowerOn() : powerable->mechanismPowerOff();
					}
				}
			}
		}

		list_FreeAll(neighbors); //Free the list.
		free(neighbors);
	}
}
Exemple #3
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();
			}
		}
	}
}
Exemple #4
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;
	}
}
Exemple #5
0
void actCampfire(Entity *my) {
	Entity *entity;
	int i;
	
	// init
	if( !CAMPFIRE_INIT ) {
		CAMPFIRE_INIT = 1;
		CAMPFIRE_HEALTH = MAXPLAYERS;
	}
		
	// crackling sounds
	if( CAMPFIRE_HEALTH>0 ) {
		CAMPFIRE_SOUNDTIME--;
		if( CAMPFIRE_SOUNDTIME <= 0 ) {
			CAMPFIRE_SOUNDTIME = 480;
			playSoundEntityLocal( my, 133, 128 );
		}
	
		// spew flame particles
		for( i=0; i<3; i++ ) {
			entity = spawnFlame(my);
			entity->x += ((rand()%30)-10)/10.f;
			entity->y += ((rand()%30)-10)/10.f;
			entity->z -= 1;
		}
		entity = spawnFlame(my);
		entity->z -= 2;
	
		// light environment
		if( !CAMPFIRE_LIGHTING ) {
			my->light = lightSphereShadow(my->x/16, my->y/16, 6, 160);
			CAMPFIRE_LIGHTING=1;
		}
		CAMPFIRE_FLICKER--;
		if(CAMPFIRE_FLICKER<=0) {
			CAMPFIRE_LIGHTING=(CAMPFIRE_LIGHTING==1)+1;
		
			if(CAMPFIRE_LIGHTING==1) {
				if( my->light != NULL )
					list_RemoveNode(my->light->node);
				my->light = lightSphereShadow(my->x/16, my->y/16, 6, 160);
			}
			else {
				if( my->light != NULL )
					list_RemoveNode(my->light->node);
				my->light = lightSphereShadow(my->x/16, my->y/16, 6, 152);
			}
			CAMPFIRE_FLICKER=2+rand()%7;
		}
	} else {
		if( my->light )
			if( my->light->node )
				list_RemoveNode(my->light->node);
		my->light = NULL;
		my->flags[BRIGHT] = FALSE;
	}

	if( multiplayer != CLIENT ) {
		// using campfire
		for(i=0;i<MAXPLAYERS;i++) {
			if( (i==0 && selectedEntity==my) || (client_selected[i]==my) ) {
				if(inrange[i]) {
					if( CAMPFIRE_HEALTH>0 ) {
						messagePlayer(i,language[457]);
						CAMPFIRE_HEALTH--;
						if( CAMPFIRE_HEALTH<=0 ) {
							serverUpdateEntitySkill(my,3); // extinguish for all clients
							messagePlayer(i,language[458]);
							if( my->light )
								if( my->light->node )
									list_RemoveNode(my->light->node);
							my->light = NULL;
						}
						Item *item = newItem(TOOL_TORCH,WORN,0,1,0,TRUE,NULL);
						itemPickup(i,item);
						free(item);
					} else {
						messagePlayer(i,language[458]);
					}
				}
			}
		}
	}
}
Exemple #6
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;
}