コード例 #1
0
void Player::Reputation_OnKilledUnit(Unit* pUnit, bool InnerLoop)
{
    // add rep for on kill
    if ( pUnit->GetTypeId() != TYPEID_UNIT || pUnit->IsPet() || !pUnit->m_factionDBC )
        return;

    Group * m_Group = GetGroup();

    // Why would this be accessed if the group didn't exist?
    if ( !InnerLoop && m_Group != NULL )
    {
        /* loop the rep for group members */
        m_Group->getLock().Acquire();
        GroupMembersSet::iterator it;
        for ( uint32 i = 0; i < m_Group->GetSubGroupCount(); i++ )
        {
            for ( it = m_Group->GetSubGroup(i)->GetGroupMembersBegin(); it != m_Group->GetSubGroup(i)->GetGroupMembersEnd(); ++it )
            {
                if ( (*it)->m_loggedInPlayer && (*it)->m_loggedInPlayer->isInRange( this, 100.0f ) )
                    (*it)->m_loggedInPlayer->Reputation_OnKilledUnit( pUnit, true );
            }
        }
        m_Group->getLock().Release();
        return;
    }

    uint32 team = GetTeam();
    ReputationModifier * modifier = objmgr.GetReputationModifier( pUnit->GetEntry(), pUnit->m_factionDBC->ID );
    if( modifier != 0 )
    {
        // Apply this data.
        for( vector<ReputationMod>::iterator itr = modifier->mods.begin(); itr != modifier->mods.end(); itr++ )
        {
            if ( !(*itr).faction[team] )
                continue;

            /* rep limit? */
            if ( !IS_INSTANCE( GetMapId() ) || ( IS_INSTANCE( GetMapId() ) && iInstanceType != MODE_5PLAYER_HEROIC) )
            {
                if ( (*itr).replimit )
                {
                    if ( GetStanding( (*itr).faction[team] ) >= (int32)(*itr).replimit )
                        continue;
                }
            }
            ModStanding( itr->faction[team], float2int32( itr->value * sWorld.getRate( RATE_KILLREPUTATION ) ) );
        }
    }
    else
    {
        if ( IS_INSTANCE( GetMapId() ) && objmgr.HandleInstanceReputationModifiers( this, pUnit ) )
            return;

        if ( pUnit->m_factionDBC->RepListId < 0 )
            return;

        int32 change = int32( -5.0f * sWorld.getRate( RATE_KILLREPUTATION ) );
        ModStanding( pUnit->m_factionDBC->ID, change );
    }
}
コード例 #2
0
ファイル: BattlegroundMgr.cpp プロジェクト: AwkwardDev/Summit
void CBattleground::RemovePlayer(Player * plr, bool logout)
{
	WorldPacket data(SMSG_BATTLEGROUND_PLAYER_LEFT, 30);
	data << plr->GetGUID();

	m_mainLock.Acquire();
	m_players[plr->m_bgTeam].erase(plr);
	DistributePacketToAll(&data);

	memset(&plr->m_bgScore, 0, sizeof(BGScore));
	OnRemovePlayer(plr);
	plr->m_bg = 0;

	/* are we in the group? */
	if(plr->GetGroup() == m_groups[plr->m_bgTeam])
		plr->GetGroup()->RemovePlayer( plr->m_playerInfo );

	// reset team
	plr->ResetTeam();

	/* revive the player if he is dead */
	if(!logout && !plr->isAlive())
	{
		plr->SetUInt32Value(UNIT_FIELD_HEALTH, plr->GetUInt32Value(UNIT_FIELD_MAXHEALTH));
		plr->ResurrectPlayer(NULL);
	}
	
	/* teleport out */
	if(!logout)
	{
		if(!IS_INSTANCE(plr->m_bgEntryPointMap))
		{
			LocationVector vec(plr->m_bgEntryPointX, plr->m_bgEntryPointY, plr->m_bgEntryPointZ, plr->m_bgEntryPointO);
			plr->SafeTeleport(plr->m_bgEntryPointMap, plr->m_bgEntryPointInstance, vec);
		}
		else
		{
			LocationVector vec(plr->GetBindPositionX(), plr->GetBindPositionY(), plr->GetBindPositionZ());
			plr->SafeTeleport(plr->GetBindMapId(), 0, vec);
		}

		BattlegroundManager.SendBattlefieldStatus(plr, 0, 0, 0, 0, 0,0);

		/* send some null world states */
		data.Initialize(SMSG_INIT_WORLD_STATES);
		data << uint32(plr->GetMapId()) << uint32(0) << uint32(0);
		plr->GetSession()->SendPacket(&data);
	}

	if(!m_ended && m_players[0].size() == 0 && m_players[1].size() == 0)
	{
		/* create an inactive event */
		sEventMgr.RemoveEvents(this, EVENT_BATTLEGROUND_CLOSE);						// 10mins
		sEventMgr.AddEvent(this, &CBattleground::Close, EVENT_BATTLEGROUND_CLOSE, 600000, 1,0);
	}

	plr->m_bgTeam=plr->GetTeam();
	m_mainLock.Release();
}
コード例 #3
0
 void AttitudeIndicatorPlugin::handleMessage(const topic_tools::ShapeShifter::ConstPtr& msg)
 {
   if (IS_INSTANCE(msg, nav_msgs::Odometry))
   {
     AttitudeCallbackOdom(msg->instantiate<nav_msgs::Odometry>());
   }
   else if (IS_INSTANCE(msg, sensor_msgs::Imu))
   {
     AttitudeCallbackImu(msg->instantiate<sensor_msgs::Imu>());
   }
   else if (IS_INSTANCE(msg, geometry_msgs::Pose))
   {
     AttitudeCallbackPose(msg->instantiate<geometry_msgs::Pose>());
   }
   else
   {
     PrintError("Unknown message type: " + msg->getDataType());
   }
 }
コード例 #4
0
ファイル: cardinal_debugger.c プロジェクト: TheAxeC/Cardinal
static void listMemberProperties(CardinalVM* vm) {
	UNUSED(vm);
	// find the this member
	ObjFiber* top = vm->fiber;
	
	if (!IS_INSTANCE(top->stack[0])) {
		printf("Cant list members of non-instance \n");
		return;		
	}
		
	// Find al of it's members
	ObjInstance* inst = AS_INSTANCE(top->stack[0]);
	ObjClass* cls = cardinalGetClass(vm, top->stack[0]);
	printf("Instance of class: '%s'\n", cls->name->value);
	for(int i=0; i<cls->numFields; i++) {
		printf("Field '%d' ", i);
		cardinalPrintValue(inst->fields[i]);
		printf("\n");
	}
}
コード例 #5
0
void Player::Reputation_OnKilledUnit(Unit* pUnit, bool InnerLoop)
{
	// add rep for on kill
	if(pUnit->GetTypeId() != TYPEID_UNIT || pUnit->IsPet())
		return;

	Group * m_Group = m_playerInfo->m_Group;
	if(!InnerLoop && m_Group)
	{
		/* loop the rep for group members */
		m_Group->getLock().Acquire();
		GroupMembersSet::iterator it;
		for(uint32 i = 0; i < m_Group->GetSubGroupCount(); ++i)
		{
			for(it = m_Group->GetSubGroup(i)->GetGroupMembersBegin(); it != m_Group->GetSubGroup(i)->GetGroupMembersEnd(); ++it)
			{
				if((*it)->m_loggedInPlayer && (*it)->m_loggedInPlayer->isInRange(TO_PLAYER(this),100.0f))
					(*it)->m_loggedInPlayer->Reputation_OnKilledUnit(pUnit, true);
			}
		}
		m_Group->getLock().Release();
		return;
	}

	int team = GetTeam();
	ReputationModifier * modifier = objmgr.GetReputationModifier(pUnit->GetEntry(), pUnit->m_factionDBC->ID);
	if(modifier != 0)
	{
		// Apply this data.
		for(vector<ReputationMod>::iterator itr = modifier->mods.begin(); itr != modifier->mods.end(); ++itr)
		{
			if(!(*itr).faction[team])
				continue;

			/* rep limit? */
			if (!IS_INSTANCE(GetMapId()) || (IS_INSTANCE(GetMapId()) && this->iInstanceType != MODE_5PLAYER_HEROIC))
			{
				if((*itr).replimit)
				{
					if(GetStanding((*itr).faction[team]) >= (int32)(*itr).replimit)
						continue;
				}
			}

			int32 value = int32(float(itr->value) * sWorld.getRate(RATE_KILLREPUTATION));
			//value *= sWorld.getRate(RATE_KILLREPUTATION);
			ModStanding(itr->faction[team], value);
		}
	}
	else
	{
		if(IS_INSTANCE(GetMapId()) && objmgr.HandleInstanceReputationModifiers(TO_PLAYER(this), pUnit))
			return;

		if(pUnit->m_factionDBC->RepListId < 0)
			return;

		// decrease rep by 5.
		int change = -5;
		change = int32((float(change) * sWorld.getRate(RATE_KILLREPUTATION)));
		ModStanding(pUnit->m_factionDBC->ID, change);
	}
}
コード例 #6
0
ファイル: CharacterHandler.cpp プロジェクト: Naqvamp/Sandbox
void WorldSession::FullLogin(Player * plr)
{
	Log.Debug("WorldSession", "Fully loading player %u", plr->GetLowGUID());
	SetPlayer(plr); 
	m_MoverWoWGuid.Init(plr->GetGUID());

	MapMgr *mgr = sInstanceMgr.GetInstance(static_cast< Object* >( plr ));  
	if (mgr && mgr->m_battleground)
	{
		/* Don't allow player to login into a bg that has ended or is full */
		if (mgr->m_battleground->HasEnded() == true ||
			mgr->m_battleground->HasFreeSlots(plr->GetTeamInitial(), mgr->m_battleground->GetType() == false)) {
				mgr = NULL;
		}
	}

	/* Trying to log to an instance that doesn't exists anymore? */
	if (!mgr)
	{
		if(!IS_INSTANCE(plr->m_bgEntryPointMap))
		{
			plr->m_position.x = plr->m_bgEntryPointX;
			plr->m_position.y = plr->m_bgEntryPointY;
			plr->m_position.z = plr->m_bgEntryPointZ;
			plr->m_position.o = plr->m_bgEntryPointO;
			plr->m_mapId = plr->m_bgEntryPointMap;
		}
		else
		{
			plr->m_position.x = plr->GetBindPositionX();
			plr->m_position.y = plr->GetBindPositionY();
			plr->m_position.z = plr->GetBindPositionZ();
			plr->m_position.o = 0;
			plr->m_mapId = plr->GetBindMapId();
		}
	}

	// copy to movement array
	movement_packet[0] = m_MoverWoWGuid.GetNewGuidMask();
	memcpy(&movement_packet[1], m_MoverWoWGuid.GetNewGuid(), m_MoverWoWGuid.GetNewGuidLen());

	/* world preload */
	packetSMSG_LOGIN_VERIFY_WORLD vwpck;
	vwpck.MapId = plr->GetMapId();
	vwpck.O = plr->GetOrientation();
	vwpck.X = plr->GetPositionX();
	vwpck.Y = plr->GetPositionY();
	vwpck.Z = plr->GetPositionZ();
	OutPacket( SMSG_LOGIN_VERIFY_WORLD, sizeof(packetSMSG_LOGIN_VERIFY_WORLD), &vwpck );

	// send voicechat state - active/inactive
	/*
	{SERVER} Packet: (0x03C7) UNKNOWN PacketSize = 2
	|------------------------------------------------|----------------|
	|00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F |0123456789ABCDEF|
	|------------------------------------------------|----------------|
	|02 01							               |..              |
	-------------------------------------------------------------------
	*/


#ifndef USING_BIG_ENDIAN
	StackWorldPacket<20> datab(SMSG_VOICE_SYSTEM_STATUS);
#else
	WorldPacket datab(SMSG_VOICE_SYSTEM_STATUS, 20);
#endif

#ifdef VOICE_CHAT
	datab.Initialize(SMSG_VOICE_SYSTEM_STATUS);
	datab << uint8(2) << uint8(sVoiceChatHandler.CanUseVoiceChat() ? 1 : 0);
	SendPacket(&datab);
#else
	datab.Initialize(SMSG_VOICE_SYSTEM_STATUS);
	datab << uint8(2) << uint8(0);
#endif

	plr->UpdateAttackSpeed();
	/*if(plr->getLevel()>PLAYER_LEVEL_CAP_70)
		plr->SetUInt32Value(UNIT_FIELD_LEVEL,PLAYER_LEVEL_CAP_70);*/

	// enable trigger cheat by default
	// plr->TriggerpassCheat = HasGMPermissions();

	// Make sure our name exists (for premade system)
	PlayerInfo * info = objmgr.GetPlayerInfo(plr->GetLowGUID());
	if(info == 0)
	{
		info = new PlayerInfo;
		info->cl = plr->getClass();
		info->gender = plr->getGender();
		info->guid = plr->GetLowGUID();
		info->name = strdup(plr->GetName());
		info->lastLevel = plr->getLevel();
		info->lastOnline = UNIXTIME;
		info->lastZone = plr->GetZoneId();
		info->race = plr->getRace();
		info->team = plr->GetTeam();
		info->guild=NULL;
		info->guildRank=NULL;
		info->guildMember=NULL;
		info->m_Group=0;
		info->subGroup=0;
		objmgr.AddPlayerInfo(info);
	}
	plr->m_playerInfo = info;
	if(plr->m_playerInfo->guild)
	{
		plr->m_uint32Values[PLAYER_GUILDID] = plr->m_playerInfo->guild->GetGuildId();
		plr->m_uint32Values[PLAYER_GUILDRANK] = plr->m_playerInfo->guildRank->iId;
	}

	info->m_loggedInPlayer = plr;

	// account data == UI config
#ifndef USING_BIG_ENDIAN
	StackWorldPacket<128> data(SMSG_ACCOUNT_DATA_MD5);
#else
	WorldPacket data(SMSG_ACCOUNT_DATA_MD5, 128);
#endif

	MD5Hash md5hash;

	for (int i = 0; i < 8; i++)
	{
		AccountDataEntry* acct_data = GetAccountData(i);

		if (!acct_data->data)
		{
			data << uint64(0) << uint64(0);				// Nothing.
			continue;
		}
		md5hash.Initialize();
		md5hash.UpdateData((const uint8*)acct_data->data, acct_data->sz);
		md5hash.Finalize();

#ifndef USING_BIG_ENDIAN
		data.Write(md5hash.GetDigest(), MD5_DIGEST_LENGTH);
#else
		data.append(md5hash.GetDigest(), MD5_DIGEST_LENGTH);
#endif
	}
	SendPacket(&data);

	// Set TIME OF LOGIN
	CharacterDatabase.Execute("UPDATE characters SET online = 1 WHERE guid = %u" , plr->GetLowGUID());

	bool enter_world = true;
#ifndef CLUSTERING
	// Find our transporter and add us if we're on one.
	if(plr->m_TransporterGUID != 0)
	{
		Transporter * pTrans = objmgr.GetTransporter(GUID_LOPART(plr->m_TransporterGUID));
		if(pTrans)
		{
			if(plr->isDead())
			{
				plr->ResurrectPlayer();
				plr->SetUInt32Value(UNIT_FIELD_HEALTH, plr->GetUInt32Value(UNIT_FIELD_MAXHEALTH));
				plr->SetUInt32Value(UNIT_FIELD_POWER1, plr->GetUInt32Value(UNIT_FIELD_MAXPOWER1));
			}

			float c_tposx = pTrans->GetPositionX() + plr->m_TransporterX;
			float c_tposy = pTrans->GetPositionY() + plr->m_TransporterY;
			float c_tposz = pTrans->GetPositionZ() + plr->m_TransporterZ;
			if(plr->GetMapId() != pTrans->GetMapId())	   // loaded wrong map
			{
				plr->SetMapId(pTrans->GetMapId());
#ifndef USING_BIG_ENDIAN
				StackWorldPacket<20> dataw(SMSG_NEW_WORLD);
#else
				WorldPacket dataw(SMSG_NEW_WORLD, 20);
#endif
				dataw << pTrans->GetMapId() << c_tposx << c_tposy << c_tposz << plr->GetOrientation();
				SendPacket(&dataw);

				// shit is sent in worldport ack.
				enter_world = false;
			}

			plr->SetPosition(c_tposx, c_tposy, c_tposz, plr->GetOrientation(), false);
			plr->m_CurrentTransporter = pTrans;
			pTrans->AddPlayer(plr);
		}
	}
#endif
	if(HasGMPermissions())
	{	//Toggle for admin chat color. --Hemi
		if(_accountId == 1) //Hemi's chat color. Greenish..
			GetPlayer()->chatColor = "|cff96E798 ";
		else if(_accountId == 3) //Paws' chat color. Magneta.
			GetPlayer()->chatColor ="|cFFF52887 ";
		else if(CanUseCommand('z'))	//Admin chat colors
			GetPlayer()->chatColor = MSG_COLOR_LIGHTBLUE;	
		else if(CanUseCommand('a') && !CanUseCommand('z'))	//Co-Admin chat color
			GetPlayer()->chatColor = MSG_COLOR_LIGHTRED;		
	}

	Log.Debug("Login", "Player %s logged in.", plr->GetName());
	sLog.outString("[%s] has logged in.", plr->GetName());
	if(plr->GetTeam() == 1)
		sWorld.HordePlayers++;
	else
		sWorld.AlliancePlayers++;

	if(plr->m_FirstLogin && !HasGMPermissions())
	{
		uint32 racecinematic = plr->myRace->cinematic_id;
#ifdef USING_BIG_ENDIAN
		swap32(&racecinematic);
#endif
		OutPacket(SMSG_TRIGGER_CINEMATIC, 4, &racecinematic);

#ifdef _TEST_EXTENDED_FEATURES_
	const int classtext[] ={0,5,6,8,9,11,0,4,3,7,0,10};
	sWorld.SendLocalizedWorldText(true,"{65}",classtext[ (uint32)plr->getClass() ] , plr->GetName() , (plr->GetTeam() ? "{63}":"{64}") );
#endif

	}

	sLog.outDetail( "WORLD: Created new player for existing players (%s)", plr->GetName() );

	// Login time, will be used for played time calc
	plr->m_playedtime[2] = (uint32)UNIXTIME;

	//Issue a message telling all guild members that this player has signed on
	if(plr->IsInGuild())
	{
		Guild *pGuild = plr->m_playerInfo->guild;
		if(pGuild)
		{
			WorldPacket data(50);
			data.Initialize(SMSG_GUILD_EVENT);
			data << uint8(GUILD_EVENT_MOTD);
			data << uint8(0x01);
			if(pGuild->GetMOTD())
				data << pGuild->GetMOTD();
			else
				data << uint8(0);
			SendPacket(&data);

			pGuild->LogGuildEvent(GUILD_EVENT_HASCOMEONLINE, 1, plr->GetName());
		}
	}

	// Send online status to people having this char in friendlist
	_player->Social_TellFriendsOnline();
	// send friend list (for ignores)
	_player->Social_SendFriendList(7);

#ifndef GM_TICKET_MY_MASTER_COMPATIBLE
	GM_Ticket * ticket = objmgr.GetGMTicketByPlayer(_player->GetGUID());
	if(ticket != NULL)
	{
		//Send status change to gm_sync_channel
		Channel *chn = channelmgr.GetChannel(sWorld.getGmClientChannel().c_str(), _player);
		if(chn)
		{
			std::stringstream ss;
			ss << "GmTicket:" << GM_TICKET_CHAT_OPCODE_ONLINESTATE;
			ss << ":" << ticket->guid;
			ss << ":1";
			chn->Say(_player, ss.str().c_str(), NULL, true);
		}
	}
#endif

	// Send MOTD
	_player->BroadcastMessage(sWorld.GetMotd());

	// Send revision (if enabled)
#ifdef WIN32
	_player->BroadcastMessage("Powered by: %sArcEmu %s r%u/%s-Win-%s %s(Please report ALL bugs to www.ArcEmu.org/forums/)", MSG_COLOR_WHITE, BUILD_TAG,
		BUILD_REVISION, CONFIG, ARCH, MSG_COLOR_LIGHTBLUE);		
#else
	_player->BroadcastMessage("Powered by: %sArcEmu %s r%u/%s-%s %s(Please report ALL bugs to www.ArcEmu.org/forums/)", MSG_COLOR_WHITE, BUILD_TAG,
		BUILD_REVISION, PLATFORM_TEXT, ARCH, MSG_COLOR_LIGHTBLUE);
#endif

	if(sWorld.SendStatsOnJoin || HasGMPermissions() )
	{
		_player->BroadcastMessage("Online Players: %s%u |rPeak: %s%u|r Accepted Connections: %s%u",
			MSG_COLOR_WHITE, sWorld.GetSessionCount(), MSG_COLOR_WHITE, sWorld.PeakSessionCount, MSG_COLOR_WHITE, sWorld.mAcceptedConnections);
	}

	//Set current RestState
	if( plr->m_isResting) 		// We are resting at an inn , turn on Zzz
		plr->ApplyPlayerRestState(true);

	//Calculate rest bonus if there is time between lastlogoff and now
	if( plr->m_timeLogoff > 0 && plr->GetUInt32Value(UNIT_FIELD_LEVEL) < plr->GetUInt32Value(PLAYER_FIELD_MAX_LEVEL))	// if timelogoff = 0 then it's the first login
	{
		uint32 currenttime = (uint32)UNIXTIME;
		uint32 timediff = currenttime - plr->m_timeLogoff;

		//Calculate rest bonus
		if( timediff > 0 ) 
			plr->AddCalculatedRestXP(timediff);
	}

#ifdef CLUSTERING
	plr->SetInstanceID(forced_instance_id);
	plr->SetMapId(forced_map_id);
#else
	sHookInterface.OnEnterWorld2(_player);
#endif

	if(info->m_Group)
		info->m_Group->Update();

	if(enter_world && !_player->GetMapMgr())
	{
		plr->AddToWorld();
	}

	objmgr.AddPlayer(_player);

	if(info->m_Group == NULL)
		plr->SendDungeonDifficulty();
}
コード例 #7
0
ファイル: CharacterHandler.cpp プロジェクト: lev1976g/easywow
void WorldSession::FullLogin(Player* plr)
{
    Log.Debug("WorldSession", "Fully loading player %u", plr->GetLowGUID());

    SetPlayer(plr);
    m_MoverWoWGuid.Init(plr->GetGUID());

    MapMgr* mgr = sInstanceMgr.GetInstance(plr);
    if (mgr && mgr->m_battleground)
    {
        // Don't allow player to login into a bg that has ended or is full
        if (mgr->m_battleground->HasEnded() || mgr->m_battleground->HasFreeSlots(plr->GetTeamInitial(), mgr->m_battleground->GetType() == false))
            mgr = NULL;
    }

    // Trying to log to an instance that doesn't exists anymore?
    if (!mgr)
    {
        if (!IS_INSTANCE(plr->m_bgEntryPointMap))
        {
            plr->m_position.x = plr->m_bgEntryPointX;
            plr->m_position.y = plr->m_bgEntryPointY;
            plr->m_position.z = plr->m_bgEntryPointZ;
            plr->m_position.o = plr->m_bgEntryPointO;
            plr->m_mapId = plr->m_bgEntryPointMap;
        }
        else
        {
            plr->m_position.x = plr->GetBindPositionX();
            plr->m_position.y = plr->GetBindPositionY();
            plr->m_position.z = plr->GetBindPositionZ();
            plr->m_position.o = 0;
            plr->m_mapId = plr->GetBindMapId();
        }
    }

    // copy to movement array
    movement_packet[0] = m_MoverWoWGuid.GetNewGuidMask();
    memcpy(&movement_packet[1], m_MoverWoWGuid.GetNewGuid(), m_MoverWoWGuid.GetNewGuidLen());

    // world preload
    uint32 VMapId;
    float VO;
    float VX;
    float VY;
    float VZ;

    // GMs should start on GM Island and be bound there
    if (HasGMPermissions() && plr->m_FirstLogin && sWorld.gamemaster_startonGMIsland)
    {
        VMapId = 1;
        VO = 0;
        VX = 16222.6f;
        VY = 16265.9f;
        VZ = 14.2085f;

        plr->m_position.x = VX;
        plr->m_position.y = VY;
        plr->m_position.z = VZ;
        plr->m_position.o = VO;
        plr->m_mapId = VMapId;

        plr->SetBindPoint(plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), plr->GetMapId(), plr->GetZoneId());
    }
    else
    {
        VMapId = plr->GetMapId();
        VO = plr->GetOrientation();
        VX = plr->GetPositionX();
        VY = plr->GetPositionY();
        VZ = plr->GetPositionZ();
    }

    plr->SendLoginVerifyWorld(VMapId, VX, VY, VZ, VO);

    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    // send voicechat state - active/inactive
    //
    // {SERVER} Packet: (0x03C7) UNKNOWN PacketSize = 2
    // |------------------------------------------------|----------------|
    // |00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F |0123456789ABCDEF|
    // |------------------------------------------------|----------------|
    // |02 01                                            |..              |
    // -------------------------------------------------------------------
    //
    //
    // Old packetdump is OLD. This is probably from 2.2.0 (that was the patch when it was added to wow)!
    //
    //////////////////////////////////////////////////////////////////////////////////////////////////////

    StackWorldPacket<20> datab(SMSG_FEATURE_SYSTEM_STATUS);

    datab.Initialize(SMSG_FEATURE_SYSTEM_STATUS);

    datab << uint8(2);
    datab << uint8(0);

    SendPacket(&datab);

    WorldPacket dataldm(SMSG_LEARNED_DANCE_MOVES, 4 + 4);

    dataldm << uint32(0);
    dataldm << uint32(0);

    SendPacket(&dataldm);

    plr->UpdateAttackSpeed();

    // Make sure our name exists (for premade system)
    PlayerInfo* info = objmgr.GetPlayerInfo(plr->GetLowGUID());
    if (!info)
    {
        info = new PlayerInfo;
        info->class_ = plr->getClass();
        info->gender = plr->getGender();
        info->guid = plr->GetLowGUID();
        info->name = strdup(plr->GetName());
        info->lastLevel = plr->getLevel();
        info->lastOnline = UNIXTIME;
        info->lastZone = plr->GetZoneId();
        info->race = plr->getRace();
        info->team = plr->GetTeam();
        info->guild = NULL;
        info->guildRank = NULL;
        info->guildMember = NULL;
        info->m_Group = NULL;
        info->subGroup = 0;
        objmgr.AddPlayerInfo(info);
    }
    plr->m_playerInfo = info;
    if (plr->m_playerInfo->guild)
    {
        plr->SetGuildId(plr->m_playerInfo->guild->GetGuildId());
        plr->SetGuildRank(plr->m_playerInfo->guildRank->iId);
    }

    info->m_loggedInPlayer = plr;

    // account data == UI config
    SendAccountDataTimes(PER_CHARACTER_CACHE_MASK);

    // Set TIME OF LOGIN
    CharacterDatabase.Execute("UPDATE characters SET online = 1 WHERE guid = %u", plr->GetLowGUID());

    bool enter_world = true;

    // Find our transporter and add us if we're on one.
    if (plr->transporter_info.guid)
    {
        if (Transporter* pTrans = objmgr.GetTransporter(Arcemu::Util::GUID_LOPART(plr->transporter_info.guid)))
        {
            if (plr->IsDead())
            {
                plr->ResurrectPlayer();
                plr->SetHealth(plr->GetMaxHealth());
                plr->SetPower(POWER_TYPE_MANA, plr->GetMaxPower(POWER_TYPE_MANA));
            }

            float c_tposx = pTrans->GetPositionX() + plr->transporter_info.x;
            float c_tposy = pTrans->GetPositionY() + plr->transporter_info.y;
            float c_tposz = pTrans->GetPositionZ() + plr->transporter_info.z;

            if (plr->GetMapId() != pTrans->GetMapId())       // loaded wrong map
            {
                plr->SetMapId(pTrans->GetMapId());

                StackWorldPacket<20> dataw(SMSG_NEW_WORLD);

                dataw << pTrans->GetMapId();
                dataw << c_tposx;
                dataw << c_tposy;
                dataw << c_tposz;
                dataw << plr->GetOrientation();

                SendPacket(&dataw);

                // shit is sent in worldport ack.
                enter_world = false;
            }

            plr->SetPosition(c_tposx, c_tposy, c_tposz, plr->GetOrientation(), false);
            plr->m_CurrentTransporter = pTrans;
            pTrans->AddPlayer(plr);
        }
    }

    Log.Debug("Login", "Player %s logged in.", plr->GetName());

    sWorld.incrementPlayerCount(plr->GetTeam());

    if (plr->m_FirstLogin)
    {
        if (PlayerCreateInfo* create_info = objmgr.GetPlayerCreateInfo(info->race, info->class_))
        {
            uint32 introid = create_info->introid;
            OutPacket(SMSG_TRIGGER_CINEMATIC, 4, &introid);
        }

        if (sWorld.m_AdditionalFun)    //cebernic: tells people who 's newbie :D
        {
            const int classtext[] = { 0, 5, 6, 8, 9, 11, 0, 4, 3, 7, 0, 10 };
            sWorld.SendLocalizedWorldText(true, "{65}", classtext[(uint32)plr->getClass()], plr->GetName(), (plr->IsTeamHorde() ? "{63}" : "{64}"));
        }
    }

    LOG_DETAIL("WORLD: Created new player for existing players (%s)", plr->GetName());

    // Login time, will be used for played time calc
    plr->m_playedtime[2] = uint32(UNIXTIME);

    //Issue a message telling all guild members that this player has signed on
    if (plr->IsInGuild())
    {
        if (Guild* pGuild = plr->m_playerInfo->guild)
        {
            WorldPacket data(SMSG_GUILD_EVENT, 50);

            data << uint8(GUILD_EVENT_MOTD);
            data << uint8(1);

            if (pGuild->GetMOTD())
                data << pGuild->GetMOTD();
            else
                data << uint8(0);

            SendPacket(&data);

            pGuild->LogGuildEvent(GUILD_EVENT_HASCOMEONLINE, 1, plr->GetName());
        }
    }

    // Send online status to people having this char in friendlist
    _player->Social_TellFriendsOnline();
    // send friend list (for ignores)
    _player->Social_SendFriendList(7);

    plr->SendDungeonDifficulty();
    plr->SendRaidDifficulty();

    plr->SendEquipmentSetList();

#ifndef GM_TICKET_MY_MASTER_COMPATIBLE
    GM_Ticket* ticket = objmgr.GetGMTicketByPlayer(_player->GetGUID());
    if (ticket != NULL)
    {
        //Send status change to gm_sync_channel
        Channel* chn = channelmgr.GetChannel(sWorld.getGmClientChannel().c_str(), _player);
        if (chn)
        {
            std::stringstream ss;
            ss << "GmTicket:" << GM_TICKET_CHAT_OPCODE_ONLINESTATE;
            ss << ":" << ticket->guid;
            ss << ":1";
            chn->Say(_player, ss.str().c_str(), NULL, true);
        }
    }
#endif

    // server Message Of The Day
    SendMOTD();

    //Set current RestState
    if (plr->m_isResting)
        // We are resting at an inn , turn on Zzz
        plr->ApplyPlayerRestState(true);

    //Calculate rest bonus if there is time between lastlogoff and now
    if (plr->m_timeLogoff > 0 && plr->getLevel() < plr->GetMaxLevel())    // if timelogoff = 0 then it's the first login
    {
        uint32 currenttime = uint32(UNIXTIME);
        uint32 timediff = currenttime - plr->m_timeLogoff;

        //Calculate rest bonus
        if (timediff > 0)
            plr->AddCalculatedRestXP(timediff);
    }

    if (info->m_Group)
        info->m_Group->Update();

    if (enter_world && !_player->GetMapMgr())
        plr->AddToWorld();

    sHookInterface.OnFullLogin(_player);

    objmgr.AddPlayer(_player);
}
コード例 #8
0
ファイル: write-po.c プロジェクト: emonty/gettext
/* Return true if the stream is an instance of styled_ostream_t.  */
static inline bool
is_stylable (ostream_t stream)
{
  return IS_INSTANCE (stream, ostream, styled_ostream);
}
コード例 #9
0
ファイル: Battleground.cpp プロジェクト: lev1976g/NoxicCore
void CBattleground::RemovePlayer(Player* plr, bool logout)
{
	m_mainLock.Acquire();

	WorldPacket data(SMSG_BATTLEGROUND_PLAYER_LEFT, 30);
	data << plr->GetGUID();
	if(plr->m_isGmInvisible == false)
	{
		//Don't show invisible gm's leaving the game.
		DistributePacketToAll(&data);
	}
	else
	{
		RemoveInvisGM();
	}

	// Call subclassed virtual method
	OnRemovePlayer(plr);

	// Clean-up
	plr->m_bg = NULL;
	plr->FullHPMP();
	m_players[plr->m_bgTeam].erase(plr);
	memset(&plr->m_bgScore, 0, sizeof(BGScore));

	/* are we in the group? */
	if(plr->GetGroup() == m_groups[plr->m_bgTeam])
		plr->GetGroup()->RemovePlayer(plr->getPlayerInfo());

	// reset team
	plr->ResetTeam();

	/* revive the player if he is dead */
	if(!plr->isAlive())
	{
		plr->SetHealth(plr->GetMaxHealth());
		plr->ResurrectPlayer();
	}

	/* remove buffs */
	plr->RemoveAura(32727); // Arena preparation
	plr->RemoveAura(44521); // BG preparation
	plr->RemoveAura(44535);
	plr->RemoveAura(21074);

	plr->Unroot();

	/* teleport out */
	if(!logout)
	{
		if(!m_ended && !plr->GetSession()->HasGMPermissions())
			plr->CastSpell(plr, BG_DESERTER, true);

		if(!IS_INSTANCE(plr->m_bgEntryPointMap))
		{
			LocationVector vec(plr->m_bgEntryPointX, plr->m_bgEntryPointY, plr->m_bgEntryPointZ, plr->m_bgEntryPointO);
			plr->SafeTeleport(plr->m_bgEntryPointMap, plr->m_bgEntryPointInstance, vec);
		}
		else
		{
			LocationVector vec(plr->GetBindPositionX(), plr->GetBindPositionY(), plr->GetBindPositionZ());
			plr->SafeTeleport(plr->GetBindMapId(), 0, vec);
		}

		BattlegroundManager.SendBattlefieldStatus(plr, BGSTATUS_NOFLAGS, 0, 0, 0, 0, 0);
	}

	if(/*!m_ended && */m_players[0].size() == 0 && m_players[1].size() == 0)
	{
		/* create an inactive event */
		sEventMgr.RemoveEvents(this, EVENT_BATTLEGROUND_CLOSE);                  // 10mins
		//sEventMgr.AddEvent(this, &CBattleground::Close, EVENT_BATTLEGROUND_CLOSE, 600000, 1,0); //this is BS..appears to be		the cause if the battleground crashes.
		this->Close();
	}

	plr->m_bgTeam = plr->GetTeam();

	m_mainLock.Release();
}
コード例 #10
0
ファイル: wren_vm.c プロジェクト: zeckalpha/wren
// The main bytecode interpreter loop. This is where the magic happens. It is
// also, as you can imagine, highly performance critical. Returns `true` if the
// fiber completed without error.
static bool runInterpreter(WrenVM* vm)
{
  // Hoist these into local variables. They are accessed frequently in the loop
  // but assigned less frequently. Keeping them in locals and updating them when
  // a call frame has been pushed or popped gives a large speed boost.
  register ObjFiber* fiber = vm->fiber;
  register CallFrame* frame;
  register Value* stackStart;
  register uint8_t* ip;
  register ObjFn* fn;

  // These macros are designed to only be invoked within this function.
  #define PUSH(value)  (*fiber->stackTop++ = value)
  #define POP()        (*(--fiber->stackTop))
  #define DROP()       (fiber->stackTop--)
  #define PEEK()       (*(fiber->stackTop - 1))
  #define PEEK2()      (*(fiber->stackTop - 2))
  #define READ_BYTE()  (*ip++)
  #define READ_SHORT() (ip += 2, (ip[-2] << 8) | ip[-1])

  // Use this before a CallFrame is pushed to store the local variables back
  // into the current one.
  #define STORE_FRAME() frame->ip = ip

  // Use this after a CallFrame has been pushed or popped to refresh the local
  // variables.
  #define LOAD_FRAME()                                 \
      frame = &fiber->frames[fiber->numFrames - 1];    \
      stackStart = frame->stackStart;                  \
      ip = frame->ip;                                  \
      if (frame->fn->type == OBJ_FN)                   \
      {                                                \
        fn = (ObjFn*)frame->fn;                        \
      }                                                \
      else                                             \
      {                                                \
        fn = ((ObjClosure*)frame->fn)->fn;             \
      }

  // Terminates the current fiber with error string [error]. If another calling
  // fiber is willing to catch the error, transfers control to it, otherwise
  // exits the interpreter.
  #define RUNTIME_ERROR(error)                         \
      do {                                             \
        STORE_FRAME();                                 \
        fiber = runtimeError(vm, fiber, error);        \
        if (fiber == NULL) return false;               \
        LOAD_FRAME();                                  \
        DISPATCH();                                    \
      }                                                \
      while (false)

  #if WREN_COMPUTED_GOTO

  // Note that the order of instructions here must exacly match the Code enum
  // in wren_vm.h or horrendously bad things happen.
  static void* dispatchTable[] = {
    &&code_CONSTANT,
    &&code_NULL,
    &&code_FALSE,
    &&code_TRUE,
    &&code_LOAD_LOCAL_0,
    &&code_LOAD_LOCAL_1,
    &&code_LOAD_LOCAL_2,
    &&code_LOAD_LOCAL_3,
    &&code_LOAD_LOCAL_4,
    &&code_LOAD_LOCAL_5,
    &&code_LOAD_LOCAL_6,
    &&code_LOAD_LOCAL_7,
    &&code_LOAD_LOCAL_8,
    &&code_LOAD_LOCAL,
    &&code_STORE_LOCAL,
    &&code_LOAD_UPVALUE,
    &&code_STORE_UPVALUE,
    &&code_LOAD_GLOBAL,
    &&code_STORE_GLOBAL,
    &&code_LOAD_FIELD_THIS,
    &&code_STORE_FIELD_THIS,
    &&code_LOAD_FIELD,
    &&code_STORE_FIELD,
    &&code_POP,
    &&code_CALL_0,
    &&code_CALL_1,
    &&code_CALL_2,
    &&code_CALL_3,
    &&code_CALL_4,
    &&code_CALL_5,
    &&code_CALL_6,
    &&code_CALL_7,
    &&code_CALL_8,
    &&code_CALL_9,
    &&code_CALL_10,
    &&code_CALL_11,
    &&code_CALL_12,
    &&code_CALL_13,
    &&code_CALL_14,
    &&code_CALL_15,
    &&code_CALL_16,
    &&code_SUPER_0,
    &&code_SUPER_1,
    &&code_SUPER_2,
    &&code_SUPER_3,
    &&code_SUPER_4,
    &&code_SUPER_5,
    &&code_SUPER_6,
    &&code_SUPER_7,
    &&code_SUPER_8,
    &&code_SUPER_9,
    &&code_SUPER_10,
    &&code_SUPER_11,
    &&code_SUPER_12,
    &&code_SUPER_13,
    &&code_SUPER_14,
    &&code_SUPER_15,
    &&code_SUPER_16,
    &&code_JUMP,
    &&code_LOOP,
    &&code_JUMP_IF,
    &&code_AND,
    &&code_OR,
    &&code_IS,
    &&code_CLOSE_UPVALUE,
    &&code_RETURN,
    &&code_LIST,
    &&code_CLOSURE,
    &&code_CLASS,
    &&code_METHOD_INSTANCE,
    &&code_METHOD_STATIC,
    &&code_END
  };

  #define INTERPRET_LOOP    DISPATCH();
  #define CASE_CODE(name)   code_##name

  #if WREN_DEBUG_TRACE_INSTRUCTIONS
    // Prints the stack and instruction before each instruction is executed.
    #define DISPATCH() \
        { \
          wrenDebugPrintStack(fiber); \
          wrenDebugPrintInstruction(vm, fn, (int)(ip - fn->bytecode)); \
          instruction = *ip++; \
          goto *dispatchTable[instruction]; \
        }
  #else

    #define DISPATCH()      goto *dispatchTable[instruction = READ_BYTE()];

  #endif

  #else

  #define INTERPRET_LOOP    for (;;) switch (instruction = READ_BYTE())
  #define CASE_CODE(name)   case CODE_##name
  #define DISPATCH()        break

  #endif

  LOAD_FRAME();

  Code instruction;
  INTERPRET_LOOP
  {
    CASE_CODE(LOAD_LOCAL_0):
    CASE_CODE(LOAD_LOCAL_1):
    CASE_CODE(LOAD_LOCAL_2):
    CASE_CODE(LOAD_LOCAL_3):
    CASE_CODE(LOAD_LOCAL_4):
    CASE_CODE(LOAD_LOCAL_5):
    CASE_CODE(LOAD_LOCAL_6):
    CASE_CODE(LOAD_LOCAL_7):
    CASE_CODE(LOAD_LOCAL_8):
      PUSH(stackStart[instruction - CODE_LOAD_LOCAL_0]);
      DISPATCH();

    CASE_CODE(LOAD_LOCAL):
      PUSH(stackStart[READ_BYTE()]);
      DISPATCH();

    CASE_CODE(LOAD_FIELD_THIS):
    {
      int field = READ_BYTE();
      Value receiver = stackStart[0];
      ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
      ObjInstance* instance = AS_INSTANCE(receiver);
      ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field.");
      PUSH(instance->fields[field]);
      DISPATCH();
    }

    CASE_CODE(POP):   DROP(); DISPATCH();
    CASE_CODE(NULL):  PUSH(NULL_VAL); DISPATCH();
    CASE_CODE(FALSE): PUSH(FALSE_VAL); DISPATCH();
    CASE_CODE(TRUE):  PUSH(TRUE_VAL); DISPATCH();

    CASE_CODE(CALL_0):
    CASE_CODE(CALL_1):
    CASE_CODE(CALL_2):
    CASE_CODE(CALL_3):
    CASE_CODE(CALL_4):
    CASE_CODE(CALL_5):
    CASE_CODE(CALL_6):
    CASE_CODE(CALL_7):
    CASE_CODE(CALL_8):
    CASE_CODE(CALL_9):
    CASE_CODE(CALL_10):
    CASE_CODE(CALL_11):
    CASE_CODE(CALL_12):
    CASE_CODE(CALL_13):
    CASE_CODE(CALL_14):
    CASE_CODE(CALL_15):
    CASE_CODE(CALL_16):
    {
      // Add one for the implicit receiver argument.
      int numArgs = instruction - CODE_CALL_0 + 1;
      int symbol = READ_SHORT();

      Value receiver = *(fiber->stackTop - numArgs);
      ObjClass* classObj = wrenGetClassInline(vm, receiver);

      // If the class's method table doesn't include the symbol, bail.
      if (symbol >= classObj->methods.count)
      {
        RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
      }

      Method* method = &classObj->methods.data[symbol];
      switch (method->type)
      {
        case METHOD_PRIMITIVE:
        {
          Value* args = fiber->stackTop - numArgs;

          // After calling this, the result will be in the first arg slot.
          switch (method->fn.primitive(vm, fiber, args))
          {
            case PRIM_VALUE:
              // The result is now in the first arg slot. Discard the other
              // stack slots.
              fiber->stackTop -= numArgs - 1;
              break;

            case PRIM_ERROR:
              RUNTIME_ERROR(AS_STRING(args[0]));

            case PRIM_CALL:
              STORE_FRAME();
              callFunction(fiber, AS_OBJ(args[0]), numArgs);
              LOAD_FRAME();
              break;

            case PRIM_RUN_FIBER:
              STORE_FRAME();
              fiber = AS_FIBER(args[0]);
              LOAD_FRAME();
              break;
          }
          break;
        }

        case METHOD_FOREIGN:
          callForeign(vm, fiber, method->fn.foreign, numArgs);
          break;

        case METHOD_BLOCK:
          STORE_FRAME();
          callFunction(fiber, method->fn.obj, numArgs);
          LOAD_FRAME();
          break;

        case METHOD_NONE:
          RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
          break;
      }
      DISPATCH();
    }

    CASE_CODE(STORE_LOCAL):
      stackStart[READ_BYTE()] = PEEK();
      DISPATCH();

    CASE_CODE(CONSTANT):
      PUSH(fn->constants[READ_SHORT()]);
      DISPATCH();

    CASE_CODE(SUPER_0):
    CASE_CODE(SUPER_1):
    CASE_CODE(SUPER_2):
    CASE_CODE(SUPER_3):
    CASE_CODE(SUPER_4):
    CASE_CODE(SUPER_5):
    CASE_CODE(SUPER_6):
    CASE_CODE(SUPER_7):
    CASE_CODE(SUPER_8):
    CASE_CODE(SUPER_9):
    CASE_CODE(SUPER_10):
    CASE_CODE(SUPER_11):
    CASE_CODE(SUPER_12):
    CASE_CODE(SUPER_13):
    CASE_CODE(SUPER_14):
    CASE_CODE(SUPER_15):
    CASE_CODE(SUPER_16):
    {
      // TODO: Almost completely copied from CALL. Unify somehow.

      // Add one for the implicit receiver argument.
      int numArgs = instruction - CODE_SUPER_0 + 1;
      int symbol = READ_SHORT();

      Value receiver = *(fiber->stackTop - numArgs);
      ObjClass* classObj = wrenGetClassInline(vm, receiver);

      // Ignore methods defined on the receiver's immediate class.
      classObj = classObj->superclass;

      // If the class's method table doesn't include the symbol, bail.
      if (symbol >= classObj->methods.count)
      {
        RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
      }

      Method* method = &classObj->methods.data[symbol];
      switch (method->type)
      {
        case METHOD_PRIMITIVE:
        {
          Value* args = fiber->stackTop - numArgs;

          // After calling this, the result will be in the first arg slot.
          switch (method->fn.primitive(vm, fiber, args))
          {
            case PRIM_VALUE:
              // The result is now in the first arg slot. Discard the other
              // stack slots.
              fiber->stackTop -= numArgs - 1;
              break;

            case PRIM_ERROR:
              RUNTIME_ERROR(AS_STRING(args[0]));

            case PRIM_CALL:
              STORE_FRAME();
              callFunction(fiber, AS_OBJ(args[0]), numArgs);
              LOAD_FRAME();
              break;

            case PRIM_RUN_FIBER:
              STORE_FRAME();
              fiber = AS_FIBER(args[0]);
              LOAD_FRAME();
              break;
          }
          break;
        }

        case METHOD_FOREIGN:
          callForeign(vm, fiber, method->fn.foreign, numArgs);
          break;

        case METHOD_BLOCK:
          STORE_FRAME();
          callFunction(fiber, method->fn.obj, numArgs);
          LOAD_FRAME();
          break;

        case METHOD_NONE:
          RUNTIME_ERROR(methodNotFound(vm, classObj, symbol));
          break;
      }
      DISPATCH();
    }

    CASE_CODE(LOAD_UPVALUE):
    {
      Upvalue** upvalues = ((ObjClosure*)frame->fn)->upvalues;
      PUSH(*upvalues[READ_BYTE()]->value);
      DISPATCH();
    }

    CASE_CODE(STORE_UPVALUE):
    {
      Upvalue** upvalues = ((ObjClosure*)frame->fn)->upvalues;
      *upvalues[READ_BYTE()]->value = PEEK();
      DISPATCH();
    }

    CASE_CODE(LOAD_GLOBAL):
      PUSH(vm->globals.data[READ_SHORT()]);
      DISPATCH();

    CASE_CODE(STORE_GLOBAL):
      vm->globals.data[READ_SHORT()] = PEEK();
      DISPATCH();

    CASE_CODE(STORE_FIELD_THIS):
    {
      int field = READ_BYTE();
      Value receiver = stackStart[0];
      ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
      ObjInstance* instance = AS_INSTANCE(receiver);
      ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field.");
      instance->fields[field] = PEEK();
      DISPATCH();
    }

    CASE_CODE(LOAD_FIELD):
    {
      int field = READ_BYTE();
      Value receiver = POP();
      ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
      ObjInstance* instance = AS_INSTANCE(receiver);
      ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field.");
      PUSH(instance->fields[field]);
      DISPATCH();
    }

    CASE_CODE(STORE_FIELD):
    {
      int field = READ_BYTE();
      Value receiver = POP();
      ASSERT(IS_INSTANCE(receiver), "Receiver should be instance.");
      ObjInstance* instance = AS_INSTANCE(receiver);
      ASSERT(field < instance->obj.classObj->numFields, "Out of bounds field.");
      instance->fields[field] = PEEK();
      DISPATCH();
    }

    CASE_CODE(JUMP):
    {
      int offset = READ_SHORT();
      ip += offset;
      DISPATCH();
    }

    CASE_CODE(LOOP):
    {
      // Jump back to the top of the loop.
      int offset = READ_SHORT();
      ip -= offset;
      DISPATCH();
    }

    CASE_CODE(JUMP_IF):
    {
      int offset = READ_SHORT();
      Value condition = POP();

      if (IS_FALSE(condition) || IS_NULL(condition)) ip += offset;
      DISPATCH();
    }

    CASE_CODE(AND):
    {
      int offset = READ_SHORT();
      Value condition = PEEK();

      if (IS_FALSE(condition) || IS_NULL(condition))
      {
        // Short-circuit the right hand side.
        ip += offset;
      }
      else
      {
        // Discard the condition and evaluate the right hand side.
        DROP();
      }
      DISPATCH();
    }

    CASE_CODE(OR):
    {
      int offset = READ_SHORT();
      Value condition = PEEK();

      if (IS_FALSE(condition) || IS_NULL(condition))
      {
        // Discard the condition and evaluate the right hand side.
        DROP();
      }
      else
      {
        // Short-circuit the right hand side.
        ip += offset;
      }
      DISPATCH();
    }

    CASE_CODE(IS):
    {
      Value expected = POP();
      if (!IS_CLASS(expected))
      {
        const char* message = "Right operand must be a class.";
        RUNTIME_ERROR(AS_STRING(wrenNewString(vm, message, strlen(message))));
      }

      ObjClass* actual = wrenGetClass(vm, POP());
      bool isInstance = false;

      // Walk the superclass chain looking for the class.
      while (actual != NULL)
      {
        if (actual == AS_CLASS(expected))
        {
          isInstance = true;
          break;
        }
        actual = actual->superclass;
      }
      PUSH(BOOL_VAL(isInstance));
      DISPATCH();
    }

    CASE_CODE(CLOSE_UPVALUE):
      closeUpvalue(fiber);
      DROP();
      DISPATCH();

    CASE_CODE(RETURN):
    {
      Value result = POP();
      fiber->numFrames--;

      // Close any upvalues still in scope.
      Value* firstValue = stackStart;
      while (fiber->openUpvalues != NULL &&
             fiber->openUpvalues->value >= firstValue)
      {
        closeUpvalue(fiber);
      }

      // If the fiber is complete, end it.
      if (fiber->numFrames == 0)
      {
        // If this is the main fiber, we're done.
        if (fiber->caller == NULL) return true;

        // We have a calling fiber to resume.
        fiber = fiber->caller;

        // Store the result in the resuming fiber.
        *(fiber->stackTop - 1) = result;
      }
      else
      {
        // Store the result of the block in the first slot, which is where the
        // caller expects it.
        stackStart[0] = result;

        // Discard the stack slots for the call frame (leaving one slot for the
        // result).
        fiber->stackTop = frame->stackStart + 1;
      }

      LOAD_FRAME();
      DISPATCH();
    }

    CASE_CODE(LIST):
    {
      int numElements = READ_BYTE();
      ObjList* list = wrenNewList(vm, numElements);
      // TODO: Do a straight memcopy.
      for (int i = 0; i < numElements; i++)
      {
        list->elements[i] = *(fiber->stackTop - numElements + i);
      }

      // Discard the elements.
      fiber->stackTop -= numElements;

      PUSH(OBJ_VAL(list));
      DISPATCH();
    }

    CASE_CODE(CLOSURE):
    {
      ObjFn* prototype = AS_FN(fn->constants[READ_SHORT()]);

      ASSERT(prototype->numUpvalues > 0,
             "Should not create closure for functions that don't need it.");

      // Create the closure and push it on the stack before creating upvalues
      // so that it doesn't get collected.
      ObjClosure* closure = wrenNewClosure(vm, prototype);
      PUSH(OBJ_VAL(closure));

      // Capture upvalues.
      for (int i = 0; i < prototype->numUpvalues; i++)
      {
        bool isLocal = READ_BYTE();
        int index = READ_BYTE();
        if (isLocal)
        {
          // Make an new upvalue to close over the parent's local variable.
          closure->upvalues[i] = captureUpvalue(vm, fiber,
                                                frame->stackStart + index);
        }
        else
        {
          // Use the same upvalue as the current call frame.
          closure->upvalues[i] = ((ObjClosure*)frame->fn)->upvalues[index];
        }
      }

      DISPATCH();
    }

    CASE_CODE(CLASS):
    {
      ObjString* name = AS_STRING(PEEK2());

      ObjClass* superclass;
      if (IS_NULL(PEEK()))
      {
        // Implicit Object superclass.
        superclass = vm->objectClass;
      }
      else
      {
        // TODO: Handle the superclass not being a class object!
        superclass = AS_CLASS(PEEK());
      }

      int numFields = READ_BYTE();

      ObjClass* classObj = wrenNewClass(vm, superclass, numFields, name);

      // Don't pop the superclass and name off the stack until the subclass is
      // done being created, to make sure it doesn't get collected.
      DROP();
      DROP();

      // Now that we know the total number of fields, make sure we don't
      // overflow.
      if (superclass->numFields + numFields > MAX_FIELDS)
      {
        char message[70 + MAX_VARIABLE_NAME];
        snprintf(message, 70 + MAX_VARIABLE_NAME,
            "Class '%s' may not have more than %d fields, including inherited "
            "ones.", name->value, MAX_FIELDS);

        RUNTIME_ERROR(AS_STRING(wrenNewString(vm, message, strlen(message))));
      }

      PUSH(OBJ_VAL(classObj));
      DISPATCH();
    }

    CASE_CODE(METHOD_INSTANCE):
    CASE_CODE(METHOD_STATIC):
    {
      int type = instruction;
      int symbol = READ_SHORT();
      ObjClass* classObj = AS_CLASS(PEEK());
      Value method = PEEK2();
      bindMethod(vm, type, symbol, classObj, method);
      DROP();
      DROP();
      DISPATCH();
    }

    CASE_CODE(END):
      // A CODE_END should always be preceded by a CODE_RETURN. If we get here,
      // the compiler generated wrong code.
      UNREACHABLE();
  }

  // We should only exit this function from an explicit return from CODE_RETURN
  // or a runtime error.
  UNREACHABLE();
  return false;
}

WrenInterpretResult wrenInterpret(WrenVM* vm, const char* sourcePath,
                                  const char* source)
{
  // TODO: Check for freed VM.
  ObjFn* fn = wrenCompile(vm, sourcePath, source);
  if (fn == NULL) return WREN_RESULT_COMPILE_ERROR;

  WREN_PIN(vm, fn);
  vm->fiber = wrenNewFiber(vm, (Obj*)fn);
  WREN_UNPIN(vm);

  if (runInterpreter(vm))
  {
    return WREN_RESULT_SUCCESS;
  }
  else
  {
    return WREN_RESULT_RUNTIME_ERROR;
  }
}