Beispiel #1
0
void Minimap::update(float dTime)
{
	Player* player = GET_STAGE_MANAGER()->getPlayer();
	if (player == nullptr)
	{
		return;
	}
	int currentRoom = GET_STAGE_MANAGER()->getCurStageNum();
	Point playerPosition = player->getPosition();
	Vec2 playerRoomOrigin = GET_STAGE_MANAGER()->positionToIdxOfFloor(playerPosition);
	Sprite* sprMM = (Sprite*)this->getChildByTag(MINIMAP);
	Sprite* sprMMPlayerPosition = (Sprite*)sprMM->getChildByTag(MINIMAP_PLAYER);
	sprMMPlayerPosition->removeChildByTag(MINIMAP_BGRECT);
	m_MMBgRect = createBgRect(MINIMAP_SCALE);
	sprMMPlayerPosition->addChild(m_MMBgRect, -10, MINIMAP_BGRECT);
	drawRoomRect(m_MMBgRect, MINIMAP_SCALE);
	m_MMBgRect->setPosition(Point(-1 * (playerRoomOrigin.x * MINIMAP_SCALE + 6), -1 * (playerRoomOrigin.y * MINIMAP_SCALE + 6)));
}
Beispiel #2
0
/* NOTE: this must be kept somewhat aligned with
 * AIPlayStates::actOnRestart to prevent blocking */
bool MatchHelpers::playerPositionedForRestart(const Player& restarter, const Player& p)
{
	switch(p.getMatch()->getPlayState()) {
		case PlayState::OutKickoff:
			return &p == &restarter || onOwnSideAndReady(p);

		case PlayState::OutThrowin:
		case PlayState::OutCornerkick:
		case PlayState::OutIndirectFreekick:
		case PlayState::OutDirectFreekick:
		case PlayState::OutDroppedball:
			/* TODO: move this magic constant */
			return !isOpposingPlayer(restarter, p) ||
				MatchEntity::distanceBetween(*p.getMatch()->getBall(), p) > 9.15f;

		case PlayState::OutPenaltykick:
			{
				bool nearball = MatchEntity::distanceBetween(*p.getMatch()->getBall(), p) < 9.15f;
				bool inpenaltyarea = (isOpposingPlayer(restarter, p) && inOwnPenaltyArea(p)) ||
					(!isOpposingPlayer(restarter, p) && inOpposingPenaltyArea(p));
				bool isrestarter = &p == &restarter;
				bool isgoalie = isOpposingPlayer(restarter, p) && p.isGoalkeeper();
				bool nearowngoalline = fabs(p.getPosition().y - MatchHelpers::ownGoalPosition(p).y) < 0.5f;

				if(isrestarter) {
					return nearball;
				}
				else if(isgoalie) {
					return nearowngoalline; 
				}
				else {
					return !nearball && !inpenaltyarea;
				}
			}

		case PlayState::OutGoalkick:
			return !isOpposingPlayer(restarter, p) ||
				!inOpposingPenaltyArea(p);

		case PlayState::InPlay:
			return true;
	}
	return true;
}
Player * Environment::getNearestConnectedPlayer(v3f pos)
{
	core::list<Player*> connected_players = getPlayers(true);
	f32 nearest_d = 0;
	Player *nearest_player = NULL;
	for(core::list<Player*>::Iterator
			i = connected_players.begin();
			i != connected_players.end(); i++)
	{
		Player *player = *i;
		f32 d = player->getPosition().getDistanceFrom(pos);
		if(d < nearest_d || nearest_player == NULL)
		{
			nearest_d = d;
			nearest_player = player;
		}
	}
	return nearest_player;
}
Beispiel #4
0
void PlayerManager::ConvertPlayer2Package(Player& player,GamePackage_Player& pack_player)
{
	pack_player.set_userid(player.GetID());
	pack_player.set_speed(player.GetSpeed());
	pack_player.set_direction(player.GetDirection());
	pack_player.set_destpointx(player.GetDestPoint().x);
	pack_player.set_destpointy(player.GetDestPoint().y);
	pack_player.set_currentpointx(player.getPosition().x);
	pack_player.set_currentpointy(player.getPosition().y);
	pack_player.set_msgcode(player.GetMsg());

	pack_player.set_bloodvalue(player.GetBloodValue());
	pack_player.set_maxbloodvalue(player.GetMaxBloodValue());
	pack_player.set_magicvalue(player.GetMagicValue());
	pack_player.set_maxmagicvalue(player.GetMaxMagicValue());
	pack_player.set_empiricalvalue(player.GetEmpiricalValue());
	pack_player.set_maxempiricalvalue(player.GetMaxEmpiricalValue());
	pack_player.set_level(player.GetLevel());
	pack_player.set_damagevalue(player.GetDamageValue());
	//pack_player.set_skill(player.GetCurrentSkill()->GetSkillID());
}
Beispiel #5
0
bool MatchHelpers::canGrabBall(const Player& p)
{
	const Ball* b = p.getMatch()->getBall();
	if(grabBallAllowed(p)) {
		if(canKickBall(p))
			return true;

		float distToBall = MatchEntity::distanceBetween(p, *b);
		float maxDist = p.standing() ? 0.5f : 0.0f;
		float gk = p.getSkills().GoalKeeping;
		maxDist += sqrt(gk);
		float ballHeight = b->getPosition().z;
		float maxBallHeight = p.isAirborne() ? p.getPosition().z + 2.0f : p.standing() ? 2.0f : 0.5f;
		float minBallHeight = p.isAirborne() ? p.getPosition().z - (0.7f * gk) : 0.0f;
		if(maxDist >= distToBall && maxBallHeight >= ballHeight && minBallHeight <= ballHeight) {
			return true;
		}
	}

	return false;
}
Beispiel #6
0
void SoundEngine::punch(int playerId) {
	Player* player = dynamic_cast<Player*>(Globals::gameObjects.playerMap[playerId]);
	FMOD::Channel* channel = punchChannels[playerId];

	glm::vec3 pos = player->getPosition();
	FMOD_VECTOR position = { pos.x, pos.y, pos.z };

	if (channel) {
		bool playing = false;
		channel->isPlaying(&playing);
		if (playing) {
			channel->set3DAttributes(&position, 0);
			return;
		}
	}

	result_ = system_->playSound(punchSound_, 0, true, &channel);
	punchChannels[playerId] = channel;
	result_ = channel->set3DAttributes(&position, 0);
	result_ = channel->setPaused(false);
}
Beispiel #7
0
void Enemy::update(uint32_t milliseconds)
{
    // Update the enemy position according the Trajectory
    if (mTrajectory != nullptr) {
        mTrajectory->update(milliseconds);
        mTrajectory->GetPosition(mPosition);
    }

    // Check for firing missles
    lastShootDuration += milliseconds;
    if (lastShootDuration >= ENEMY_SHOOT_TIME_MILLISEC) {
        lastShootDuration = 0;
        Player * player = SpriteManager::GetInstance()->getET();
        float_t velX = (player->getPosition()->x - (mPosition.x));
        float_t velY = (player->getPosition()->y - (mPosition.y));
        float_t length = (float_t) sqrt(velY * velY + velX * velX);
        velY *= SHOT_FORCE / length;
        velX *= SHOT_FORCE / length;
        SpriteManager::GetInstance()->CreateBullet(mPosition.x, mPosition.y, velX, velY, SpriteManager::ENEMY_GREEN);
    }
}
Beispiel #8
0
bool Commands::createItemById(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	std::string tmp = param;

	std::string::size_type pos = tmp.find(' ', 0);
	if(pos == std::string::npos){
		pos = tmp.size();
	}

	int32_t type = atoi(tmp.substr(0, pos).c_str());
	int32_t count = 1;
	if(pos < tmp.size()){
		tmp.erase(0, pos+1);
		count = std::max(0, std::min(atoi(tmp.c_str()), 100));
	}

	Item* newItem = Item::CreateItem(type, count);
	if(!newItem){
		return false;
    }
    g_game.startDecay(newItem);

	ReturnValue ret = g_game.internalAddItem(player, newItem);

	if(ret != RET_NOERROR){
		ret = g_game.internalAddItem(player->getTile(), newItem, INDEX_WHEREEVER, FLAG_NOLIMIT);

		if(ret != RET_NOERROR){
			delete newItem;
			return false;
		}
	}

	g_game.addMagicEffect(player->getPosition(), NM_ME_MAGIC_POISON);
	return true;
}
void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
		std::vector<u16> *far_players, float far_d_nodes,
		bool remove_metadata)
{
	float maxd = far_d_nodes*BS;
	v3f p_f = intToFloat(p, BS);

	std::vector<u16> clients = m_clients.getClientIDs();
	for(auto
				i = clients.begin();
		i != clients.end(); ++i)
	{

		if(far_players) {
			// Get player
			Player *player = m_env->getPlayer(*i);
			if(player)
			{
				// If player is far away, only set modified blocks not sent
				v3f player_pos = player->getPosition();
				if(player_pos.getDistanceFrom(p_f) > maxd) {
					far_players->push_back(*i);
					continue;
				}
			}
		}
		SharedBuffer<u8> reply(0);
		RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
		if (client != 0)
		{
			// Create packet
			MSGPACK_PACKET_INIT(TOCLIENT_ADDNODE, 3);
			PACK(TOCLIENT_ADDNODE_POS, p);
			PACK(TOCLIENT_ADDNODE_NODE, n);
			PACK(TOCLIENT_ADDNODE_REMOVE_METADATA, remove_metadata);

			m_clients.send(*i, 0, buffer, true);
		}
	}
}
void MeteorSpawner::spawn(Player &p)
{
	int n = 1; // number of meteors to spawn

	if (canSpawn())
	{
		POINT start;
		POINT end;
		int velocity;

		for (int i = index; i < (n + index); i++)
		{
			i = i % MAX_METEORS;

			if (meteors[i].isAlive()) // don't overwrite existing meteors
				continue;

			start.x = rand() % (B_WIDTH + 80) - 40;
			start.y = -50;
			end.x = p.getPosition().x + ((rand() % 200) - 100);
			end.y = B_HEIGHT;

			if (start.x == end.x) // TODO: handle undefined slopes
			{
				end.x++;
			}

			meteors[i] = Meteor(start, end);
		}

		index = (index + n) % MAX_METEORS;
		ticks = 0; // reset
	}
	else
	{
		ticks++;
		if (delay != 0)
			delay--;
	}
}
Beispiel #11
0
/************************************************************************
*  玩家经验值改变
************************************************************************/
bool Controller::CheckPlayerIsInPortal()
{
	Player* myPlayer = GetMyPlayer();//GetPlayerManager()->GetPlayer(m_strMyPlayerID);
	Point playerPosition = myPlayer->getPosition();
	if (GetCurrentChapter() != CHAPTER_4 && Game()->GetPathManager()->IsInRect(Game()->GetSkillManager()->GetPortalAnimation()->GetScope(),playerPosition))
	{
		if (GetCurrentChapter() == CHAPTER_1)
		{
			ChangeChapter(CHAPTER_2);
		}
		else if (GetCurrentChapter() == CHAPTER_2)
		{
			ChangeChapter(CHAPTER_3);
		}
		else if (GetCurrentChapter() == CHAPTER_3)
		{
			ChangeChapter(CHAPTER_4);
		}
		return true;
	}
	return false;
}
Beispiel #12
0
bool House::kickPlayer(Player* player, const std::string& name)
{
	Player* kickingPlayer = g_game.getPlayerByName(name);
	if(kickingPlayer)
	{
		HouseTile* houseTile = dynamic_cast<HouseTile*>(kickingPlayer->getTile());
		if(houseTile && houseTile->getHouse() == this)
		{
			if(getHouseAccessLevel(player) >= getHouseAccessLevel(kickingPlayer) && !kickingPlayer->hasFlag(PlayerFlag_CanEditHouses))
			{
				Position oldPosition = kickingPlayer->getPosition();
				if(g_game.internalTeleport(kickingPlayer, getEntryPosition()) == RET_NOERROR)
				{
					g_game.addMagicEffect(oldPosition, NM_ME_POFF);
					g_game.addMagicEffect(getEntryPosition(), NM_ME_TELEPORT);
				}
				return true;
			}
		}
	}
	return false;
}
Beispiel #13
0
void Window::updatePlayers()
{
	Game* g = Game::instance();
	Player *p = Game::getPuckHolder();
	Player *h = g->getHomeTeamPlayers(), *a = g->getAwayTeamPlayers();

	// Get positions of the green players
	Math::Vector2D<double> greenPos = h->getPosition();

	// Get positions of the blue players
	Math::Vector2D<double> bluePos = a->getPosition();
	
	// Set up new positions
	blueRect.x = floor(bluePos.x) - withPuck.w/2; blueRect.y = floor(bluePos.y) - withPuck.h/2;
	blueNameRect.x = blueRect.x; blueNameRect.y = withPuck.h + blueRect.y;
	greenRect.x = floor(greenPos.x) - withPuck.w/2; greenRect.y = floor(greenPos.y) - withPuck.h/2;
	greenNameRect.x = greenRect.x; greenNameRect.y = withPuck.h + greenRect.y;

	// Blit surfaces
	if (p == h)
	{
		SDL_BlitSurface(greenPlayer, &withPuck, mainSurface, &greenRect);
		SDL_BlitSurface(bluePlayer, &withoutPuck, mainSurface, &blueRect);
	}
	else if (p == a)
	{
		SDL_BlitSurface(greenPlayer, &withoutPuck, mainSurface, &greenRect);
		SDL_BlitSurface(bluePlayer, &withPuck, mainSurface, &blueRect);
	}
	else
	{
		SDL_BlitSurface(greenPlayer, &withoutPuck, mainSurface, &greenRect);
		SDL_BlitSurface(bluePlayer, &withoutPuck, mainSurface, &blueRect);
	}

	// Render the player names
	drawText(&blueNameRect, nameFont, a->getName().c_str());
	drawText(&greenNameRect, nameFont, h->getName().c_str());
}
Beispiel #14
0
void HomingMissile::acquireTarget(void)
{
    int best_target = -1;
    float best_dist = 10000;

    for(Server::Entpool::iterator ii=server->entities.begin(); ii!=server->entities.end(); ii++)
    {
        if(!ii->second->isPlayer())
            continue;
        Player *ent = (Player*)ii->second;
        float dist = (ent->getPosition().positionVector() - targetPos).getMagnitude();
        if(dist > best_dist)
            continue;

        if(ent->shouldDelete() || !ent->canCollideWith(this))
            continue;
        if(ent->getTeam() == ownerTeam && ownerTeam != team_free)
            continue;

        best_target = ent->getEntId();
        best_dist = dist;
    }
    target = best_target;
}
Beispiel #15
0
void InputSystem::update(float delta)
{
    if(!mouseControl)
        return;

    Player *player = game->getPlayer();
    if(!player)
        return;

    // Compute the view position.
    Vector2 viewPosition = game->getRenderer()->windowToView(mouseX, mouseY);
    float dir = viewPosition.x - player->getPosition().x;

    // Compute the new velocity.
    const float DirectionMargin = 0.5f;
    Vector2 velocity = player->getVelocity();
    if(dir > DirectionMargin)
        velocity.x = PlayerSpeed;
    else if(dir < -DirectionMargin)
        velocity.x = -PlayerSpeed;
    else
        velocity.x = 0.0f;
    player->setVelocity(velocity);
}
Beispiel #16
0
std::vector<std::vector<Phase>> initializeBossPhases(World &world, Boss &boss)
{
    std::vector<std::vector<Phase>> data(Boss::TypeCount);

    // Welcome to one of the most un-readable code I've ever made :

    // Boss1 Phase1
    Phase b1p1(world, boss, sf::seconds(5.f));
    b1p1.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time){
        Player* player = world.getPlayerEntity();
        //world.shakeCameraFor(0.3f);
        boss.unsensible();
        if((b.getPosition().x-player->getPosition().x) > 40) {
            boss.move(Entity::Left);
        } else if((b.getPosition().x-player->getPosition().x) < 40) {
            boss.move(Entity::Right);
        } else {
            //boss.knock();
        }
    });
    data[Boss::Boss1].push_back(b1p1);
    // Boss1 Phase2
    Phase b1p2(world, boss, sf::seconds(3.f));
    b1p2.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time){
        b.sensible();
    });
    data[Boss::Boss1].push_back(b1p2);
    // Boss1 Phase3
    Phase b1p3(world, boss, sf::seconds(1.f));
    b1p3.addSkill(sf::seconds(0.9f), [&](Boss& b, sf::Time dt){
        if(randomInt(0,5) == 1) world.addMedkit(sf::Vector2f(randomFloat(10, 1270), 20));
    });
    data[Boss::Boss1].push_back(b1p3);
    // Boss1 Phase4
    Phase b1p4(world, boss, sf::seconds(1.f));
    b1p4.addSkill(sf::seconds(0.9f), [&](Boss& b, sf::Time dt){
        Player* player = world.getPlayerEntity();
        auto pos = player->getPosition();
        //world.addZombie(sf::Vector2f(pos.x, 100.f));
        //world.addZombie(sf::Vector2f(pos.x+50.f, 100.f));
        world.addZombie(sf::Vector2f(randomFloat(10, 1270), 100.f));
        b.playLocalSound(world.getCommandQueue(), Sounds::Boss1AddPop);
    });
    data[Boss::Boss1].push_back(b1p4);

    //////////////////////////////////////////////

    /*// Boss2 Phase2
    Phase b2p2(world, boss, sf::seconds(2.f));
    b2p2.addSkill(sf::seconds(0.90f), [&](Boss&, sf::Time){
    });
    data[Entity::Boss2].push_back(b2p2);
    // Boss2 Phase1
    Phase b2p1(world, boss, sf::seconds(1.2f));
    b2p1.addSkill(sf::seconds(0.5f), [&](Boss& b, sf::Time){
        PlayerEntity* player = world.player();
        if((b.getPosition().x-player->getPosition().x) > 0) {
            world.addCreature(2, 50.f);
        } else {
            world.addCreature(2, -50.f);
        }
    });
    data[Entity::Boss2].push_back(b2p1);
    // Boss2 Phase2
    data[Entity::Boss2].push_back(b2p2);
    data[Entity::Boss2].push_back(b2p1);
    data[Entity::Boss2].push_back(b2p2);
    data[Entity::Boss2].push_back(b2p1);
    // Boss1 Phase4
    Phase b2p3(world, boss, sf::seconds(0.f));
    b2p3.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time dt){
        PlayerEntity* player = world.player();
        if(b.getPosition().x < 512) {
            for(unsigned int i = 0; i < 5; ++i)
            {
                world.addCreature(2, 50.f + i*32.f);
            }
            world.addCreature(1, 380.f);
        } else {
            for(unsigned int i = 0; i < 5; ++i)
            {
                world.addCreature(2, -50.f - i*32.f);
            }
            world.addCreature(1, -380.f);
        }
    });
    data[Entity::Boss2].push_back(b2p3);
    // Boss2 Phase4
    Phase b2p4(world, boss, sf::seconds(4.f));
    b2p4.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time){
        PlayerEntity* player = world.player();
        if((b.getPosition().x-player->getPosition().x) > 0) {
            boss.move(Entity::Left);
        } else {
            boss.move(Entity::Right);
        }
    });
    data[Entity::Boss2].push_back(b2p4);
    // Boss2 Phase5
    Phase b2p5(world, boss, sf::seconds(2.f));
    b2p5.addSkill(sf::seconds(0.90f), [&](Boss& b, sf::Time){
        b.knock();
    });
    data[Entity::Boss2].push_back(b2p5);
    // Boss2 Phase6
    Phase b2p6(world, boss, sf::seconds(0.0f));
    b2p6.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time){
        PlayerEntity* player = world.player();
        if((b.getPosition().x-player->getPosition().x) > 0) {
            world.addCreature(3, 50.f);
        } else {
            world.addCreature(3, -50.f);
        }
    });
    data[Entity::Boss2].push_back(b2p6);
    // Boss2 Phase7
    Phase b2p7(world, boss, sf::seconds(4.1f));
    b2p7.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time){
        PlayerEntity* player = world.player();
        if((b.getPosition().x-player->getPosition().x) > 0) {
            boss.move(Entity::Right);
        } else {
            boss.move(Entity::Left);
        }
    });
    data[Entity::Boss2].push_back(b2p7);

    //////////////////////////////////////////////

    // Boss3 Phase1
    Phase b3p1(world, boss, sf::seconds(0.6f));
    b3p1.addSkill(sf::seconds(0.5f), [&](Boss& b, sf::Time){
        for(unsigned int i = 0; i < 6; ++i)
        {
            world.addCreature(3, 50.f + 150.f*i);
            world.addCreature(3, -50.f - 150.f*i);
        }
    });
    data[Entity::Boss3].push_back(b3p1);
    Phase b3p2(world, boss, sf::seconds(5.f));
    b3p2.addSkill(sf::seconds(0.90f), [&](Boss& b, sf::Time){b.knock();});
    data[Entity::Boss3].push_back(b3p2);
    // Boss1 Phase1
    Phase b3p3(world, boss, sf::seconds(5.f));
    b3p3.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time){
        PlayerEntity* player = world.player();
        world.shakeCameraFor(0.3f);
        if((b.getPosition().x-player->getPosition().x) > 0) {
            boss.move(Entity::Left);
        } else {
            boss.move(Entity::Right);
        }
    });
    data[Entity::Boss3].push_back(b3p3);
    data[Entity::Boss3].push_back(b3p1);
    // Boss1 Phase4
    Phase b3p4(world, boss, sf::seconds(3.f));
    b3p4.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time){
        b.knock();
    });
    data[Entity::Boss3].push_back(b3p4);
    // Boss3 Phase5
    Phase b3p5(world, boss, sf::seconds(2.f));
    b3p5.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time dt){
        b.setPosition(sf::Vector2f(b.getPosition().x, b.getPosition().y-500*dt.asSeconds()));
    });
    data[Entity::Boss3].push_back(b3p5);
    data[Entity::Boss3].push_back(b3p2);
    // Boss3 Phase6
    Phase b3p6(world, boss, sf::seconds(0.0f));
    b3p6.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time dt){
        PlayerEntity* player = world.player();
        b.setPosition(sf::Vector2f(player->getPosition().x, -160));
        world.addCreature(1, 50);
    });
    data[Entity::Boss3].push_back(b3p6);
    Phase b3p6bis(world, boss, sf::seconds(1.5f));
    b3p6bis.addSkill(sf::seconds(0.90f), [&](Boss& b, sf::Time){b.knock();});
    data[Entity::Boss3].push_back(b3p6bis);
    // Boss3 Phase7
    Phase b3p7(world, boss, sf::seconds(1.3f));
    b3p7.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time dt){
        if(b.getPosition().y < 512-105)
        {
            b.setPosition(sf::Vector2f(b.getPosition().x, b.getPosition().y+500*dt.asSeconds()));
        }
        else
        {
            world.shakeCamera();
            b.playLocalSound(world.getCommandQueue(), Sounds::BossCrush);
        }
    });
    data[Entity::Boss3].push_back(b3p7);
    data[Entity::Boss3].push_back(b3p1);
    // Boss3 Phase8
    data[Entity::Boss3].push_back(b3p5);
    data[Entity::Boss3].push_back(b3p6);
    data[Entity::Boss3].push_back(b3p6bis);
    data[Entity::Boss3].push_back(b3p7);
    data[Entity::Boss3].push_back(b3p1);
    data[Entity::Boss3].push_back(b3p5);
    // Boss3 Phase9
    Phase b3p9(world, boss, sf::seconds(1.5f));
    b3p9.addSkill(sf::seconds(0.f), [&](Boss& b, sf::Time dt){
        b.setPosition(1024+160, 512-105);
    });
    data[Entity::Boss3].push_back(b3p9);*/

    return data;
}
Beispiel #17
0
int main()
{
	srand(time(nullptr));
	sf::Clock time;
	sf::View followPlayer; //private member in class
	sf::Sprite background;
	sf::Texture background_texture;
	sf::Sprite key;
	sf::Sprite key2;
	sf::Texture key_texture;
	sf::Texture mute_texture;
	sf::Sprite mute_sprite;
	vector<Key*> keys;
	vector<unsigned int> keysForDeletion;
	
	if (!background_texture.loadFromFile("Data/Sprites/background.png"))
	{
		return -1;
	}

	if (!key_texture.loadFromFile("Data/Sprites/key.png")){
		return -1;
	}

	key2.setTexture(key_texture);
	key2.setScale(5, 5);
	key.setTexture(key_texture);
	key.setScale(5, 5);

	if (!mute_texture.loadFromFile("Data/Sprites/mute_icon.png")){
		cout << "Couldn't load mute_icon.png" << endl;
	}
	mute_sprite.setTexture(mute_texture);
	mute_sprite.setScale(3, 3);
	if (!keyBuffer.loadFromFile("Data/Sounds/key_taken.wav")){
		cout << "Couldn't load key_taken.wav" << endl;
	}
	keySound.setBuffer(keyBuffer);

	/*Load the theme music and start playing it if it loads correctly*/
	if (!buffer.loadFromFile("Data/Sounds/theme.wav")){
		cout << "Couldn't load theme.wav" << endl;
	}
	else {
		theme.setBuffer(buffer);
		theme.play();
	}


	background.setTexture(background_texture);

	background.setScale(5, 5);

	/*Set the position relative the middle of the background's bounds */
	background.setPosition(-background.getLocalBounds().width / 2, -background.getLocalBounds().height / 2);
	key.setPosition(200, 150);
	key2.setPosition(350, 350);
	Player player = Player(background.getPosition(), Vector2f(background.getLocalBounds().width * background.getScale().x, background.getLocalBounds().height * background.getScale().y));

	/*Window setup*/
	sf::RenderWindow window(sf::VideoMode(1200, 720), "Presence");
	window.clear(sf::Color(255, 255, 255, 0));
	 
	/*keyCounter doesn't work when keys in between get deleted*/
	keys.push_back(new Key(player, Vector2f(background.getLocalBounds().width * background.getScale().x, background.getLocalBounds().height * background.getScale().y)));
	keys.push_back(new Key(player, Vector2f(background.getLocalBounds().width * background.getScale().x, background.getLocalBounds().height * background.getScale().y)));
	keys.push_back(new Key(player, Vector2f(background.getLocalBounds().width * background.getScale().x, background.getLocalBounds().height * background.getScale().y)));
	keys.push_back(new Key(player, Vector2f(background.getLocalBounds().width * background.getScale().x, background.getLocalBounds().height * background.getScale().y)));
	keys.push_back(new Key(player, Vector2f(background.getLocalBounds().width * background.getScale().x, background.getLocalBounds().height * background.getScale().y)));

	while (window.isOpen())
	{
		if (muted){
			if (theme.getStatus() == theme.Playing){
				theme.pause();
			}
		}
		else if(theme.getStatus() == theme.Paused){
			theme.play();
		}
		/*Deltatime*/
		sf::Time delta = time.restart();

		//EVENTS
		sf::Event event;
		while (window.pollEvent(event))
		{
			if (event.type == sf::Event::KeyPressed){
				if (event.key.code == sf::Keyboard::M){
					if (muted) muted = false;
					else muted = true;
				}
			}
			if (event.type == sf::Event::Closed || event.key.code == sf::Keyboard::Escape)
				window.close();
			player.move(event);
		}

		//LOGIC
		player.update(delta.asSeconds());

		//RENDERING
		window.clear(sf::Color(178, 148, 0, 0));
		window.draw(background);

		Vector2f cameraSpeed = getCameraSpeed(followPlayer.getCenter(), player.getPosition());
		float cameraXSpeed = cameraSpeed.x;
		float cameraYSpeed = cameraSpeed.y;

		if (!keyTaken && key.getGlobalBounds().intersects(player.getBounds())){
			cout << "HIT!" << endl;
			
			keyTaken = true;
			if (!muted) keySound.play();
		}
		if (!key2Taken && key2.getGlobalBounds().intersects(player.getBounds())){
			key2Taken = true;
			if(!muted) keySound.play();
		}
		followPlayer.setCenter(followPlayer.getCenter().x + cameraXSpeed * delta.asSeconds(), followPlayer.getCenter().y + cameraYSpeed * delta.asSeconds()); //in constructor

		followPlayer.setSize(1200, 720);
		window.setView(followPlayer);

		if (muted){
			mute_sprite.setPosition(window.mapPixelToCoords(Vector2i(1, 0)));
			window.draw(mute_sprite);
		}
		if (!keyTaken){
			window.draw(key);
		}
		if (!key2Taken){
			window.draw(key2);
		}
		player.render(window);

		int i = 0;
		/*Free memory from taken key objects*/
		for (Key* key : keys){
			if (!key->readyForDeletion()){
				key->update(delta.asSeconds());
				key->render(window);
			}
			else{
				keysForDeletion.push_back(i);
			}
			i++;
		}
		for (unsigned int index : keysForDeletion){
			Key* key_ptr = keys[index];
			keys.erase(remove(keys.begin(), keys.end(), key_ptr), keys.end());
			delete key_ptr;
		}

		keysForDeletion.clear();

		window.display();
	}

	return 0;
}
void Game::update(float delta)
{
	for (size_t i = 0; i < delays.size(); i++)
	{
		delays[i].time -= delta;

		if (!delays[i].fired && delays[i].time <= 0.0f)
		{
			delays[i].fired = true;
			delays[i].func();

			delays[i] = delays[delays.size() - 1];
			delays.pop_back();
			i--;
		}
	}

	highestBlock = 0.0f;
	shakeIntensity = glm::max(0.0f, shakeIntensity - delta * 1.5f);

	for (int i = 0; i < 2; i++)
		bound[i] = glm::clamp(bound[i] - delta * 2.0f, 0.0f, 1.0f);

	for (auto it = powerups.begin(); it != powerups.end(); ++it)
	{
		if (it->update(delta))
		{
			*it = powerups.back();
			it--;
			powerups.pop_back();
			continue;
		}
	}

	for (auto it = blocks.begin(); it != blocks.end(); ++it)
	{
		if (!it->alive)
		{
			*it = blocks.back();
			it--;
			blocks.pop_back();
			continue;
		}

		it->update(delta);
	}

	if (glfwGetTime() >= nextBlockSpawn)
	{
		scheduleNextBlockSpawn();

		std::uniform_int_distribution<> dist(4, 8);
		std::uniform_real_distribution<> dist2(0.0f, 3150.0f);

		int count = dist(random);

		for (int i = 0; i < count; i++)
		{
			float x = 50 * glm::round((float)dist2(random) / 50);
			blocks.push_back(Block(this, glm::vec2(x, highestBlock -1050.0f)));
		}
	}

	if (glfwGetTime() >= nextPowerupSpawn)
	{
		scheduleNextPowerupSpawn();
		powerups.push_back(Powerup(this));
	}

	glm::vec2 pos_min, pos_max;
	bool pos_one = false;

	//for (auto it = players.begin(); it != players.end(); ++it)
	for (size_t i = 0; i < players.size(); i++)
	{
		Player *it = &*players[i];

		if (!it->dead)
		{
			glm::vec2 pos = it->getPosition();

			if (!pos_one)
			{
				pos_min = pos;
				pos_max = pos;
				pos_one = true;
			}
			else
			{
				pos_min = glm::min(pos_min, pos);
				pos_max = glm::max(pos_max, pos);
			}

			it->update(delta);
		}
		else if (glfwGetTime() - it->deathTime >= 3.0f)
			it->resetFinish();
	}

	for (auto it = particles.begin(); it != particles.end(); ++it)
	{
		if (it->duration <= 0.0f)
		{
			*it = particles.back();
			it--;
			particles.pop_back();
			continue;
		}

		it->update(delta);
	}

	if (pos_one)
	{
		int width, height;
		glfwGetWindowSize(window, &width, &height);

		//camera.pos_dest.x = (pos_min.x + pos_max.x) / 2.0f - width / 2.0f + 25.0f;
		//camera.pos_dest.y = (pos_min.y + pos_max.y) / 2.0f - height / 2.0f + 25.0f;
		camera.pos_dest.x = (pos_min.x + pos_max.x) / 2.0f + 25.0f;
		camera.pos_dest.y = (pos_min.y + pos_max.y) / 2.0f + 25.0f;
		//camera.pos_dest.y = 1000.0f - height;
		camera.scale_dest = glm::min(1.0f, (width - 200) / glm::abs(pos_min.x - pos_max.x));

		camera.pos -= (camera.pos - camera.pos_dest) * delta * camera.speed;
		camera.scale -= (camera.scale - camera.scale_dest) * delta * camera.speed;
	}

	fmod->update();
}
void ServerState::ProcessPackets(GameUtility *gameUtility)
{
	//sC->globalMutex.lock();
	auto packets = sC->packets;
	sC->packets = std::queue<std::pair<sf::Packet*, Client*>>();
	//sC->globalMutex.unlock();

	while(packets.size() > 0)
	{
		auto data = packets.front();
		sf::Packet* packet = data.first;
		Client *client = data.second;

		sf::Uint16 packetType;
		if(!(*packet >> packetType))
			std::cout << "ERROR: Server could not extract data" << std::endl;

		sf::Packet* const originalPacket = new sf::Packet(*packet);

		switch(packetType)
		{
		case PingMessage: //measure ping between sent 1 and received 1 (type)
			{
				float ping = client->pingClock.getElapsedTime().asMilliseconds();
				client->pingClock.restart();
				client->ping = ping;
				//std::cout << "Client " << client->ID << " has ping " << ping << std::endl;
			}
			break;
		case KickMessage: //server kicks client (type, string message)

			break;
		case PlayerJoinLeft:
			{
				sf::Uint16 type;
				float xPos;
				float yPos;

				//std::cout << "Server got PlayerJoinLeft " << packetType << " " << type << " " << xPos << " " << yPos << " " << client->ID << std::endl;

				sf::Packet send;
				sf::Uint16 packetTypeTemp = PlayerJoinLeft;
				sf::Uint16 clientidtemp = client->ID;

				*packet >> type;

				if(type == 0) //Player has joined
				{
					*packet >> xPos >> yPos;

					//Add the player to the server world
					currentWorld->AddPlayer(client->ID, new Player(xPos, yPos, 14, 14, true, "smileys.png", 0, "temp"));

					// Send the init message
					// Players
					send << (sf::Uint16) InitMessage;
					for(std::pair<int, Client*> pair : sC->clients)
					{
						Player* temp = currentWorld->GetPlayer(pair.first);
						if(temp != nullptr)
							send << (sf::Int16)pair.first << (sf::Int16)temp->getPosition().x << (sf::Int16)temp->getPosition().y << (sf::Int16)temp->getSize().x << (sf::Int16)temp->getSize().y;
					}
					client->socket.send(send);

					send.clear();
					send << packetType << type << xPos << yPos << clientidtemp;

				}
				/*else if(type == 1) //Player has left
				{
				currentWorld->RemovePlayer(client->ID);
				send.Clear();
				send << packetType << type << (sf::Uint16)client->ID;
				std::cout << client->IP << " has left" << std::endl;
				}*/

				sC->Broadcast(send);
				//std::cout << "Server sent PlayerJoinLeft " << packetType << " " << type << " " << xPos << " " << yPos << " " << clientidtemp << std::endl;
				break;
			}
		case PlayerMove:
			{
				float xPos;
				float yPos;
				float speedX;
				float speedY;
				float angle;
				float horizontal;
				float vertical;
				*packet >> xPos >> yPos >> speedX >> speedY >> angle >> horizontal >> vertical;
				Player* p = currentWorld->GetPlayer(client->ID);
				if (p != nullptr)
				{
					//Broadcast playermove data
					sf::Packet packet;
					sf::Int16 clientid = client->ID;
					packet << (sf::Uint16)PlayerMove << clientid << xPos << yPos << speedX << speedY << angle << horizontal << vertical;
					sC->Broadcast(packet);

					//Move player in server world
					p->CreatureMove(xPos, yPos, speedX, speedY, angle, horizontal, vertical);

					//Send world data in radius around player
					/*int chunkX = xPos * 0.00390625;
					int chunkY = yPos * 0.00390625;
					currentWorld->get*/
				}
			}
			break;
		case BlockPlace:
			{
				sf::Int32 xPos;
				sf::Int32 yPos;
				sf::Uint16 layer;
				sf::Uint16 id;
				sf::Uint16 metadata;
				*packet >> xPos >> yPos >> layer >> id >> metadata;
				std::cout << "server received " << xPos << " " << yPos << " " << layer << " " << id << " " << metadata << std::endl;
				if(id != 0)
					Block* temp = blockRegister->getBlockType(id)->OnReceive(originalPacket, gameUtility);
				else
					gameUtility->getCurrentWorld()->setBlockAndMetadata(xPos, yPos, layer, 0, metadata, gameUtility);
			}
			break;
		case BlockMetadataChange:
			{
				sf::Int32 xPos;
				sf::Int32 yPos;
				sf::Uint16 layer;
				sf::Uint16 metadata;
				*packet >> xPos >> yPos >> layer >> metadata;
				currentWorld->setBlockMetadata(xPos, yPos, layer, metadata, this);
			}
			break;
		}
		delete packet;
		delete originalPacket;
		packets.pop();
	}
void ServerEnvironment::step(float dtime)
{
	DSTACK(__FUNCTION_NAME);
	
	//TimeTaker timer("ServerEnv step");

	// Get some settings
	bool footprints = g_settings.getBool("footprints");

	/*
		Increment game time
	*/
	{
		m_game_time_fraction_counter += dtime;
		u32 inc_i = (u32)m_game_time_fraction_counter;
		m_game_time += inc_i;
		m_game_time_fraction_counter -= (float)inc_i;
	}
	
	/*
		Handle players
	*/
	for(core::list<Player*>::Iterator i = m_players.begin();
			i != m_players.end(); i++)
	{
		Player *player = *i;
		
		// Ignore disconnected players
		if(player->peer_id == 0)
			continue;

		v3f playerpos = player->getPosition();
		
		// Move
		player->move(dtime, *m_map, 100*BS);
		
		/*
			Add footsteps to grass
		*/
		if(footprints)
		{
			// Get node that is at BS/4 under player
			v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
			try{
				MapNode n = m_map->getNode(bottompos);
				if(n.getContent() == CONTENT_GRASS)
				{
					n.setContent(CONTENT_GRASS_FOOTSTEPS);
					m_map->setNode(bottompos, n);
				}
			}
			catch(InvalidPositionException &e)
			{
			}
		}
	}

	/*
		Manage active block list
	*/
	if(m_active_blocks_management_interval.step(dtime, 2.0))
	{
		/*
			Get player block positions
		*/
		core::list<v3s16> players_blockpos;
		for(core::list<Player*>::Iterator
				i = m_players.begin();
				i != m_players.end(); i++)
		{
			Player *player = *i;
			// Ignore disconnected players
			if(player->peer_id == 0)
				continue;
			v3s16 blockpos = getNodeBlockPos(
					floatToInt(player->getPosition(), BS));
			players_blockpos.push_back(blockpos);
		}
		
		/*
			Update list of active blocks, collecting changes
		*/
		const s16 active_block_range = 5;
		core::map<v3s16, bool> blocks_removed;
		core::map<v3s16, bool> blocks_added;
		m_active_blocks.update(players_blockpos, active_block_range,
				blocks_removed, blocks_added);

		/*
			Handle removed blocks
		*/

		// Convert active objects that are no more in active blocks to static
		deactivateFarObjects(false);
		
		for(core::map<v3s16, bool>::Iterator
				i = blocks_removed.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();

			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") became inactive"<<std::endl;*/
			
			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;
			
			// Set current time as timestamp (and let it set ChangedFlag)
			block->setTimestamp(m_game_time);
		}

		/*
			Handle added blocks
		*/

		for(core::map<v3s16, bool>::Iterator
				i = blocks_added.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();
			
			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") became active"<<std::endl;*/

			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;

			activateBlock(block);
		}
	}

	/*
		Mess around in active blocks
	*/
	if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
	{
		float dtime = 1.0;

		for(core::map<v3s16, bool>::Iterator
				i = m_active_blocks.m_list.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();
			
			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") being handled"<<std::endl;*/

			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;

			// Reset block usage timer
			block->resetUsageTimer();
			
			// Set current time as timestamp
			block->setTimestampNoChangedFlag(m_game_time);

			// Run node metadata
			bool changed = block->m_node_metadata.step(dtime);
			if(changed)
			{
				MapEditEvent event;
				event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
				event.p = p;
				m_map->dispatchEvent(&event);

				block->setChangedFlag();
			}
		}
	}
	if(m_active_blocks_test_interval.step(dtime, 10.0))
	{
		//float dtime = 10.0;
		
		for(core::map<v3s16, bool>::Iterator
				i = m_active_blocks.m_list.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();
			
			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") being handled"<<std::endl;*/

			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;
			
			// Set current time as timestamp
			block->setTimestampNoChangedFlag(m_game_time);

			/*
				Do stuff!

				Note that map modifications should be done using the event-
				making map methods so that the server gets information
				about them.

				Reading can be done quickly directly from the block.

				Everything should bind to inside this single content
				searching loop to keep things fast.
			*/
			// TODO: Implement usage of ActiveBlockModifier
			
			// Find out how many objects the block contains
			u32 active_object_count = block->m_static_objects.m_active.size();
			// Find out how many objects this and all the neighbors contain
			u32 active_object_count_wider = 0;
			for(s16 x=-1; x<=1; x++)
			for(s16 y=-1; y<=1; y++)
			for(s16 z=-1; z<=1; z++)
			{
				MapBlock *block = m_map->getBlockNoCreateNoEx(p+v3s16(x,y,z));
				if(block==NULL)
					continue;
				active_object_count_wider +=
						block->m_static_objects.m_active.size();
			}

			v3s16 p0;
			for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
			for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
			for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
			{
				v3s16 p = p0 + block->getPosRelative();
				MapNode n = block->getNodeNoEx(p0);

				/*
					Test something:
					Convert mud under proper lighting to grass
				*/
				if(n.getContent() == CONTENT_MUD)
				{
					if(myrand()%20 == 0)
					{
						MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
						if(content_features(n_top).air_equivalent &&
								n_top.getLightBlend(getDayNightRatio()) >= 13)
						{
							n.setContent(CONTENT_GRASS);
							m_map->addNodeWithEvent(p, n);
						}
					}
				}
				/*
					Convert grass into mud if under something else than air
				*/
				if(n.getContent() == CONTENT_GRASS)
				{
					//if(myrand()%20 == 0)
					{
						MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
						if(content_features(n_top).air_equivalent == false)
						{
							n.setContent(CONTENT_MUD);
							m_map->addNodeWithEvent(p, n);
						}
					}
				}
				/*
					Rats spawn around regular trees
				*/
				if(n.getContent() == CONTENT_TREE ||
						n.getContent() == CONTENT_JUNGLETREE)
				{
   					if(myrand()%200 == 0 && active_object_count_wider == 0)
					{
						v3s16 p1 = p + v3s16(myrand_range(-2, 2),
								0, myrand_range(-2, 2));
						MapNode n1 = m_map->getNodeNoEx(p1);
						MapNode n1b = m_map->getNodeNoEx(p1+v3s16(0,-1,0));
						if(n1b.getContent() == CONTENT_GRASS &&
								n1.getContent() == CONTENT_AIR)
						{
							v3f pos = intToFloat(p1, BS);
							ServerActiveObject *obj = new RatSAO(this, 0, pos);
							addActiveObject(obj);
						}
					}
			 }
			}
		}
	}
	
	/*
		Step active objects
	*/
	{
		//TimeTaker timer("Step active objects");
		
		// This helps the objects to send data at the same time
		bool send_recommended = false;
		m_send_recommended_timer += dtime;
		if(m_send_recommended_timer > 0.15)
		{
			m_send_recommended_timer = 0;
			send_recommended = true;
		}

		for(core::map<u16, ServerActiveObject*>::Iterator
				i = m_active_objects.getIterator();
				i.atEnd()==false; i++)
		{
			ServerActiveObject* obj = i.getNode()->getValue();
			// Don't step if is to be removed or stored statically
			if(obj->m_removed || obj->m_pending_deactivation)
				continue;
			// Step object
			obj->step(dtime, send_recommended);
			// Read messages from object
			while(obj->m_messages_out.size() > 0)
			{
				m_active_object_messages.push_back(
						obj->m_messages_out.pop_front());
			}
		}
	}
	
	/*
		Manage active objects
	*/
	if(m_object_management_interval.step(dtime, 0.5))
	{
		/*
			Remove objects that satisfy (m_removed && m_known_by_count==0)
		*/
		removeRemovedObjects();
	}

	if(g_settings.getBool("enable_experimental"))
	{

	/*
		TEST CODE
	*/
#if 1
	m_random_spawn_timer -= dtime;
	if(m_random_spawn_timer < 0)
	{
		//m_random_spawn_timer += myrand_range(2.0, 20.0);
		//m_random_spawn_timer += 2.0;
		m_random_spawn_timer += 200.0;

		/*
			Find some position
		*/

		/*v2s16 p2d(myrand_range(-5,5), myrand_range(-5,5));
		s16 y = 1 + getServerMap().findGroundLevel(p2d);
		v3f pos(p2d.X*BS,y*BS,p2d.Y*BS);*/
		
		Player *player = getRandomConnectedPlayer();
		v3f pos(0,0,0);
		if(player)
			pos = player->getPosition();
		pos += v3f(
			myrand_range(-3,3)*BS,
			0,
			myrand_range(-3,3)*BS
		);

		/*
			Create a ServerActiveObject
		*/

		//TestSAO *obj = new TestSAO(this, 0, pos);
		//ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
		//ServerActiveObject *obj = new RatSAO(this, 0, pos);
		//ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
		ServerActiveObject *obj = new FireflySAO(this, 0, pos);
		addActiveObject(obj);
	}
#endif

	} // enable_experimental
}
Beispiel #21
0
	virtual bool update() {

		move(0, walls.getSpeed());
		move(vel);


		updateCollisionPoly();
		Vec2 normal;
		float distance = walls.checkCollision(poly, &normal);
		if (distance > 0) {
			move(normal * -distance);
			updateCollisionPoly();
			// bounce of walls
			vel -= 2.0f * normal * dot(vel, normal);
		}

		Vec2 pos = getPosition();

		// find leader
		QueueGuy* leader = nullptr;
		float squareDist = 10000;
		for (unique_ptr<BadGuy>& guy : badGuys) {
			QueueGuy* queue = dynamic_cast<QueueGuy*>(&*guy);
			if (queue && queue != this) {
				Vec2 diff = queue->getPosition() - pos;
				Vec2 dir = normalized(diff);
				if (dot(normalized(vel), dir) > 0.1 && dot(vel, queue->vel) > 0.1) {
					float d = dot(diff, diff);
					if (d < squareDist) {
						squareDist = d;
						leader = queue;
					}
				}
			}
		}



		if (leader) { // follow
			Vec2 dst = leader->getPosition() - normalized(leader->vel) * 50.0f;
			Vec2 dir = dst - pos;
			Vec2 a = dir * 0.01f + (leader->vel - vel) * 0.2f;
			if (length(a) > 0.1f) a *= 0.1f / length(a);
			vel += a;


			// shoot
			tick += randInt(1, 2);
			if (tick >= 300 && !walls.shootAt(getPosition(), player.getPosition())) {
				tick = randInt(0, 100);

				Vec2 diff = player.getPosition() - pos;
				float ang = atan2(diff.x, diff.y) + randFloat(-0.1, 0.1);
				Vec2 dir = Vec2(sin(ang), cos(ang));
				makeBullet<Bullet>(pos, dir * randFloat(3.7, 4));
			}

		}
		else { // lead

			Vec2 dir = normalized(vel);
			Vec2 perp(dir.y, -dir.x);


			if (--turnDelay <= 0) {
				turn = randFloat(-1, 1) * 0.03;
				turnDelay = randInt(30, 100);
			}

			float dodge = turn;
			float i1, i2;
			bool s1 = walls.shootAt(pos + perp * 10.0f, pos + dir * 60.0f + perp * 40.0f, &i1);
			bool s2 = walls.shootAt(pos - perp * 10.0f, pos + dir * 60.0f - perp * 40.0f, &i2);
			if (s1 || s2) {
				dodge = (s1 < s2 || i1 < i2) ? -0.2 * (1 - i2) : 0.2 * (1 - i1);
				vel *= 0.98f;
			}


			float ss = sin(dodge);
			float cc = cos(dodge);
			vel = Vec2(
				vel.x * cc - vel.y * ss,
				vel.x * ss + vel.y * cc
			);

			float v = length(vel);
			if (v < 2.2) vel += dir * 0.05f;


		}
		float v = length(vel);
		if (v > 2.8) vel *= 2.8f / v;

		setRotation(atan2(-vel.x, vel.y) * 180 / M_PI);




		setFrame(frame / 4);
		if (++frame >= frameCount * 4) frame = 0;

		if (pos.x < -50 || pos.x > 850) return false;
		if (pos.y < -200 || pos.y > 650) return false;
		return checkCollisionWithLaser();
	}
Beispiel #22
0
float MatchHelpers::distanceToOppositeGoal(const Player& p)
{
	return (p.getPosition() - oppositeGoalPosition(p)).length();
}
void ClientEnvironment::step(float dtime)
{
	DSTACK(__FUNCTION_NAME);

	// Get some settings
	bool free_move = g_settings.getBool("free_move");
	bool footprints = g_settings.getBool("footprints");

	// Get local player
	LocalPlayer *lplayer = getLocalPlayer();
	assert(lplayer);
	// collision info queue
	core::list<CollisionInfo> player_collisions;
	
	/*
		Get the speed the player is going
	*/
	bool is_climbing = lplayer->is_climbing;

	f32 player_speed = 0.001; // just some small value
	player_speed = lplayer->getSpeed().getLength();
	
	/*
		Maximum position increment
	*/
	//f32 position_max_increment = 0.05*BS;
	f32 position_max_increment = 0.1*BS;

	// Maximum time increment (for collision detection etc)
	// time = distance / speed
	f32 dtime_max_increment = position_max_increment / player_speed;
	
	// Maximum time increment is 10ms or lower
	if(dtime_max_increment > 0.01)
		dtime_max_increment = 0.01;
	
	// Don't allow overly huge dtime
	if(dtime > 0.5)
		dtime = 0.5;
	
	f32 dtime_downcount = dtime;

	/*
		Stuff that has a maximum time increment
	*/

	u32 loopcount = 0;
	do
	{
		loopcount++;

		f32 dtime_part;
		if(dtime_downcount > dtime_max_increment)
		{
			dtime_part = dtime_max_increment;
			dtime_downcount -= dtime_part;
		}
		else
		{
			dtime_part = dtime_downcount;
			/*
				Setting this to 0 (no -=dtime_part) disables an infinite loop
				when dtime_part is so small that dtime_downcount -= dtime_part
				does nothing
			*/
			dtime_downcount = 0;
		}
		
		/*
			Handle local player
		*/
		
		{
			v3f lplayerpos = lplayer->getPosition();
			
			// Apply physics
			if(free_move == false && is_climbing == false)
			{
				// Gravity
				v3f speed = lplayer->getSpeed();
				if(lplayer->swimming_up == false)
					speed.Y -= 9.81 * BS * dtime_part * 2;

				// Water resistance
				if(lplayer->in_water_stable || lplayer->in_water)
				{
					f32 max_down = 2.0*BS;
					if(speed.Y < -max_down) speed.Y = -max_down;

					f32 max = 2.5*BS;
					if(speed.getLength() > max)
					{
						speed = speed / speed.getLength() * max;
					}
				}

				lplayer->setSpeed(speed);
			}

			/*
				Move the lplayer.
				This also does collision detection.
			*/
			lplayer->move(dtime_part, *m_map, position_max_increment,
					&player_collisions);
		}
	}
	while(dtime_downcount > 0.001);
		
	//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;

	for(core::list<CollisionInfo>::Iterator
			i = player_collisions.begin();
			i != player_collisions.end(); i++)
	{
		CollisionInfo &info = *i;
		if(info.t == COLLISION_FALL)
		{
			//f32 tolerance = BS*10; // 2 without damage
			f32 tolerance = BS*12; // 3 without damage
			f32 factor = 1;
			if(info.speed > tolerance)
			{
				f32 damage_f = (info.speed - tolerance)/BS*factor;
				u16 damage = (u16)(damage_f+0.5);
				if(lplayer->hp > damage)
					lplayer->hp -= damage;
				else
					lplayer->hp = 0;

				ClientEnvEvent event;
				event.type = CEE_PLAYER_DAMAGE;
				event.player_damage.amount = damage;
				m_client_event_queue.push_back(event);
			}
		}
	}
	
	/*
		Stuff that can be done in an arbitarily large dtime
	*/
	for(core::list<Player*>::Iterator i = m_players.begin();
			i != m_players.end(); i++)
	{
		Player *player = *i;
		v3f playerpos = player->getPosition();
		
		/*
			Handle non-local players
		*/
		if(player->isLocal() == false)
		{
			// Move
			player->move(dtime, *m_map, 100*BS);

			// Update lighting on remote players on client
			u8 light = LIGHT_MAX;
			try{
				// Get node at head
				v3s16 p = floatToInt(playerpos + v3f(0,BS+BS/2,0), BS);
				MapNode n = m_map->getNode(p);
				light = n.getLightBlend(getDayNightRatio());
			}
			catch(InvalidPositionException &e) {}
			player->updateLight(light);
		}
		
		/*
			Add footsteps to grass
		*/
		if(footprints)
		{
			// Get node that is at BS/4 under player
			v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
			try{
				MapNode n = m_map->getNode(bottompos);
				if(n.getContent() == CONTENT_GRASS)
				{
					n.setContent(CONTENT_GRASS_FOOTSTEPS);
					m_map->setNode(bottompos, n);
					// Update mesh on client
					if(m_map->mapType() == MAPTYPE_CLIENT)
					{
						v3s16 p_blocks = getNodeBlockPos(bottompos);
						MapBlock *b = m_map->getBlockNoCreate(p_blocks);
						//b->updateMesh(getDayNightRatio());
						b->setMeshExpired(true);
					}
				}
			}
			catch(InvalidPositionException &e)
			{
			}
		}
	}
	
	/*
		Step active objects and update lighting of them
	*/
	
	for(core::map<u16, ClientActiveObject*>::Iterator
			i = m_active_objects.getIterator();
			i.atEnd()==false; i++)
	{
		ClientActiveObject* obj = i.getNode()->getValue();
		// Step object
		obj->step(dtime, this);

		if(m_active_object_light_update_interval.step(dtime, 0.21))
		{
			// Update lighting
			//u8 light = LIGHT_MAX;
			u8 light = 0;
			try{
				// Get node at head
				v3s16 p = obj->getLightPosition();
				MapNode n = m_map->getNode(p);
				light = n.getLightBlend(getDayNightRatio());
			}
			catch(InvalidPositionException &e) {}
			obj->updateLight(light);
		}
	}
}
Beispiel #24
0
void FireflySAO::step(float dtime, bool send_recommended)
{
	ScopeProfiler sp2(g_profiler, "FireflySAO::step avg", SPT_AVG);

	assert(m_env);

	if(m_is_active == false)
	{
		if(m_inactive_interval.step(dtime, 0.5)==false)
			return;
	}

	/*
		The AI
	*/

	// Apply (less) gravity
	m_speed_f.Y -= dtime*3*BS;

	/*
		Move around if some player is close
	*/
	bool player_is_close = false;
	// Check connected players
	core::list<Player*> players = m_env->getPlayers(true);
	core::list<Player*>::Iterator i;
	for(i = players.begin();
			i != players.end(); i++)
	{
		Player *player = *i;
		v3f playerpos = player->getPosition();
		if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
		{
			player_is_close = true;
			break;
		}
	}

	m_is_active = player_is_close;
	
	if(player_is_close == false)
	{
		m_speed_f.X = 0;
		m_speed_f.Z = 0;
	}
	else
	{
		// Move around
		v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
		f32 speed = BS/2;
		m_speed_f.X = speed * dir.X;
		m_speed_f.Z = speed * dir.Z;

		if(m_touching_ground && (m_oldpos - m_base_position).getLength()
				< dtime*speed/2)
		{
			m_counter1 -= dtime;
			if(m_counter1 < 0.0)
			{
				m_counter1 += 1.0;
				m_speed_f.Y = 5.0*BS;
			}
		}

		{
			m_counter2 -= dtime;
			if(m_counter2 < 0.0)
			{
				m_counter2 += (float)(myrand()%100)/100*3.0;
				m_yaw += ((float)(myrand()%200)-100)/100*180;
				m_yaw = wrapDegrees(m_yaw);
			}
		}
	}
	
	m_oldpos = m_base_position;

	/*
		Move it, with collision detection
	*/

	core::aabbox3d<f32> box(-BS/3.,-BS*2/3.0,-BS/3., BS/3.,BS*4./3.,BS/3.);
	collisionMoveResult moveresult;
	// Maximum movement without glitches
	f32 pos_max_d = BS*0.25;
	// Limit speed
	if(m_speed_f.getLength()*dtime > pos_max_d)
		m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
	v3f pos_f = getBasePosition();
	v3f pos_f_old = pos_f;
	IGameDef *gamedef = m_env->getGameDef();
	moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
			pos_max_d, box, dtime, pos_f, m_speed_f);
	m_touching_ground = moveresult.touching_ground;
	
	setBasePosition(pos_f);

	if(send_recommended == false)
		return;

	if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
	{
		m_last_sent_position = pos_f;

		std::ostringstream os(std::ios::binary);
		// command (0 = update position)
		writeU8(os, 0);
		// pos
		writeV3F1000(os, m_base_position);
		// yaw
		writeF1000(os, m_yaw);
		// create message and add to list
		ActiveObjectMessage aom(getId(), false, os.str());
		m_messages_out.push_back(aom);
	}
}
Beispiel #25
0
bool Board::hasPlayerFinished(Player player) {
    return player.getPosition().x + player.getWidth() / 2.0 >= width_;
}
Beispiel #26
0
void Oerkki1SAO::step(float dtime, bool send_recommended)
{
	ScopeProfiler sp2(g_profiler, "Oerkki1SAO::step avg", SPT_AVG);

	assert(m_env);

	if(m_is_active == false)
	{
		if(m_inactive_interval.step(dtime, 0.5)==false)
			return;
	}

	/*
		The AI
	*/

	m_age += dtime;
	if(m_age > 120)
	{
		// Die
		m_removed = true;
		return;
	}

	m_after_jump_timer -= dtime;

	v3f old_speed = m_speed_f;

	// Apply gravity
	m_speed_f.Y -= dtime*9.81*BS;

	/*
		Move around if some player is close
	*/
	bool player_is_close = false;
	bool player_is_too_close = false;
	v3f near_player_pos;
	// Check connected players
	core::list<Player*> players = m_env->getPlayers(true);
	core::list<Player*>::Iterator i;
	for(i = players.begin();
			i != players.end(); i++)
	{
		Player *player = *i;
		v3f playerpos = player->getPosition();
		f32 dist = m_base_position.getDistanceFrom(playerpos);
		if(dist < BS*0.6)
		{
			m_removed = true;
			return;
			player_is_too_close = true;
			near_player_pos = playerpos;
		}
		else if(dist < BS*15.0 && !player_is_too_close)
		{
			player_is_close = true;
			near_player_pos = playerpos;
		}
	}

	m_is_active = player_is_close;

	v3f target_speed = m_speed_f;

	if(!player_is_close)
	{
		target_speed = v3f(0,0,0);
	}
	else
	{
		// Move around

		v3f ndir = near_player_pos - m_base_position;
		ndir.Y = 0;
		ndir.normalize();

		f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
		if(nyaw < m_yaw - 180)
			nyaw += 360;
		else if(nyaw > m_yaw + 180)
			nyaw -= 360;
		m_yaw = 0.95*m_yaw + 0.05*nyaw;
		m_yaw = wrapDegrees(m_yaw);
		
		f32 speed = 2*BS;

		if((m_touching_ground || m_after_jump_timer > 0.0)
				&& !player_is_too_close)
		{
			v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
			target_speed.X = speed * dir.X;
			target_speed.Z = speed * dir.Z;
		}

		if(m_touching_ground && (m_oldpos - m_base_position).getLength()
				< dtime*speed/2)
		{
			m_counter1 -= dtime;
			if(m_counter1 < 0.0)
			{
				m_counter1 += 0.2;
				// Jump
				target_speed.Y = 5.0*BS;
				m_after_jump_timer = 1.0;
			}
		}

		{
			m_counter2 -= dtime;
			if(m_counter2 < 0.0)
			{
				m_counter2 += (float)(myrand()%100)/100*3.0;
				//m_yaw += ((float)(myrand()%200)-100)/100*180;
				m_yaw += ((float)(myrand()%200)-100)/100*90;
				m_yaw = wrapDegrees(m_yaw);
			}
		}
	}
	
	if((m_speed_f - target_speed).getLength() > BS*4 || player_is_too_close)
		accelerate_xz(m_speed_f, target_speed, dtime*BS*8);
	else
		accelerate_xz(m_speed_f, target_speed, dtime*BS*4);
	
	m_oldpos = m_base_position;

	/*
		Move it, with collision detection
	*/

	core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
	collisionMoveResult moveresult;
	// Maximum movement without glitches
	f32 pos_max_d = BS*0.25;
	/*// Limit speed
	if(m_speed_f.getLength()*dtime > pos_max_d)
		m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);*/
	v3f pos_f = getBasePosition();
	v3f pos_f_old = pos_f;
	IGameDef *gamedef = m_env->getGameDef();
	moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
			pos_max_d, box, dtime, pos_f, m_speed_f);
	m_touching_ground = moveresult.touching_ground;
	
	// Do collision damage
	float tolerance = BS*30;
	float factor = BS*0.5;
	v3f speed_diff = old_speed - m_speed_f;
	// Increase effect in X and Z
	speed_diff.X *= 2;
	speed_diff.Z *= 2;
	float vel = speed_diff.getLength();
	if(vel > tolerance)
	{
		f32 damage_f = (vel - tolerance)/BS*factor;
		u16 damage = (u16)(damage_f+0.5);
		doDamage(damage);
	}

	setBasePosition(pos_f);

	if(send_recommended == false && m_speed_f.getLength() < 3.0*BS)
		return;

	if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
	{
		m_last_sent_position = pos_f;

		std::ostringstream os(std::ios::binary);
		// command (0 = update position)
		writeU8(os, 0);
		// pos
		writeV3F1000(os, m_base_position);
		// yaw
		writeF1000(os, m_yaw);
		// create message and add to list
		ActiveObjectMessage aom(getId(), false, os.str());
		m_messages_out.push_back(aom);
	}
}
Beispiel #27
0
void MobV2SAO::step(float dtime, bool send_recommended)
{
	ScopeProfiler sp2(g_profiler, "MobV2SAO::step avg", SPT_AVG);

	assert(m_env);
	Map *map = &m_env->getMap();

	m_age += dtime;

	if(m_die_age >= 0.0 && m_age >= m_die_age){
		m_removed = true;
		return;
	}

	m_random_disturb_timer += dtime;
	if(m_random_disturb_timer >= 5.0)
	{
		m_random_disturb_timer = 0;
		// Check connected players
		core::list<Player*> players = m_env->getPlayers(true);
		core::list<Player*>::Iterator i;
		for(i = players.begin();
				i != players.end(); i++)
		{
			Player *player = *i;
			v3f playerpos = player->getPosition();
			f32 dist = m_base_position.getDistanceFrom(playerpos);
			if(dist < BS*16)
			{
				if(myrand_range(0,3) == 0){
					actionstream<<"Mob id="<<m_id<<" at "
							<<PP(m_base_position/BS)
							<<" got randomly disturbed by "
							<<player->getName()<<std::endl;
					m_disturbing_player = player->getName();
					m_disturb_timer = 0;
					break;
				}
			}
		}
	}

	Player *disturbing_player =
			m_env->getPlayer(m_disturbing_player.c_str());
	v3f disturbing_player_off = v3f(0,1,0);
	v3f disturbing_player_norm = v3f(0,1,0);
	float disturbing_player_distance = 1000000;
	float disturbing_player_dir = 0;
	if(disturbing_player){
		disturbing_player_off =
				disturbing_player->getPosition() - m_base_position;
		disturbing_player_distance = disturbing_player_off.getLength();
		disturbing_player_norm = disturbing_player_off;
		disturbing_player_norm.normalize();
		disturbing_player_dir = 180./PI*atan2(disturbing_player_norm.Z,
				disturbing_player_norm.X);
	}

	m_disturb_timer += dtime;
	
	if(!m_falling)
	{
		m_shooting_timer -= dtime;
		if(m_shooting_timer <= 0.0 && m_shooting){
			m_shooting = false;
			
			std::string shoot_type = m_properties->get("shoot_type");
			v3f shoot_pos(0,0,0);
			shoot_pos.Y += m_properties->getFloat("shoot_y") * BS;
			if(shoot_type == "fireball"){
				v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
				dir.Y = m_shoot_y;
				dir.normalize();
				v3f speed = dir * BS * 10.0;
				v3f pos = m_base_position + shoot_pos;
				infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
						<<" shooting fireball from "<<PP(pos)
						<<" at speed "<<PP(speed)<<std::endl;
				Settings properties;
				properties.set("looks", "fireball");
				properties.setV3F("speed", speed);
				properties.setFloat("die_age", 5.0);
				properties.set("move_type", "constant_speed");
				properties.setFloat("hp", 1000);
				properties.set("lock_full_brightness", "true");
				properties.set("player_hit_damage", "9");
				properties.set("player_hit_distance", "2");
				properties.set("player_hit_interval", "1");
				ServerActiveObject *obj = new MobV2SAO(m_env,
						pos, &properties);
				//m_env->addActiveObjectAsStatic(obj);
				m_env->addActiveObject(obj);
			} else {
				infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
						<<": Unknown shoot_type="<<shoot_type
						<<std::endl;
			}
		}

		m_shoot_reload_timer += dtime;

		float reload_time = 15.0;
		if(m_disturb_timer <= 15.0)
			reload_time = 3.0;

		bool shoot_without_player = false;
		if(m_properties->getBool("mindless_rage"))
			shoot_without_player = true;

		if(!m_shooting && m_shoot_reload_timer >= reload_time &&
				!m_next_pos_exists &&
				(m_disturb_timer <= 60.0 || shoot_without_player))
		{
			m_shoot_y = 0;
			if(m_disturb_timer < 60.0 && disturbing_player &&
					disturbing_player_distance < 16*BS &&
					fabs(disturbing_player_norm.Y) < 0.8){
				m_yaw = disturbing_player_dir;
				sendPosition();
				m_shoot_y += disturbing_player_norm.Y;
			} else {
				m_shoot_y = 0.01 * myrand_range(-30,10);
			}
			m_shoot_reload_timer = 0.0;
			m_shooting = true;
			m_shooting_timer = 1.5;
			{
				std::ostringstream os(std::ios::binary);
				// command (2 = shooting)
				writeU8(os, 2);
				// time
				writeF1000(os, m_shooting_timer + 0.1);
				// bright?
				writeU8(os, true);
				// create message and add to list
				ActiveObjectMessage aom(getId(), false, os.str());
				m_messages_out.push_back(aom);
			}
		}
	}
	
	if(m_move_type == "ground_nodes")
	{
		if(!m_shooting){
			m_walk_around_timer -= dtime;
			if(m_walk_around_timer <= 0.0){
				m_walk_around = !m_walk_around;
				if(m_walk_around)
					m_walk_around_timer = 0.1*myrand_range(10,50);
				else
					m_walk_around_timer = 0.1*myrand_range(30,70);
			}
		}

		/* Move */
		if(m_next_pos_exists){
			v3f pos_f = m_base_position;
			v3f next_pos_f = intToFloat(m_next_pos_i, BS);

			v3f v = next_pos_f - pos_f;
			m_yaw = atan2(v.Z, v.X) / PI * 180;
			
			v3f diff = next_pos_f - pos_f;
			v3f dir = diff;
			dir.normalize();
			float speed = BS * 0.5;
			if(m_falling)
				speed = BS * 3.0;
			dir *= dtime * speed;
			bool arrived = false;
			if(dir.getLength() > diff.getLength()){
				dir = diff;
				arrived = true;
			}
			pos_f += dir;
			m_base_position = pos_f;

			if((pos_f - next_pos_f).getLength() < 0.1 || arrived){
				m_next_pos_exists = false;
			}
		}

		v3s16 pos_i = floatToInt(m_base_position, BS);
		v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
		v3s16 pos_size_off(0,0,0);
		if(m_size.X >= 2.5){
			pos_size_off.X = -1;
			pos_size_off.Y = -1;
		}
		
		if(!m_next_pos_exists){
			/* Check whether to drop down */
			if(checkFreePosition(map,
					pos_i + pos_size_off + v3s16(0,-1,0), size_blocks)){
				m_next_pos_i = pos_i + v3s16(0,-1,0);
				m_next_pos_exists = true;
				m_falling = true;
			} else {
				m_falling = false;
			}
		}

		if(m_walk_around)
		{
			if(!m_next_pos_exists){
				/* Find some position where to go next */
				v3s16 dps[3*3*3];
				int num_dps = 0;
				for(int dx=-1; dx<=1; dx++)
				for(int dy=-1; dy<=1; dy++)
				for(int dz=-1; dz<=1; dz++){
					if(dx == 0 && dy == 0)
						continue;
					if(dx != 0 && dz != 0 && dy != 0)
						continue;
					dps[num_dps++] = v3s16(dx,dy,dz);
				}
				u32 order[3*3*3];
				get_random_u32_array(order, num_dps);
				for(int i=0; i<num_dps; i++){
					v3s16 p = dps[order[i]] + pos_i;
					bool is_free = checkFreeAndWalkablePosition(map,
							p + pos_size_off, size_blocks);
					if(!is_free)
						continue;
					m_next_pos_i = p;
					m_next_pos_exists = true;
					break;
				}
			}
		}
	}
	else if(m_move_type == "constant_speed")
	{
		m_base_position += m_speed * dtime;
		
		v3s16 pos_i = floatToInt(m_base_position, BS);
		v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
		v3s16 pos_size_off(0,0,0);
		if(m_size.X >= 2.5){
			pos_size_off.X = -1;
			pos_size_off.Y = -1;
		}
		bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks);
		if(!free){
			explodeSquare(map, pos_i, v3s16(3,3,3));
			m_removed = true;
			return;
		}
	}
	else
	{
		errorstream<<"MobV2SAO::step(): id="<<m_id<<" unknown move_type=\""
				<<m_move_type<<"\""<<std::endl;
	}

	if(send_recommended == false)
		return;

	if(m_base_position.getDistanceFrom(m_last_sent_position) > 0.05*BS)
	{
		sendPosition();
	}
}
Beispiel #28
0
//---------------------------------------------------------------------------
// ● フレーム更新処理 (オブジェクトに影響を与える処理)
//---------------------------------------------------------------------------
bool Valfirle::UpdateSelf()
{
	//死んだ際に持っている武器を落とす
	if(this->mLife <= 0 && !this->m_bCreateWeapon)
	{
		this->m_bCreateWeapon = true;
	}

	bool right = false;
	bool left  = false;
	bool button_A  = false;
	bool button_B  = false;
	bool Up = false;
	bool UpTrigger = false;
	bool Down = false;
	bool DownTrigger = false;
	bool Guard = false;
	bool GuardTrigger = false;

	Player *pPlayer = GameManager::getInstance()->getPlayer();

	//AI
	switch(this->m_eAction)
	{
	//未定義
	case ENEMY_ACT_UNDEF:
		this->m_eAction = ENEMY_ACT_WAIT;
		break;

	//待機
	case ENEMY_ACT_WAIT:
		//フェーズの移行をチェックする
		this->ChangePhase();

		//範囲内探索を行う
		if(this->SearchPlayer())
		{
			//範囲内であれば追跡を開始する
			this->m_eAction = ENEMY_ACT_CHASE;
			break;
		}

		//散歩を開始する
		if(this->m_nWalkIntvCnt > this->scm_nWalkIntv)
		{
			this->m_nWalkRangeCnt = ::rand() % this->scm_nWalkRange; //散歩距離の設定
			this->m_nWalkIntvCnt = 0;
			this->m_bWalkDir = static_cast<bool>(::rand() % 2);
			this->m_eAction = ENEMY_ACT_WALK;
		}
		else
		{
			++this->m_nWalkIntvCnt;
		}
		break;

	//散歩
	case ENEMY_ACT_WALK:
		//散歩を行っている
		if(this->m_nWalkRangeCnt)
		{
			if(this->m_bWalkDir)
				right = true;
			else
				left = true;

			--this->m_nWalkRangeCnt;
		}
		//散歩終わり
		else
		{
			this->m_eAction = ENEMY_ACT_WAIT;
		}
		break;

	//追跡
	case ENEMY_ACT_CHASE:
		//フェーズの移行をチェックする
		this->ChangePhase();

		//プレイヤーが探索範囲内である
		if(this->SearchPlayer())
		{
			//Playerは右にいる
			if(this->mPosition.x - pPlayer->getPosition().x < 0)
			{
				right = true;
			}
			//Playerは左にいる
			else
			{
				left = true;
			}

			//まれにジャンプする
			if(!(::rand() % scg_nValfirleJumpRatio[GameManager::getInstance()->getRank()]))
			{
				button_B = true;
			}

			//プレイヤーが観察範囲内である
			if(::abs(this->mPosition.x + ::rand() % this->scm_nSearchRand - pPlayer->getPosition().x) <= this->scm_nStandbyRange)
			{
				//ランダムで観察を開始する
				if(!(::rand() % scg_nValfirleStandbyRatio[GameManager::getInstance()->getRank()]))
				{
					this->m_nStandbyCnt = ::rand() % this->scm_nStandbyIntv;
					this->m_eAction = ENEMY_ACT_STANDBY;
					break;
				}
			}

			//プレイヤーが攻撃範囲内である
			if(this->SearchAttack1Range())
			{
				this->m_eAction = ENEMY_ACT_ATTACK_RANGE;
				break;
			}
		}
		else
		{
			//探索範囲外であれば待機に戻す
			this->m_eAction = ENEMY_ACT_WAIT;
		}
		break;

	//観察
	case ENEMY_ACT_STANDBY:
		//プレイヤーがジャンプした瞬間対空攻撃を行う
		if(pPlayer->getCharaState() == CHARASTATE_JUMP)
		{
			//this->m_nStandbyCnt = 0;
			break;
		}

		//観察を行う
		if(this->m_nStandbyCnt)
		{
			--this->m_nStandbyCnt;
		}
		else
		{
			this->m_eAction = ENEMY_ACT_WAIT;
		}
		break;

	//逃走
	case ENEMY_ACT_ESCAPE:
		if(this->m_nEscapeRangeCnt)
		{
			//Playerは右にいる
			if(this->mPosition.x - pPlayer->getPosition().x < 0)
			{
				left = true;
			}
			//Playerは左にいる
			else
			{
				right = true;
			}

			--this->m_nEscapeRangeCnt;
		}
		else
		{
			this->m_eAction = ENEMY_ACT_WAIT;
		}
		break;

	//攻撃範囲内
	case ENEMY_ACT_ATTACK_RANGE:
		if(this->SearchAttack1Range())
		{
			//ランダムで攻撃を開始する
			if(!(::rand() % scg_nValfirleAttackRatio[GameManager::getInstance()->getRank()]))
			{
				this->m_eAction = ENEMY_ACT_ATTACK;
				break;
			}
			//ランダムで防御を開始する
			if(!(::rand() % scg_nValfirleGuardRatio[GameManager::getInstance()->getRank()]))
			{
				this->m_nGuardCnt = ::rand() % this->scm_nGuardIntv;
				this->m_eAction = ENEMY_ACT_GUARD;
				break;
			}
			//ランダムで観察を開始する
			if(!(::rand() % scg_nValfirleStandbyRatio[GameManager::getInstance()->getRank()]))
			{
				this->m_nStandbyCnt = ::rand() % this->scm_nStandbyIntv;
				this->m_eAction = ENEMY_ACT_STANDBY;
				break;
			}
			//ランダムでしゃがみガードを開始する
			if(!(::rand() % scg_nValfirleSquatGuardRatio[GameManager::getInstance()->getRank()]))
			{
				this->m_nGuardCnt = ::rand() % this->scm_nGuardIntv;
				this->m_eAction = ENEMY_ACT_SQUAT_GUARD;
				break;
			}
			//ランダムでしゃがみを開始する
			if(!(::rand() % scg_nValfirleSquatRatio[GameManager::getInstance()->getRank()]))
			{
				this->m_nSquatCnt = ::rand() % this->scm_nStandbyIntv;
				this->m_eAction = ENEMY_ACT_SQUAT;
				break;
			}
			//ランダムで逃走を開始する
			if(!(::rand() % scg_nValfirleEscapeRatio[GameManager::getInstance()->getRank()]))
			{
				this->m_nEscapeRangeCnt = ::rand() % this->scm_nEscapeRange;
				this->m_eAction = ENEMY_ACT_ESCAPE;
				break;
			}
		}
		//攻撃範囲外
		else
		{
			this->m_eAction = ENEMY_ACT_CHASE;
		}
		break;

	//攻撃中
	case ENEMY_ACT_ATTACK:
		if(this->SearchAttack1Range())
		{
			switch(this->m_eCharaState)
			{
			case CHARASTATE_ATTACK_SQUAT_ATTACK:
			case CHARASTATE_ATTACK_JUMP_ATTACK:
			case CHARASTATE_ATTACK_ANTIAIR_ATTACK:
			case CHARASTATE_ATTACK_DUSH_ATTACK:
				//特殊攻撃後は待機に戻す
				this->m_eAction = ENEMY_ACT_WAIT;
				break;

			case CHARASTATE_ATTACK_1:
				//通常攻撃2段目
				if(scg_bValfirleAttack2Permission[GameManager::getInstance()->getRank()] && (::rand() % scg_nValfirleAttack2Ratio[GameManager::getInstance()->getRank()]))
					button_A = true;
				else
					this->m_eAction = ENEMY_ACT_WAIT;
				break;

			case CHARASTATE_ATTACK_2:
				//通常攻撃3段目
				if(scg_bValfirleAttack3Permission[GameManager::getInstance()->getRank()] && (::rand() % scg_nValfirleAttack3Ratio[GameManager::getInstance()->getRank()]))
					button_A = true;
				else
					this->m_eAction = ENEMY_ACT_WAIT;
				break;

			default:
				//ジャンプ攻撃は事前にジャンプする
				if(!(::rand() % scg_nValfirleJumpAttackRatio[GameManager::getInstance()->getRank()]))
				{
					button_B = true;
					break;
				}
				//しゃがみ攻撃
				if(!(::rand() % scg_nValfirleSquatAttackRatio[GameManager::getInstance()->getRank()]))
				{
					Down = true;
				}

				//通常攻撃1段目
				button_A = true;

				break;
			}

			//Player座標が上であれば、対空攻撃をする
			if(this->mPosition.y < pPlayer->getPosition().y)
			{
				Up = true;
			}
		}
		else
		{
			this->m_eAction = ENEMY_ACT_CHASE;
		}
		break;

	//防御
	case ENEMY_ACT_GUARD:
		if(this->m_nGuardCnt)
		{
			Guard = true;
			--this->m_nGuardCnt;
		}
		else
		{
			this->m_eAction = ENEMY_ACT_WAIT;
		}
		break;

	//しゃがみガード
	case ENEMY_ACT_SQUAT_GUARD:
		if(this->m_nGuardCnt)
		{
			GuardTrigger = true;
			Guard = true;
			Down = true;
			--this->m_nGuardCnt;
		}
		else
		{
			this->m_eAction = ENEMY_ACT_WAIT;
		}
		break;

	//しゃがみ
	case ENEMY_ACT_SQUAT:
		if(this->m_nSquatCnt)
		{
			Down = true;
			--this->m_nSquatCnt;
		}
		else
		{
			this->m_eAction = ENEMY_ACT_WAIT;
		}
		break;

	default:
		this->m_eAction = ENEMY_ACT_WAIT;
		break;
	}
	//AI end

    // 死亡 (死亡モーション中) は入力を受け付けない
    if ( isDead() )
    {
        return true;
    }

    // 移動できる場合 (のけぞり中等ではない)
    if ( mStunFrame == 0 )
    {
        //------------------------------------------------------
        // 攻撃動作中の場合
        if ( isAttacking() )
        {
			// 行動制限解除(=出し終わり)してないと操作不可
			if ( !mAttackLocked )
			{
				// 連続攻撃
				if ( button_A )
				{
					// 行動制限
					this->AttackLock();

					switch( m_eCharaState )
					{
					case CHARASTATE_ATTACK_1:
						if(scg_bValfirleAttack2Permission[GameManager::getInstance()->getRank()])
							getManager()->postEvent( getHandle(), EV_ACTION_ATTACK_2, NULL, 0 );
						break;

					case CHARASTATE_ATTACK_2:
						if(scg_bValfirleAttack3Permission[GameManager::getInstance()->getRank()])
							getManager()->postEvent( getHandle(), EV_ACTION_ATTACK_3, NULL, 0 );
						break;

					default:
						// 万が一おかしい値になったらロック解除
						this->AttackUnLock();
						break;
					}
				}
			}
        }
        //------------------------------------------------------
        // 攻撃動作中ではない場合
        else
        {
			
			// 攻撃開始
            if ( button_A && m_eCharaState != EV_ACTION_ATTACK_1 )  // 後ろのは仮
            {
                // ジャンプ中の場合
                if ( mJump )
                {
					this->AttackLock();
					getManager()->postEvent( getHandle(), EV_ACTION_ATTACK_JUMP_ATTACK, NULL, 0 );
                }
                // しゃがみ中の場合
                else if ( Down )
                {
					this->AttackLock();
					getManager()->postEvent( getHandle(), EV_ACTION_ATTACK_SQUAT_ATTACK, NULL, 0 );
                }
				// 上を押しながらの場合
				else if ( !mTouchLadder && Up )
				{
					this->AttackLock();
					getManager()->postEvent( getHandle(), EV_ACTION_ATTACK_ANTIAIR_ATTACK, NULL, 0 );
					this->m_nAttackDelay = 0;
				}
                // 以上以外は通常攻撃
                else
                {
					// 攻撃のため行動制限
					if(scg_bValfirleAttack1Permission[GameManager::getInstance()->getRank()])
					{
						this->AttackLock();
						getManager()->postEvent( getHandle(), EV_ACTION_ATTACK_1, NULL, 0 );
					}
                }

                return true;
            }

			// ガード
			if ( !Down && Guard && mOnGround && !mClimbLadder && m_eCharaState != CHARASTATE_GUARD )
			{
				getManager()->postEvent( getHandle(), EV_ACTION_GUARD, NULL, 0 );
				return true;
			}

			// 向きを変えるための処理
			if ( right )
			{
				setDirection( CHARADIR_RIGHT );
			}
			else if ( left )
			{
				setDirection( CHARADIR_LEFT );
			}

			// 右移動
			//if ( !mClimbLadder && right && ( m_eCharaState != CHARASTATE_RUN || m_eDirection != CHARADIR_RIGHT ) )
			//{
			//	// 方向をつけて EV_ACTION_RUN イベントを送る。
			//	// このあと、HandleEvent() で実際に移動を開始する。
			//	// このイベントはキューイングせず、即座に HandleEvent() に送られる。
			//	//u32 dir = CHARADIR_RIGHT;

			//	if ( !Down )
			//		getManager()->postEvent( getHandle(), EV_ACTION_RUN, NULL, 0 );
			//		// getManager()->postEvent( getHandle(), EV_ACTION_RUN, &dir, sizeof( u32 ) );
			//}
			//// 左移動
			//else if( !mClimbLadder && left && ( m_eCharaState != CHARASTATE_RUN || m_eDirection != CHARADIR_LEFT ) )
			//{
			//	//u32 dir = CHARADIR_LEFT;

			// 移動
			if ( ( !Guard && !this->mClimbLadder && right && !left && ( m_eCharaState != CHARASTATE_RUN || m_eDirection != CHARADIR_RIGHT ) )
				|| ( !Guard && !this->mClimbLadder && left && !right && ( m_eCharaState != CHARASTATE_RUN || m_eDirection != CHARADIR_LEFT ) ) )
			{
				if ( !Down )
					getManager()->postEvent( getHandle(), EV_ACTION_RUN, NULL, 0 );
			}
			// 左右のいずれも押されていない場合は待機にする
			// 梯子離したときも待機で。
			// (後ろの mState != CHARASTATE_WAIT は、待機中に連続でイベントが送られないようにするために必要)
			else if ( ( !Guard && this->mOnGround && ( ( !right && !left ) || ( right && left ) ) && !Down && !this->mClimbLadder && m_eCharaState != CHARASTATE_WAIT )
				|| this->mNewTouchObj != OBJ_LADDER && this->mOldTouchObj == OBJ_LADDER && m_eCharaState != CHARASTATE_WAIT && m_eCharaState != CHARASTATE_JUMP && m_eCharaState != CHARASTATE_RUN )
			{
				getManager()->postEvent( getHandle(), EV_ACTION_WAIT, NULL, 0 );
			}

			// ジャンプ開始
			if ( button_B && m_eCharaState != CHARASTATE_JUMP && ( this->mOnGround || this->mClimbLadder ) )
			{
				getManager()->postEvent( getHandle(), EV_ACTION_JUMP, NULL, 0 );
				return true;
			}

			// しゃがみ開始
			if ( Down && this->mOnGround && !this->mTouchLadder )
			{
				// しゃがみながらガードした場合
				// ガードしながらしゃがんだ場合
				if ( ( ( GuardTrigger ) || ( DownTrigger && Guard ) ) && m_eCharaState != CHARASTATE_SQGUARD )
				{
					getManager()->postEvent( getHandle(), EV_ACTION_SQUAT_GUARD, NULL, 0 );
				}
				else if ( !Guard && m_eCharaState != CHARASTATE_SQUAT )
				{
					getManager()->postEvent( getHandle(), EV_ACTION_SQUAT, NULL, 0 );
				}
			}

			// はしごつかみ
			if ( mTouchLadder
				&& m_eCharaState != CHARASTATE_LADDER_UP
				&& m_eCharaState != CHARASTATE_LADDER_DOWN
				&& m_eCharaState != CHARASTATE_LADDER_WAIT )
			{
				bool Catch = false;

				if ( UpTrigger && mDistance.y > 0 )
					Catch = true;

				if ( DownTrigger && mDistance.y < 0 )
					Catch = true;

				if ( Catch )
				{
					this->mPosition.set(
						mPosition.x + mDistance.x,
						mPosition.y,
						mPosition.z
						);
					mClimbLadder = true;
				}
			}

			// はしご上昇
			if ( Up && m_eCharaState != CHARASTATE_LADDER_UP && mClimbLadder )
			{
				getManager()->postEvent( getHandle(), EV_ACTION_LADDER_UP, NULL, 0 );

				return true;
			}
			// はしご下降
			else if ( Down && m_eCharaState != CHARASTATE_LADDER_DOWN && mClimbLadder )
			{
				getManager()->postEvent( getHandle(), EV_ACTION_LADDER_DOWN, NULL, 0 );

				return true;
			}
			// はしご待機
			else if ( !Up && !Down && mClimbLadder && m_eCharaState != CHARASTATE_LADDER_WAIT )
			{
				getManager()->postEvent( getHandle(), EV_ACTION_LADDER_WAIT, NULL, 0 );

				return true;
			}
        }
    }

    return true;
}
void Server::ProcessData(NetworkPacket *pkt)
{
	DSTACK(__FUNCTION_NAME);
	// Environment is locked first.
	//JMutexAutoLock envlock(m_env_mutex);

	ScopeProfiler sp(g_profiler, "Server::ProcessData");

	auto peer_id = pkt->getPeerId();

	std::string addr_s;
	try{
		Address address = getPeerAddress(peer_id);
		addr_s = address.serializeString();

		// drop player if is ip is banned
		if(m_banmanager->isIpBanned(addr_s)){
			std::string ban_name = m_banmanager->getBanName(addr_s);
			infostream<<"Server: A banned client tried to connect from "
					<<addr_s<<"; banned name was "
					<<ban_name<<std::endl;
			// This actually doesn't seem to transfer to the client
			DenyAccess(peer_id, std::string("Your ip is banned. Banned name was ") + ban_name);
			return;
		}
	}
	catch(con::PeerNotFoundException &e)
	{
		/*
		 * no peer for this packet found
		 * most common reason is peer timeout, e.g. peer didn't
		 * respond for some time, your server was overloaded or
		 * things like that.
		 */
		verbosestream<<"Server::ProcessData(): Canceling: peer "
				<<peer_id<<" not found"<<std::endl;
		return;
	}

	try
	{

	auto datasize = pkt->getSize();

	if(datasize < 2)
		return;

	int command;
	std::map<int, msgpack::object> packet;
	msgpack::unpacked msg;
	if (!con::parse_msgpack_packet(pkt->getString(0), datasize, &packet, &command, &msg)) {
		verbosestream<<"Server: Ignoring broken packet from " <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
		return;
	}

	if(command == TOSERVER_INIT_LEGACY)
	{
		RemoteClient* client = getClient(peer_id, CS_Created);

		// If net_proto_version is set, this client has already been handled
		if(client->getState() > CS_Created)
		{
			verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
					<<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
			return;
		}

		verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
				<<peer_id<<")"<<std::endl;

		// Do not allow multiple players in simple singleplayer mode.
		// This isn't a perfect way to do it, but will suffice for now
		if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
			infostream<<"Server: Not allowing another client ("<<addr_s
					<<") to connect in simple singleplayer mode"<<std::endl;
			DenyAccess(peer_id, "Running in simple singleplayer mode.");
			return;
		}

		// First byte after command is maximum supported
		// serialization version
		u8 client_max;
		packet[TOSERVER_INIT_FMT].convert(&client_max);
		u8 our_max = SER_FMT_VER_HIGHEST_READ;
		// Use the highest version supported by both
		int deployed = std::min(client_max, our_max);
		// If it's lower than the lowest supported, give up.
		if(deployed < SER_FMT_CLIENT_VER_LOWEST)
			deployed = SER_FMT_VER_INVALID;

		if(deployed == SER_FMT_VER_INVALID)
		{
			actionstream<<"Server: A mismatched client tried to connect from "
					<<addr_s<<std::endl;
			infostream<<"Server: Cannot negotiate serialization version with "
					<<addr_s<<std::endl;
			DenyAccess(peer_id, std::string(
					"Your client's version is not supported.\n"
					"Server version is ")
					+ (g_version_string) + "."
			);
			return;
		}

		client->setPendingSerializationVersion(deployed);

		/*
			Read and check network protocol version
		*/

		u16 min_net_proto_version = 0;
		packet[TOSERVER_INIT_PROTOCOL_VERSION_MIN].convert(&min_net_proto_version);
		u16 max_net_proto_version = min_net_proto_version;
		packet[TOSERVER_INIT_PROTOCOL_VERSION_MAX].convert(&max_net_proto_version);

		// Start with client's maximum version
		u16 net_proto_version = max_net_proto_version;

		// Figure out a working version if it is possible at all
		if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
				min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
		{
			// If maximum is larger than our maximum, go with our maximum
			if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
				net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
			// Else go with client's maximum
			else
				net_proto_version = max_net_proto_version;
		}

		verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
				<<min_net_proto_version<<", max: "<<max_net_proto_version
				<<", chosen: "<<net_proto_version<<std::endl;

		client->net_proto_version = net_proto_version;

		if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
				net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
		{
			actionstream<<"Server: A mismatched client tried to connect from "
					<<addr_s<<std::endl;
			DenyAccess(peer_id, std::string(
					"Your client's version is not supported.\n"
					"Server version is ")
					+ (g_version_string) + ",\n"
					+ "server's PROTOCOL_VERSION is "
					+ itos(SERVER_PROTOCOL_VERSION_MIN)
					+ "..."
					+ itos(SERVER_PROTOCOL_VERSION_MAX)
					+ ", client's PROTOCOL_VERSION is "
					+ itos(min_net_proto_version)
					+ "..."
					+ itos(max_net_proto_version)
			);
			return;
		}

		if(g_settings->getBool("strict_protocol_version_checking"))
		{
			if(net_proto_version != LATEST_PROTOCOL_VERSION)
			{
				actionstream<<"Server: A mismatched (strict) client tried to "
						<<"connect from "<<addr_s<<std::endl;
				DenyAccess(peer_id, std::string(
						"Your client's version is not supported.\n"
						"Server version is ")
						+ (g_version_string) + ",\n"
						+ "server's PROTOCOL_VERSION (strict) is "
						+ itos(LATEST_PROTOCOL_VERSION)
						+ ", client's PROTOCOL_VERSION is "
						+ itos(min_net_proto_version)
						+ "..."
						+ itos(max_net_proto_version)
				);
				return;
			}
		}

		/*
			Set up player
		*/

		// Get player name
		std::string playername;
		packet[TOSERVER_INIT_NAME].convert(&playername);

		if(playername.empty())
		{
			actionstream<<"Server: Player with an empty name "
					<<"tried to connect from "<<addr_s<<std::endl;
			DenyAccess(peer_id, "Empty name");
			return;
		}

		if(!g_settings->getBool("enable_any_name") && string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
		{
			actionstream<<"Server: Player with an invalid name ["<<playername
					<<"] tried to connect from "<<addr_s<<std::endl;
			DenyAccess(peer_id, "Name contains unallowed characters");
			return;
		}

		if(!isSingleplayer() && playername == "singleplayer")
		{
			actionstream<<"Server: Player with the name \"singleplayer\" "
					<<"tried to connect from "<<addr_s<<std::endl;
			DenyAccess(peer_id, "Name is not allowed");
			return;
		}

		{
			std::string reason;
			if(m_script->on_prejoinplayer(playername, addr_s, reason))
			{
				actionstream<<"Server: Player with the name \""<<playername<<"\" "
						<<"tried to connect from "<<addr_s<<" "
						<<"but it was disallowed for the following reason: "
						<<reason<<std::endl;
				DenyAccess(peer_id, reason);
				return;
			}
		}

		infostream<<"Server: New connection: \""<<playername<<"\" from "
				<<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;

		// Get password
		std::string given_password;
		packet[TOSERVER_INIT_PASSWORD].convert(&given_password);

		if(!base64_is_valid(given_password.c_str())){
			actionstream<<"Server: "<<playername
					<<" supplied invalid password hash"<<std::endl;
			DenyAccess(peer_id, "Invalid password hash");
			return;
		}

		// Enforce user limit.
		// Don't enforce for users that have some admin right
		if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
				!checkPriv(playername, "server") &&
				!checkPriv(playername, "ban") &&
				!checkPriv(playername, "privs") &&
				!checkPriv(playername, "password") &&
				playername != g_settings->get("name"))
		{
			actionstream<<"Server: "<<playername<<" tried to join, but there"
					<<" are already max_users="
					<<g_settings->getU16("max_users")<<" players."<<std::endl;
			DenyAccess(peer_id, "Too many users.");
			return;
		}

		std::string checkpwd; // Password hash to check against
		bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);

		// If no authentication info exists for user, create it
		if(!has_auth){
			if(!isSingleplayer() &&
					g_settings->getBool("disallow_empty_password") &&
					given_password == ""){
				actionstream<<"Server: "<<playername
						<<" supplied empty password"<<std::endl;
				DenyAccess(peer_id, "Empty passwords are "
						"disallowed. Set a password and try again.");
				return;
			}
			std::string raw_default_password = g_settings->get("default_password");
			std::string initial_password =
				translatePassword(playername, raw_default_password);

			// If default_password is empty, allow any initial password
			if (raw_default_password.length() == 0)
				initial_password = given_password;

			m_script->createAuth(playername, initial_password);
		}

		has_auth = m_script->getAuth(playername, &checkpwd, NULL);

		if(!has_auth){
			actionstream<<"Server: "<<playername<<" cannot be authenticated"
					<<" (auth handler does not work?)"<<std::endl;
			DenyAccess(peer_id, "Not allowed to login");
			return;
		}

		if(given_password != checkpwd){
			actionstream<<"Server: "<<playername<<" supplied wrong password"
					<<std::endl;
			DenyAccess(peer_id, "Wrong password");
			return;
		}

		RemotePlayer *player =
				static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));

		if(player && player->peer_id != 0){
			errorstream<<"Server: "<<playername<<": Failed to emerge player"
					<<" (player allocated to an another client)"<<std::endl;
			DenyAccess(peer_id, "Another client is connected with this "
					"name. If your client closed unexpectedly, try again in "
					"a minute.");
		}

		m_clients.setPlayerName(peer_id,playername);

		/*
			Answer with a TOCLIENT_INIT
		*/
		{
			MSGPACK_PACKET_INIT(TOCLIENT_INIT, 4);
			PACK(TOCLIENT_INIT_DEPLOYED, deployed);
			PACK(TOCLIENT_INIT_SEED, m_env->getServerMap().getSeed());
			PACK(TOCLIENT_INIT_STEP, g_settings->getFloat("dedicated_server_step"));

			//if (player) //todo : remake me
			//	PACK(TOCLIENT_INIT_POS, player->getPosition());

			Settings params;
			m_emerge->params.save(params);
			PACK(TOCLIENT_INIT_MAP_PARAMS, params);

			// Send as reliable
			m_clients.send(peer_id, 0, buffer, true);
			m_clients.event(peer_id, CSE_Init);
		}

		return;
	}

	if(command == TOSERVER_INIT2)
	{
		verbosestream<<"Server: Got TOSERVER_INIT2 from "
				<<peer_id<<std::endl;

		m_clients.event(peer_id, CSE_GotInit2);
		u16 protocol_version = m_clients.getProtocolVersion(peer_id);


		///// begin compatibility code
		PlayerSAO* playersao = NULL;
		if (protocol_version <= 22) {
			playersao = StageTwoClientInit(peer_id);

			if (playersao == NULL) {
				errorstream
					<< "TOSERVER_INIT2 stage 2 client init failed for peer "
					<< peer_id << std::endl;
				return;
			}
		}
		///// end compatibility code

		/*
			Send some initialization data
		*/

		infostream<<"Server: Sending content to "
				<<getPlayerName(peer_id)<<std::endl;

		// Send player movement settings
		SendMovement(peer_id);

		// Send item definitions
		SendItemDef(peer_id, m_itemdef, protocol_version);

		// Send node definitions
		SendNodeDef(peer_id, m_nodedef, protocol_version);

		m_clients.event(peer_id, CSE_SetDefinitionsSent);

		// Send media announcement
		sendMediaAnnouncement(peer_id);

		// Send detached inventories
		sendDetachedInventories(peer_id);

		// Send time of day
		u16 time = m_env->getTimeOfDay();
		float time_speed = g_settings->getFloat("time_speed");
		SendTimeOfDay(peer_id, time, time_speed);

		///// begin compatibility code
		if (protocol_version <= 22) {
			m_clients.event(peer_id, CSE_SetClientReady);
			m_script->on_joinplayer(playersao);
		}
		///// end compatibility code

		// Warnings about protocol version can be issued here
		if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
		{
			SendChatMessage(peer_id, "# Server: WARNING: YOUR CLIENT'S "
					"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
		}

		return;
	}

	u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
	u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;

	if(peer_ser_ver == SER_FMT_VER_INVALID)
	{
		errorstream<<"Server::ProcessData(): Canceling: Peer"
				" serialization format invalid or not initialized."
				" Skipping incoming command="<<command<<std::endl;
		return;
	}

	/* Handle commands relate to client startup */
	if(command == TOSERVER_REQUEST_MEDIA) {
		std::vector<std::string> tosend;
		packet[TOSERVER_REQUEST_MEDIA_FILES].convert(&tosend);

		sendRequestedMedia(peer_id, tosend);
		return;
	}
	else if(command == TOSERVER_RECEIVED_MEDIA) {
		return;
	}
	else if(command == TOSERVER_CLIENT_READY) {
		// clients <= protocol version 22 did not send ready message,
		// they're already initialized
		if (peer_proto_ver <= 22) {
			infostream << "Client sent message not expected by a "
				<< "client using protocol version <= 22,"
				<< "disconnecting peer_id: " << peer_id << std::endl;
			m_con.DisconnectPeer(peer_id);
			return;
		}

		PlayerSAO* playersao = StageTwoClientInit(peer_id);

		// If failed, cancel
		if (playersao == NULL) {
			errorstream
				<< "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
				<< peer_id << std::endl;
			m_con.DisconnectPeer(peer_id);
			return;
		}
		m_clients.setClientVersion(
			peer_id,
			packet[TOSERVER_CLIENT_READY_VERSION_MAJOR].as<int>(),
			packet[TOSERVER_CLIENT_READY_VERSION_MINOR].as<int>(),
			0, // packet[TOSERVER_CLIENT_READY_VERSION_PATCH].as<int>(), TODO
			packet[TOSERVER_CLIENT_READY_VERSION_STRING].as<std::string>()
		);
		m_clients.event(peer_id, CSE_SetClientReady);
		m_script->on_joinplayer(playersao);

		stat.add("join", playersao->getPlayer()->getName());
	}

	if (m_clients.getClientState(peer_id) < CS_Active)
	{
		if (command == TOSERVER_PLAYERPOS) return;

		errorstream<<"Got packet command: " << command << " for peer id "
				<< peer_id << " but client isn't active yet. Dropping packet "
				<<std::endl;
		return;
	}

	Player *player = m_env->getPlayer(peer_id);
	if(player == NULL) {
/*
		verbosestream<<"Server::ProcessData(): Canceling: "
				"No player for peer_id="<<peer_id
				<< " disconnecting peer!" <<std::endl;
*/
		m_con.DisconnectPeer(peer_id);
		return;
	}

	PlayerSAO *playersao = player->getPlayerSAO();
	if(playersao == NULL) {
		errorstream<<"Server::ProcessData(): Canceling: "
				"No player object for peer_id="<<peer_id
				<< " disconnecting peer!" <<std::endl;
		m_con.DisconnectPeer(peer_id);
		return;
	}

	if(command == TOSERVER_PLAYERPOS)
	{
	// If player is dead we don't care of this packet

		if (player->hp != 0 && playersao->m_ms_from_last_respawn > 1000)
		player->setPosition(packet[TOSERVER_PLAYERPOS_POSITION].as<v3f>());
		player->setSpeed(packet[TOSERVER_PLAYERPOS_SPEED].as<v3f>());
		player->setPitch(modulo360f(packet[TOSERVER_PLAYERPOS_PITCH].as<f32>()));
		player->setYaw(modulo360f(packet[TOSERVER_PLAYERPOS_YAW].as<f32>()));
		u32 keyPressed = packet[TOSERVER_PLAYERPOS_KEY_PRESSED].as<u32>();
		player->keyPressed = keyPressed;
		player->control.up = (bool)(keyPressed&1);
		player->control.down = (bool)(keyPressed&2);
		player->control.left = (bool)(keyPressed&4);
		player->control.right = (bool)(keyPressed&8);
		player->control.jump = (bool)(keyPressed&16);
		player->control.aux1 = (bool)(keyPressed&32);
		player->control.sneak = (bool)(keyPressed&64);
		player->control.LMB = (bool)(keyPressed&128);
		player->control.RMB = (bool)(keyPressed&256);

		auto old_pos = playersao->m_last_good_position;
		if(playersao->checkMovementCheat()){
			// Call callbacks
			m_script->on_cheat(playersao, "moved_too_fast");
			SendMovePlayer(peer_id);
		}
		else if (playersao->m_ms_from_last_respawn > 3000) {
			auto dist = (old_pos/BS).getDistanceFrom(playersao->m_last_good_position/BS);
			if (dist)
				stat.add("move", playersao->getPlayer()->getName(), dist);
		}

		if (playersao->m_ms_from_last_respawn > 2000) {
			auto obj = playersao; // copypasted from server step:
			auto uptime = m_uptime.get();
			if (!obj->m_uptime_last)  // not very good place, but minimum modifications
				obj->m_uptime_last = uptime - 0.1;
			if (uptime - obj->m_uptime_last > 0.5) {
				obj->step(uptime - obj->m_uptime_last, true); //todo: maybe limit count per time
				obj->m_uptime_last = uptime;
			}
		}

		/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
															<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
															<<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
	}
	else if(command == TOSERVER_DELETEDBLOCKS)
	{
		std::vector<v3s16> deleted_blocks;
		packet[TOSERVER_DELETEDBLOCKS_DATA].convert(&deleted_blocks);
		RemoteClient *client = getClient(peer_id);
		for (auto &block : deleted_blocks)
			client->SetBlockDeleted(block);
	}
	else if(command == TOSERVER_INVENTORY_ACTION)
	{
		std::string datastring;
		packet[TOSERVER_INVENTORY_ACTION_DATA].convert(&datastring);
		std::istringstream is(datastring, std::ios_base::binary);
		// Create an action
		InventoryAction *a = InventoryAction::deSerialize(is);
		if(a == NULL)
		{
			infostream<<"TOSERVER_INVENTORY_ACTION: "
					<<"InventoryAction::deSerialize() returned NULL"
					<<std::endl;
			return;
		}

		// If something goes wrong, this player is to blame
		RollbackScopeActor rollback_scope(m_rollback,
				std::string("player:")+player->getName());

		/*
			Note: Always set inventory not sent, to repair cases
			where the client made a bad prediction.
		*/

		/*
			Handle restrictions and special cases of the move action
		*/
		if(a->getType() == IACTION_MOVE)
		{
			IMoveAction *ma = (IMoveAction*)a;

			ma->from_inv.applyCurrentPlayer(player->getName());
			ma->to_inv.applyCurrentPlayer(player->getName());

			setInventoryModified(ma->from_inv, false);
			setInventoryModified(ma->to_inv, false);

			bool from_inv_is_current_player =
				(ma->from_inv.type == InventoryLocation::PLAYER) &&
				(ma->from_inv.name == player->getName());

			bool to_inv_is_current_player =
				(ma->to_inv.type == InventoryLocation::PLAYER) &&
				(ma->to_inv.name == player->getName());

			/*
				Disable moving items out of craftpreview
			*/
			if(ma->from_list == "craftpreview")
			{
				infostream<<"Ignoring IMoveAction from "
						<<(ma->from_inv.dump())<<":"<<ma->from_list
						<<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
						<<" because src is "<<ma->from_list<<std::endl;
				delete a;
				return;
			}

			/*
				Disable moving items into craftresult and craftpreview
			*/
			if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
			{
				infostream<<"Ignoring IMoveAction from "
						<<(ma->from_inv.dump())<<":"<<ma->from_list
						<<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
						<<" because dst is "<<ma->to_list<<std::endl;
				delete a;
				return;
			}

			// Disallow moving items in elsewhere than player's inventory
			// if not allowed to interact
			if(!checkPriv(player->getName(), "interact") &&
					(!from_inv_is_current_player ||
					!to_inv_is_current_player))
			{
				infostream<<"Cannot move outside of player's inventory: "
						<<"No interact privilege"<<std::endl;
				delete a;
				return;
			}
		}
		/*
			Handle restrictions and special cases of the drop action
		*/
		else if(a->getType() == IACTION_DROP)
		{
			IDropAction *da = (IDropAction*)a;

			da->from_inv.applyCurrentPlayer(player->getName());

			setInventoryModified(da->from_inv, false);

			/*
				Disable dropping items out of craftpreview
			*/
			if(da->from_list == "craftpreview")
			{
				infostream<<"Ignoring IDropAction from "
						<<(da->from_inv.dump())<<":"<<da->from_list
						<<" because src is "<<da->from_list<<std::endl;
				delete a;
				return;
			}

			// Disallow dropping items if not allowed to interact
			if(!checkPriv(player->getName(), "interact"))
			{
				delete a;
				return;
			}
			stat.add("drop", player->getName());
		}
		/*
			Handle restrictions and special cases of the craft action
		*/
		else if(a->getType() == IACTION_CRAFT)
		{
			ICraftAction *ca = (ICraftAction*)a;

			ca->craft_inv.applyCurrentPlayer(player->getName());

			setInventoryModified(ca->craft_inv, false);

			//bool craft_inv_is_current_player =
			//	(ca->craft_inv.type == InventoryLocation::PLAYER) &&
			//	(ca->craft_inv.name == player->getName());

			// Disallow crafting if not allowed to interact
			if(!checkPriv(player->getName(), "interact"))
			{
				infostream<<"Cannot craft: "
						<<"No interact privilege"<<std::endl;
				delete a;
				return;
			}
			stat.add("craft", player->getName());
		}

		// Do the action
		a->apply(this, playersao, this);
		// Eat the action
		delete a;

		SendInventory(playersao);

	}
	else if(command == TOSERVER_CHAT_MESSAGE)
	{
		std::string message = packet[TOSERVER_CHAT_MESSAGE_DATA].as<std::string>();

		// If something goes wrong, this player is to blame
		RollbackScopeActor rollback_scope(m_rollback,
				std::string("player:")+player->getName());

		// Get player name of this client
		std::string name = player->getName();

		// Run script hook
		bool ate = m_script->on_chat_message(player->getName(), message);
		// If script ate the message, don't proceed
		if(ate)
			return;

		// Line to send to players
		std::string line;
		// Whether to send to other players
		bool send_to_others = false;

		// Commands are implemented in Lua, so only catch invalid
		// commands that were not "eaten" and send an error back
		if(message[0] == '/')
		{
			message = message.substr(1);
			if(message.length() == 0)
				line += "-!- Empty command";
			else
				// TODO: str_split(message, ' ')[0]
				line += "-!- Invalid command: " + message;
		}
		else
		{
			if(checkPriv(player->getName(), "shout")){
				line += "<";
				line += name;
				line += "> ";
				line += message;
				send_to_others = true;
			} else
				line += "-!- You don't have permission to shout.";
		}

		if(!line.empty())
		{
			if(send_to_others) {
				stat.add("chat", player->getName());
				actionstream<<"CHAT: "<<line<<std::endl;
				SendChatMessage(PEER_ID_INEXISTENT, line);
			} else
				SendChatMessage(peer_id, line);
		}
	}
	else if(command == TOSERVER_DAMAGE)
	{
		u8 damage = packet[TOSERVER_DAMAGE_VALUE].as<u8>();

		if(g_settings->getBool("enable_damage"))
		{
			actionstream<<player->getName()<<" damaged by "
					<<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
					<<std::endl;

			playersao->setHP(playersao->getHP() - damage);

			SendPlayerHPOrDie(playersao->getPeerID(), playersao->getHP() == 0);

			stat.add("damage", player->getName(), damage);
		}
	}
	else if(command == TOSERVER_BREATH)
	{

	/*
	 * If player is dead, we don't need to update the breath
	 * He is dead !
	 */
	if (!player->isDead()) {
		playersao->setBreath(packet[TOSERVER_BREATH_VALUE].as<u16>());
		SendPlayerBreath(peer_id);
	}
	}
	else if(command == TOSERVER_CHANGE_PASSWORD)
	{
		std::string oldpwd, newpwd;
		packet[TOSERVER_CHANGE_PASSWORD_OLD].convert(&oldpwd);
		packet[TOSERVER_CHANGE_PASSWORD_NEW].convert(&newpwd);

		if(!base64_is_valid(newpwd)){
			infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
			// Wrong old password supplied!!
			SendChatMessage(peer_id, "Invalid new password hash supplied. Password NOT changed.");
			return;
		}

		infostream<<"Server: Client requests a password change from "
				<<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;

		std::string playername = player->getName();

		std::string checkpwd;
		m_script->getAuth(playername, &checkpwd, NULL);

		if(oldpwd != checkpwd)
		{
			infostream<<"Server: invalid old password"<<std::endl;
			// Wrong old password supplied!!
			SendChatMessage(peer_id, "Invalid old password supplied. Password NOT changed.");
			return;
		}

		bool success = m_script->setPassword(playername, newpwd);
		if(success){
			actionstream<<player->getName()<<" changes password"<<std::endl;
			SendChatMessage(peer_id, "Password change successful.");
		} else {
			actionstream<<player->getName()<<" tries to change password but "
					<<"it fails"<<std::endl;
			SendChatMessage(peer_id, "Password change failed or inavailable.");
		}
	}
	else if(command == TOSERVER_PLAYERITEM)
	{
		u16 item = packet[TOSERVER_PLAYERITEM_VALUE].as<u16>();
		playersao->setWieldIndex(item);
	}
	else if(command == TOSERVER_RESPAWN)
	{
		if(!player->isDead())
			return;

		RespawnPlayer(peer_id);

		actionstream << player->getName() << " respawns at "
				<< PP(player->getPosition()/BS) << std::endl;

		// ActiveObject is added to environment in AsyncRunStep after
		// the previous addition has been successfully removed
	}
	else if(command == TOSERVER_INTERACT)
	{
		u8 action;
		u16 item_i;
		PointedThing pointed;

		packet[TOSERVER_INTERACT_ACTION].convert(&action);
		packet[TOSERVER_INTERACT_ITEM].convert(&item_i);
		packet[TOSERVER_INTERACT_POINTED_THING].convert(&pointed);

		if(player->hp == 0)
		{
			verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
				<<" tried to interact, but is dead!"<<std::endl;
			return;
		}

		v3f player_pos = playersao->getLastGoodPosition();

		// Update wielded item
		playersao->setWieldIndex(item_i);

		// Get pointed to node (undefined if not POINTEDTYPE_NODE)
		v3s16 p_under = pointed.node_undersurface;
		v3s16 p_above = pointed.node_abovesurface;

		// Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
		ServerActiveObject *pointed_object = NULL;
		if(pointed.type == POINTEDTHING_OBJECT)
		{
			pointed_object = m_env->getActiveObject(pointed.object_id);
			if(pointed_object == NULL)
			{
				verbosestream<<"TOSERVER_INTERACT: "
					"pointed object is NULL"<<std::endl;
				return;
			}

		}

		v3f pointed_pos_under = player_pos;
		v3f pointed_pos_above = player_pos;
		if(pointed.type == POINTEDTHING_NODE)
		{
			pointed_pos_under = intToFloat(p_under, BS);
			pointed_pos_above = intToFloat(p_above, BS);
		}
		else if(pointed.type == POINTEDTHING_OBJECT)
		{
			pointed_pos_under = pointed_object->getBasePosition();
			pointed_pos_above = pointed_pos_under;
		}

		/*
			Check that target is reasonably close
			(only when digging or placing things)
		*/
		if(action == 0 || action == 2 || action == 3)
		{
			float d = player_pos.getDistanceFrom(pointed_pos_under);
			float max_d = BS * 14; // Just some large enough value
			if(d > max_d){
				actionstream<<"Player "<<player->getName()
						<<" tried to access "<<pointed.dump()
						<<" from too far: "
						<<"d="<<d<<", max_d="<<max_d
						<<". ignoring."<<std::endl;
				// Re-send block to revert change on client-side
				RemoteClient *client = getClient(peer_id);
				v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
				client->SetBlockNotSent(blockpos);
				// Call callbacks
				m_script->on_cheat(playersao, "interacted_too_far");
				// Do nothing else
				return;
			}
		}

		/*
			Make sure the player is allowed to do it
		*/
		if(!checkPriv(player->getName(), "interact"))
		{
			actionstream<<player->getName()<<" attempted to interact with "
					<<pointed.dump()<<" without 'interact' privilege"
					<<std::endl;
			// Re-send block to revert change on client-side
			RemoteClient *client = getClient(peer_id);
			// Digging completed -> under
			if(action == 2){
				v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
				client->SetBlockNotSent(blockpos);
			}
			// Placement -> above
			if(action == 3){
				v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
				client->SetBlockNotSent(blockpos);
			}
			stat.add("interact_denied", player->getName());
			return;
		}

		/*
			If something goes wrong, this player is to blame
		*/
		RollbackScopeActor rollback_scope(m_rollback,
				std::string("player:")+player->getName());

		/*
			0: start digging or punch object
		*/
		if(action == 0)
		{
			if(pointed.type == POINTEDTHING_NODE)
			{
				/*
					NOTE: This can be used in the future to check if
					somebody is cheating, by checking the timing.
				*/
				MapNode n(CONTENT_IGNORE);
				bool pos_ok;
				n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
				if (pos_ok)
					n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);

				if (!pos_ok) {
					infostream<<"Server: Not punching: Node not found."
							<<" Adding block to emerge queue."
							<<std::endl;
					m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
				}

				if(n.getContent() != CONTENT_IGNORE)
					m_script->node_on_punch(p_under, n, playersao, pointed);
				// Cheat prevention
				playersao->noCheatDigStart(p_under);
			}
			else if(pointed.type == POINTEDTHING_OBJECT)
			{
				// Skip if object has been removed
				if(pointed_object->m_removed)
					return;

				actionstream<<player->getName()<<" punches object "
						<<pointed.object_id<<": "
						<<pointed_object->getDescription()<<std::endl;

				ItemStack punchitem = playersao->getWieldedItem();
				ToolCapabilities toolcap =
						punchitem.getToolCapabilities(m_itemdef);
				v3f dir = (pointed_object->getBasePosition() -
						(player->getPosition() + player->getEyeOffset())
							).normalize();
				float time_from_last_punch =
					playersao->resetTimeFromLastPunch();

			s16 src_original_hp = pointed_object->getHP();
			s16 dst_origin_hp = playersao->getHP();

				pointed_object->punch(dir, &toolcap, playersao,
						time_from_last_punch);

			// If the object is a player and its HP changed
			if (src_original_hp != pointed_object->getHP() &&
					pointed_object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
				SendPlayerHPOrDie(((PlayerSAO*)pointed_object)->getPeerID(),
						pointed_object->getHP() == 0);
			}

			// If the puncher is a player and its HP changed
			if (dst_origin_hp != playersao->getHP()) {
				SendPlayerHPOrDie(playersao->getPeerID(), playersao->getHP() == 0);
			}

				stat.add("punch", player->getName());
			}

		} // action == 0

		/*
			1: stop digging
		*/
		else if(action == 1)
		{
		} // action == 1

		/*
			2: Digging completed
		*/
		else if(action == 2)
		{
			// Only digging of nodes
			if(pointed.type == POINTEDTHING_NODE)
			{
				bool pos_ok;
				MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
				if (!pos_ok) {
					infostream << "Server: Not finishing digging: Node not found."
					           << " Adding block to emerge queue."
					           << std::endl;
					m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
				}

				/* Cheat prevention */
				bool is_valid_dig = true;
				if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
				{
					v3s16 nocheat_p = playersao->getNoCheatDigPos();
					float nocheat_t = playersao->getNoCheatDigTime();
					playersao->noCheatDigEnd();
					// If player didn't start digging this, ignore dig
					if(nocheat_p != p_under){
						infostream<<"Server: NoCheat: "<<player->getName()
								<<" started digging "
								<<PP(nocheat_p)<<" and completed digging "
								<<PP(p_under)<<"; not digging."<<std::endl;
						is_valid_dig = false;
						// Call callbacks
						m_script->on_cheat(playersao, "finished_unknown_dig");
					}
					// Get player's wielded item
					ItemStack playeritem;
					InventoryList *mlist = playersao->getInventory()->getList("main");
					if(mlist != NULL)
						playeritem = mlist->getItem(playersao->getWieldIndex());
					ToolCapabilities playeritem_toolcap =
							playeritem.getToolCapabilities(m_itemdef);
					// Get diggability and expected digging time
					DigParams params = getDigParams(m_nodedef->get(n).groups,
							&playeritem_toolcap);
					// If can't dig, try hand
					if(!params.diggable){
						const ItemDefinition &hand = m_itemdef->get("");
						const ToolCapabilities *tp = hand.tool_capabilities;
						if(tp)
							params = getDigParams(m_nodedef->get(n).groups, tp);
					}
					// If can't dig, ignore dig
					if(!params.diggable){
						infostream<<"Server: NoCheat: "<<player->getName()
								<<" completed digging "<<PP(p_under)
								<<", which is not diggable with tool. not digging."
								<<std::endl;
						is_valid_dig = false;
						// Call callbacks
						m_script->on_cheat(playersao, "dug_unbreakable");
					}
					// Check digging time
					// If already invalidated, we don't have to
					if(!is_valid_dig){
						// Well not our problem then
					}
					// Clean and long dig
					else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
						// All is good, but grab time from pool; don't care if
						// it's actually available
						playersao->getDigPool().grab(params.time);
					}
					// Short or laggy dig
					// Try getting the time from pool
					else if(playersao->getDigPool().grab(params.time)){
						// All is good
					}
					// Dig not possible
					else{
						infostream<<"Server: NoCheat: "<<player->getName()
								<<" completed digging "<<PP(p_under)
								<<"too fast; not digging."<<std::endl;
						is_valid_dig = false;
						// Call callbacks
						m_script->on_cheat(playersao, "dug_too_fast");
					}
				}

				/* Actually dig node */

				if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
				{
					m_script->node_on_dig(p_under, n, playersao);
					stat.add("dig", player->getName());
					stat.add("dig_"+ m_nodedef->get(n).name , player->getName());
				}

				v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
				RemoteClient *client = getClient(peer_id);
				// Send unusual result (that is, node not being removed)
				if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
				{
					// Re-send block to revert change on client-side
					client->SetBlockNotSent(blockpos);
				}
				else {
					client->ResendBlockIfOnWire(blockpos);
				}
			}
		} // action == 2

		/*
			3: place block or right-click object
		*/
		else if(action == 3)
		{
			ItemStack item = playersao->getWieldedItem();

			// Reset build time counter
			if(pointed.type == POINTEDTHING_NODE &&
					item.getDefinition(m_itemdef).type == ITEM_NODE)
				getClient(peer_id)->m_time_from_building = 0.0;

			if(pointed.type == POINTEDTHING_OBJECT)
			{
				// Right click object

				// Skip if object has been removed
				if(pointed_object->m_removed)
					return;

/* android bug - too many
				actionstream<<player->getName()<<" right-clicks object "
						<<pointed.object_id<<": "
						<<pointed_object->getDescription()<<std::endl;
*/

				// Do stuff
				pointed_object->rightClick(playersao);
			}
			else if(m_script->item_OnPlace(
					item, playersao, pointed))
			{
				// Placement was handled in lua

				// Apply returned ItemStack
			if (playersao->setWieldedItem(item)) {
				SendInventory(playersao);
			}

				stat.add("place", player->getName());
				//stat.add("place_" + item.name, player->getName());
			}

			// If item has node placement prediction, always send the
			// blocks to make sure the client knows what exactly happened
			RemoteClient *client = getClient(peer_id);
			v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
			v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
			if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
				client->SetBlockNotSent(blockpos);
				if(blockpos2 != blockpos) {
					client->SetBlockNotSent(blockpos2);
				}
			}
			else {
				client->ResendBlockIfOnWire(blockpos);
				if(blockpos2 != blockpos) {
					client->ResendBlockIfOnWire(blockpos2);
				}
			}
		} // action == 3

		/*
			4: use
		*/
		else if(action == 4)
		{
			ItemStack item = playersao->getWieldedItem();

			actionstream<<player->getName()<<" uses "<<item.name
					<<", pointing at "<<pointed.dump()<<std::endl;

			if(m_script->item_OnUse(
					item, playersao, pointed))
			{
				// Apply returned ItemStack
				if (playersao->setWieldedItem(item)) {
					SendInventory(playersao);
				}
				stat.add("use", player->getName());
				stat.add("use_" + item.name, player->getName());
			}

		} // action == 4


		/*
			Catch invalid actions
		*/
		else
		{
			infostream<<"WARNING: Server: Invalid action "
					<<action<<std::endl;
		}
	}
	else if(command == TOSERVER_REMOVED_SOUNDS)
	{
		std::vector<s32> removed_ids;
		packet[TOSERVER_REMOVED_SOUNDS_IDS].convert(&removed_ids);
		for (auto id : removed_ids) {
			std::map<s32, ServerPlayingSound>::iterator i =
					m_playing_sounds.find(id);
			if(i == m_playing_sounds.end())
				continue;
			ServerPlayingSound &psound = i->second;
			psound.clients.erase(peer_id);
			if(psound.clients.empty())
				m_playing_sounds.erase(i);
		}
	}
	else if(command == TOSERVER_NODEMETA_FIELDS)
	{
		v3s16 p = packet[TOSERVER_NODEMETA_FIELDS_POS].as<v3s16>();
		std::string formname = packet[TOSERVER_NODEMETA_FIELDS_FORMNAME].as<std::string>();
		std::map<std::string, std::string> fields;
		packet[TOSERVER_NODEMETA_FIELDS_DATA].convert(&fields);

		// If something goes wrong, this player is to blame
		RollbackScopeActor rollback_scope(m_rollback,
				std::string("player:")+player->getName());

		// Check the target node for rollback data; leave others unnoticed
		RollbackNode rn_old(&m_env->getMap(), p, this);

		m_script->node_on_receive_fields(p, formname, fields,playersao);

		// Report rollback data
		RollbackNode rn_new(&m_env->getMap(), p, this);
		if(rollback() && rn_new != rn_old){
			RollbackAction action;
			action.setSetNode(p, rn_old, rn_new);
			rollback()->reportAction(action);
		}
	}
	else if(command == TOSERVER_INVENTORY_FIELDS)
	{
		std::string formname;
		std::map<std::string, std::string> fields;

		packet[TOSERVER_INVENTORY_FIELDS_FORMNAME].convert(&formname);
		packet[TOSERVER_INVENTORY_FIELDS_DATA].convert(&fields);

		m_script->on_playerReceiveFields(playersao, formname, fields);
	}
	else if(command == TOSERVER_DRAWCONTROL)
	{
		auto client = getClient(peer_id);
		client->wanted_range = packet[TOSERVER_DRAWCONTROL_WANTED_RANGE].as<u32>();
		client->range_all = packet[TOSERVER_DRAWCONTROL_RANGE_ALL].as<u32>();
		client->farmesh  = packet[TOSERVER_DRAWCONTROL_FARMESH].as<u8>();
		client->fov  = packet[TOSERVER_DRAWCONTROL_FOV].as<f32>();
		client->block_overflow = packet[TOSERVER_DRAWCONTROL_BLOCK_OVERFLOW].as<bool>();
	}
	else
	{
		infostream<<"Server::ProcessData(): Ignoring "
				"unknown command "<<command<<std::endl;
	}

	} //try
	catch(SendFailedException &e)
	{
		errorstream<<"Server::ProcessData(): SendFailedException: "
				<<"what="<<e.what()
				<<std::endl;
	}
}
bool ConditionRegeneration::executeCondition(Creature* creature, int32_t interval)
{
	internalHealthTicks += interval;
	internalManaTicks += interval;

	if (creature->getZone() == ZONE_PROTECTION) {
		return ConditionGeneric::executeCondition(creature, interval);
	}

	if (internalHealthTicks >= healthTicks) {
		internalHealthTicks = 0;

		int32_t realHealthGain = creature->getHealth();
		creature->changeHealth(healthGain);
		realHealthGain = creature->getHealth() - realHealthGain;

		if (isBuff && realHealthGain > 0) {
			Player* player = creature->getPlayer();
			if (player) {
				std::string healString = std::to_string(realHealthGain) + (realHealthGain != 1 ? " hitpoints." : " hitpoint.");

				TextMessage message(MESSAGE_HEALED, "You were healed for " + healString);
				message.position = player->getPosition();
				message.primary.value = realHealthGain;
				message.primary.color = TEXTCOLOR_MAYABLUE;
				player->sendTextMessage(message);

				SpectatorHashSet spectators;
				g_game.map.getSpectators(spectators, player->getPosition(), false, true);
				spectators.erase(player);
				if (!spectators.empty()) {
					message.type = MESSAGE_HEALED_OTHERS;
					message.text = player->getName() + " was healed for " + healString;
					for (Creature* spectator : spectators) {
						spectator->getPlayer()->sendTextMessage(message);
					}
				}
			}
		}
	}

	if (internalManaTicks >= manaTicks) {
		internalManaTicks = 0;

		if (Player* player = creature->getPlayer()) {
			int32_t realManaGain = player->getMana();
			player->changeMana(manaGain);
			realManaGain = player->getMana() - realManaGain;

			if (isBuff && realManaGain > 0) {
				std::string manaGainString = std::to_string(realManaGain);

				TextMessage message(MESSAGE_HEALED, "You gained " + manaGainString + " mana.");
				message.position = player->getPosition();
				message.primary.value = realManaGain;
				message.primary.color = TEXTCOLOR_MAYABLUE;
				player->sendTextMessage(message);

				SpectatorHashSet spectators;
				g_game.map.getSpectators(spectators, player->getPosition(), false, true);
				spectators.erase(player);
				if (!spectators.empty()) {
					message.type = MESSAGE_HEALED_OTHERS;
					message.text = player->getName() + " gained " + manaGainString + " mana.";
					for (Creature* spectator : spectators) {
						spectator->getPlayer()->sendTextMessage(message);
					}
				}
			}
		}
	}

	return ConditionGeneric::executeCondition(creature, interval);
}