Пример #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;
}
void readNextDistance(I2cBusConnection* i2cBusConnection) {
    if (!readNextDistanceFlag) {
        return;
    }
    readNextDistanceFlag = false;

    unsigned int distance = getSRF02DistanceEndRanging(i2cBusConnection, SONAR_INDEX);
    delaymSec(1);
    startSRF02Ranging(i2cBusConnection, SONAR_INDEX);
    distances[(unsigned int) distanceIndex] = distance;

    /*
    appendDec(getDebugOutputStreamLogger(), distance);
    append(getDebugOutputStreamLogger(), '.');
     */

    // Manage index of history
    distanceIndex++;
    if (distanceIndex > ROBOT_SONAR_DETECTOR_DEVICE_HISTORY_SIZE) {
        distanceIndex = 0;
    }

    if (checkObstacle()) {
        // for the main LOOP
        obstacle = true;
    }
}
Пример #3
0
 RobotPosition PledgeAlgorithm::getNextPosition(const RobotPosition p_pos)
 {
     int x = (int) meterToCm(p_pos.point.x);
     int y = (int) meterToCm(p_pos.point.y);
     float theta = p_pos.theta;
     bool obstacle = false;
     bool leftSideObstacle = false;
     RobotPosition newPosition;
     
     
     if(turn == 0)
     {
         if(!obstacle)
         {
             newPosition = calculateNewPosition(x, y, theta);
             return newPosition;
         }
         else
         {
             obstacleFound = true;
             while(obstacle) // evtl sackgasse
             {
                 theta -= M_PI/2;
                 turn--;
                 
                 obstacle = checkObstacle(x, y, theta);
             }
             newPosition = calculateNewPosition(x, y, theta);
             return newPosition;
         }
     }
     
     if(turn != 0)
     {
         leftSideObstacle = checkLeftSideObstacle(x, y, theta);
         
         if(leftSideObstacle)
         {
             newPosition = calculateNewPosition(x, y, theta);
             return newPosition;
         }
         else
         {
             theta += M_PI/2; //drehung nach links?
             turn++;
             newPosition = calculateNewPosition(x, y, theta);
             return newPosition;
         }
     }
 }
Пример #4
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;
}
Пример #5
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;
					}
				}
			}
		}
	}
Пример #6
0
void initShopkeeper(Entity *my, stat_t *myStats) {
	int c;
	node_t *node;

	my->sprite = 217;
	//my->flags[GENIUS]=TRUE;
	my->flags[UPDATENEEDED]=TRUE;
	my->flags[BLOCKSIGHT]=TRUE;
	my->flags[INVISIBLE]=FALSE;
	
	if( multiplayer!=CLIENT ) {
		MONSTER_SPOTSND = -1;
		MONSTER_SPOTVAR = 1;
		MONSTER_IDLESND = -1;
		MONSTER_IDLEVAR = 1;
	}
	if( multiplayer!=CLIENT && !MONSTER_INIT ) {
		if( myStats ) {
			for( c=0; c<std::max(NUMPROFICIENCIES,NUMEFFECTS); c++ ) {
				if( c<NUMPROFICIENCIES )
					myStats->PROFICIENCIES[c]=0;
				if( c<NUMEFFECTS ) {
					myStats->EFFECTS[c]=FALSE;
					myStats->EFFECTS_TIMERS[c]=0;
				}
			}
		}
		
		int x, y;
		MONSTER_SHOPXS = my->x/16;
		MONSTER_SHOPXE = my->x/16;
		MONSTER_SHOPYS = my->y/16;
		MONSTER_SHOPYE = my->y/16;
		for( x=my->x; x>=0; x-=16 ) {
			if( !checkObstacle(x,my->y,my,NULL) )
				MONSTER_SHOPXS = x;
			else
				break;
		}
		for( x=my->x; x<map.width<<4; x+=16 ) {
			if( !checkObstacle(x,my->y,my,NULL) )
				MONSTER_SHOPXE = x;
			else
				break;
		}
		for( y=my->y; y>=0; y-=16 ) {
			if( !checkObstacle(my->x,y,my,NULL) )
				MONSTER_SHOPYS = y;
			else
				break;
		}
		for( y=my->y; y<map.height<<4; y+=16 ) {
			if( !checkObstacle(my->x,y,my,NULL) )
				MONSTER_SHOPYE = y;
			else
				break;
		}
		for( x=MONSTER_SHOPXS-16; x<=MONSTER_SHOPXE+16; x+=16 ) {
			for( y=MONSTER_SHOPYS-16; y<=MONSTER_SHOPYE+16; y+=16 ) {
				if( x/16>=0 && x/16<map.width && y/16>=0 && y/16<map.height )
					shoparea[y/16+(x/16)*map.height] = TRUE;
			}
		}

		myStats->sex = MALE;
		myStats->appearance = rand();
		strcpy(myStats->name,language[158+rand()%26]);
		myStats->inventory.first = NULL;
		myStats->inventory.last = NULL;
		myStats->HP = 300; myStats->MAXHP = 300;
		myStats->MP = 200; myStats->MAXMP = 200;
		myStats->OLDHP = myStats->HP;
		myStats->STR = 10;
		myStats->DEX = 4;
		myStats->CON = 10;
		myStats->INT = 7;
		myStats->PER = 7;
		myStats->CHR = 3+rand()%4;
		myStats->EXP = 0;
		myStats->LVL = 10;
		myStats->GOLD = 300+rand()%200;
		myStats->HUNGER = 900;
		if( !myStats->leader_uid )
			myStats->leader_uid = 0;
		myStats->FOLLOWERS.first=NULL; myStats->FOLLOWERS.last=NULL;
		myStats->PROFICIENCIES[PRO_MAGIC]=50;
		myStats->PROFICIENCIES[PRO_SPELLCASTING]=50;
		myStats->PROFICIENCIES[PRO_TRADING]=75;
		myStats->PROFICIENCIES[PRO_APPRAISAL]=75;
		myStats->helmet = NULL;
		myStats->breastplate = NULL;
		myStats->gloves = NULL;
		myStats->shoes = NULL;
		myStats->shield = NULL;
		myStats->weapon = NULL;
		myStats->cloak = NULL;
		myStats->amulet = NULL;
		myStats->ring = NULL;
		myStats->mask = NULL;
		myStats->weapon = newItem(SPELLBOOK_MAGICMISSILE,EXCELLENT,0,1,0,FALSE,NULL);

		if( rand()%20==0 ) {
			myStats->EFFECTS[EFF_ASLEEP] = TRUE;
			myStats->EFFECTS_TIMERS[EFF_ASLEEP] = 1800+rand()%3600;
		}
	
		// give shopkeeper items
		MONSTER_STORETYPE = rand()%9;
		if( MONSTER_STORETYPE==8 )
			MONSTER_STORETYPE++;
		int numitems = 10+rand()%5;
		switch( MONSTER_STORETYPE ) {
			case 0:
				// arms & armor store
				for( c=0; c<numitems; c++ ) {
					if( rand()%2 ) {
						newItem( static_cast<ItemType>(rand()%20), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%4, rand(), FALSE, &myStats->inventory );
					} else {
						int i=rand()%21;
						if( i<18 )
							newItem( static_cast<ItemType>(GLOVES+i), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%4, rand(), FALSE, &myStats->inventory );
						else
							newItem( static_cast<ItemType>(GLOVES+i+4), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%6, rand(), FALSE, &myStats->inventory );
					}
				}
				break;
			case 1:
				// hat store
				for( c=0; c<numitems; c++ ) {
					newItem( static_cast<ItemType>(HAT_PHRYGIAN+rand()%7), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%6, rand(), FALSE, &myStats->inventory );
				}
				break;
			case 2:
				// jewelry store
				for( c=0; c<numitems; c++ ) {
					switch( rand()%3 ) {
						case 0:
							newItem( static_cast<ItemType>(AMULET_SEXCHANGE+rand()%6), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), FALSE, &myStats->inventory );
							break;
						case 1:
							newItem( static_cast<ItemType>(RING_ADORNMENT+rand()%12), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), FALSE, &myStats->inventory );
							break;
						case 2:
							newItem( static_cast<ItemType>(GEM_GARNET+rand()%16), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), FALSE, &myStats->inventory );
							break;
					}
				}
				break;
			case 3:
				// bookstore
				for( c=0; c<numitems; c++ ) {
					switch( rand()%3 ) {
						case 0:
							newItem( static_cast<ItemType>(SPELLBOOK_FORCEBOLT+rand()%22), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), TRUE, &myStats->inventory );
							break;
						case 1:
							newItem( static_cast<ItemType>(SCROLL_MAIL+rand()%14), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%2, rand(), TRUE, &myStats->inventory );
							break;
						case 2:
							newItem( READABLE_BOOK, static_cast<Status>(WORN+rand()%3), 0, 1+rand()%3, rand(), FALSE, &myStats->inventory );
							break;
					}
				}
				break;
			case 4:
				// apothecary
				for( c=0; c<numitems; c++ ) {
					newItem( static_cast<ItemType>(POTION_WATER+rand()%15), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%5, rand(), TRUE, &myStats->inventory );
				}
				break;
			case 5:
				// staff shop
				for( c=0; c<numitems; c++ ) {
					newItem( static_cast<ItemType>(MAGICSTAFF_LIGHT+rand()%10), static_cast<Status>(WORN+rand()%3), 0, 1, 1, TRUE, &myStats->inventory );
				}
				break;
			case 6:
				// food store
				for( c=0; c<numitems; c++ ) {
					newItem( static_cast<ItemType>(FOOD_BREAD+rand()%7), static_cast<Status>(SERVICABLE+rand()%2), 0, 1+rand()%3, rand(), FALSE, &myStats->inventory );
				}
				break;
			case 7:
				// hardware store
				for( c=0; c<numitems; c++ ) {
					newItem( static_cast<ItemType>(TOOL_PICKAXE+rand()%11), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%3, rand(), FALSE, &myStats->inventory );
				}
				break;
			case 8:
				// lighting store
				for( c=0; c<numitems; c++ ) {
					newItem( static_cast<ItemType>(TOOL_TORCH+rand()%2), EXCELLENT, 0, 1, 7, FALSE, &myStats->inventory );
				}
				break;
			case 9:
				// general store
				for( c=0; c<numitems; c++ ) {
					newItem( static_cast<ItemType>(rand()%(NUMITEMS-(NUMITEMS-SPELL_ITEM))), static_cast<Status>(WORN+rand()%3), 0, 1+rand()%3, rand(), FALSE, &myStats->inventory );
				}
				break;
		}
	}

	// torso
	Entity *entity = newEntity(218, 0, map.entities);
	entity->sizex = 4;
	entity->sizey = 4;
	entity->skill[2] = my->uid;
	entity->flags[PASSABLE]=TRUE;
	entity->flags[NOUPDATE]=TRUE;
	entity->flags[USERFLAG2]=my->flags[USERFLAG2];
	entity->focalx = limbs[SHOPKEEPER][1][0]; // 0
	entity->focaly = limbs[SHOPKEEPER][1][1]; // 0
	entity->focalz = limbs[SHOPKEEPER][1][2]; // 0
	entity->behavior=&actShopkeeperLimb;
	entity->parent=my->uid;
	node = list_AddNodeLast(&my->children);
	node->element = entity;
	node->deconstructor = &emptyDeconstructor;
	node->size = sizeof(Entity *);

	// right leg
	entity = newEntity(222, 0, map.entities);
	entity->sizex = 4;
	entity->sizey = 4;
	entity->skill[2] = my->uid;
	entity->flags[PASSABLE]=TRUE;
	entity->flags[NOUPDATE]=TRUE;
	entity->flags[USERFLAG2]=my->flags[USERFLAG2];
	entity->focalx = limbs[SHOPKEEPER][2][0]; // 0
	entity->focaly = limbs[SHOPKEEPER][2][1]; // 0
	entity->focalz = limbs[SHOPKEEPER][2][2]; // 2
	entity->behavior=&actShopkeeperLimb;
	entity->parent=my->uid;
	node = list_AddNodeLast(&my->children);
	node->element = entity;
	node->deconstructor = &emptyDeconstructor;
	node->size = sizeof(Entity *);

	// left leg
	entity = newEntity(221, 0, map.entities);
	entity->sizex = 4;
	entity->sizey = 4;
	entity->skill[2] = my->uid;
	entity->flags[PASSABLE]=TRUE;
	entity->flags[NOUPDATE]=TRUE;
	entity->flags[USERFLAG2]=my->flags[USERFLAG2];
	entity->focalx = limbs[SHOPKEEPER][3][0]; // 0
	entity->focaly = limbs[SHOPKEEPER][3][1]; // 0
	entity->focalz = limbs[SHOPKEEPER][3][2]; // 2
	entity->behavior=&actShopkeeperLimb;
	entity->parent=my->uid;
	node = list_AddNodeLast(&my->children);
	node->element = entity;
	node->deconstructor = &emptyDeconstructor;
	node->size = sizeof(Entity *);

	// right arm
	entity = newEntity(220, 0, map.entities);
	entity->sizex = 4;
	entity->sizey = 4;
	entity->skill[2] = my->uid;
	entity->flags[PASSABLE]=TRUE;
	entity->flags[NOUPDATE]=TRUE;
	entity->flags[USERFLAG2]=my->flags[USERFLAG2];
	entity->focalx = limbs[SHOPKEEPER][4][0]; // 0
	entity->focaly = limbs[SHOPKEEPER][4][1]; // 0
	entity->focalz = limbs[SHOPKEEPER][4][2]; // 1.5
	entity->behavior=&actShopkeeperLimb;
	entity->parent=my->uid;
	node = list_AddNodeLast(&my->children);
	node->element = entity;
	node->deconstructor = &emptyDeconstructor;
	node->size = sizeof(Entity *);

	// left arm
	entity = newEntity(219, 0, map.entities);
	entity->sizex = 4;
	entity->sizey = 4;
	entity->skill[2] = my->uid;
	entity->flags[PASSABLE]=TRUE;
	entity->flags[NOUPDATE]=TRUE;
	entity->flags[USERFLAG2]=my->flags[USERFLAG2];
	entity->focalx = limbs[SHOPKEEPER][5][0]; // 0
	entity->focaly = limbs[SHOPKEEPER][5][1]; // 0
	entity->focalz = limbs[SHOPKEEPER][5][2]; // 1.5
	entity->behavior=&actShopkeeperLimb;
	entity->parent=my->uid;
	node = list_AddNodeLast(&my->children);
	node->element = entity;
	node->deconstructor = &emptyDeconstructor;
	node->size = sizeof(Entity *);
}
Node* AIManager::astar(Vector3f end, Vector3f begin)
{
    bool firstGo = true;
    Node* start = new Node(begin);
    Node* goal = new Node(end);
    Node* current;
    std::vector<Node*> openlist;
    std::vector<Node*> closelist;
    Vector3f goalvf = end;

    openlist.push_back(start);
    std::make_heap(openlist.begin(), openlist.end());

    while(!openlist.empty())
    {
        current = openlist.front();
        std::pop_heap(openlist.begin(), openlist.end());
        openlist.pop_back();
        if(isGoal(current, goal))
        {
            return current;
        }
    //    getSuccessors(current, openlist, closelist, end);
    //If adjacent position is not obstacle and not on closed
    //add adjacent positions to list
    Node* temp = new Node;
    bool valid = true;
    //if(!Overlay::isObstacle(current->_x+STEP, current->_y, current->_z))
    if(!checkObstacle(Vector3f(current->_x+STEP, current->_y, current->_z)))
    {
        temp->_x = current->_x+STEP;
        temp->_z = current->_z; 
        for(unsigned int i = 0; i < closelist.size() && valid; ++i)
        {
            if(temp->isSamePosition(closelist[i]))
                valid = false;
        }
        
        if(valid)
        {
            temp->_g = current->_g+GSCORE;
            temp->_h = calculateHn(Vector3f(float(temp->_x), float(temp->_y), float(temp->_z)), goalvf);
            temp->calculateFn();
            temp->setParent(current);
            openlist.push_back(temp);
            std::push_heap(openlist.begin(), openlist.end());
        }
    }
    //if(!Overlay::isObstacle(current->_x-STEP, current->_y, current->_z))
    if(!checkObstacle(Vector3f(current->_x-STEP, current->_y, current->_z)))
    {
        temp->_x = current->_x-STEP;
        temp->_z = current->_z; 
        for(unsigned int i = 0; i < closelist.size() && valid; ++i)
        {
            if(temp->isSamePosition(closelist[i]))
                valid = false;
        }
        if(valid)
        {
            temp->_g = current->_g+GSCORE;
            temp->_h = calculateHn(Vector3f(float(temp->_x), float(temp->_y), float(temp->_z)), goalvf);
            temp->calculateFn();
            temp->setParent(current);
            openlist.push_back(temp);
            std::push_heap(openlist.begin(), openlist.end());
        }
        valid = true;
    }
    //if(!Overlay::isObstacle(current->_x, current->_y, current->_z+STEP))
    if(!checkObstacle(Vector3f(current->_x, current->_y, current->_z+STEP)))
    {
        temp->_x = current->_x;
        temp->_z = current->_z+STEP; 
        for(unsigned int i = 0; i < closelist.size() && valid; ++i)
        {
            if(temp->isSamePosition(closelist[i]))
                valid = false;
        }
        if(valid)
        {
            temp->_g = current->_g+GSCORE;
            temp->_h = calculateHn(Vector3f(float(temp->_x), float(temp->_y), float(temp->_z)), goalvf);
            temp->calculateFn();
            temp->setParent(current);
            openlist.push_back(temp);
            std::push_heap(openlist.begin(), openlist.end());
        }
        valid = true;
    }
    //if(!Overlay::isObstacle(current->_x, current->_y, current->_z-STEP))
    if(!checkObstacle(Vector3f(current->_x, current->_y, current->_z-STEP)))
    {
        temp->_x = current->_x;
        temp->_z = current->_z-STEP; 
        for(unsigned int i = 0; i < closelist.size() && valid; ++i)
        {
            if(temp->isSamePosition(closelist[i]))
                valid = false;
        }
        if(valid)
        {
            temp->_g = current->_g+GSCORE;
            temp->_h = calculateHn(Vector3f(float(temp->_x), float(temp->_y), float(temp->_z)), goalvf);
            temp->calculateFn();
            temp->setParent(current);
            openlist.push_back(temp);
            std::push_heap(openlist.begin(), openlist.end());
        }
        valid = true;
    }
        if(firstGo && !openlist.empty())
        {
            std::make_heap(openlist.begin(), openlist.end());
            firstGo = false;
        }
        closelist.push_back(current);
        return current;
    }
    return NULL;

}
Пример #8
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;
}