// // Created by koncord on 14.01.16. // #include #include #include #include "../mwbase/environment.hpp" #include "../mwstate/statemanagerimp.hpp" #include "../mwinput/inputmanagerimp.hpp" #include "../mwscript/scriptmanagerimp.hpp" #include "../mwgui/windowmanagerimp.hpp" #include "../mwworld/worldimp.hpp" #include "../mwworld/player.hpp" #include "../mwworld/customdata.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwclass/npc.hpp" #include "../mwclass/creature.hpp" #include "../mwmechanics/mechanicsmanagerimp.hpp" #include "../mwworld/cellstore.hpp" #include #include #include #include #include #include "LocalPlayer.hpp" #include "Main.hpp" using namespace mwmp; using namespace std; LocalPlayer::LocalPlayer() { CharGenStage()->current = 0; CharGenStage()->end = 1; } LocalPlayer::~LocalPlayer() { } Networking *LocalPlayer::GetNetworking() { return mwmp::Main::get().getNetworking(); } MWWorld::Ptr LocalPlayer::GetPlayerPtr() { return MWBase::Environment::get().getWorld()->getPlayerPtr(); } void LocalPlayer::Update() { updateCell(); updatePosition(); updateDrawStateAndFlags(); updateAttackState(); updateDeadState(); updateEquipped(); updateDynamicStats(); updateAttributes(); updateSkills(); updateLevel(); updateInventory(); } void LocalPlayer::charGen(int stageFirst, int stageEnd) { CharGenStage()->current = stageFirst; CharGenStage()->end = stageEnd; } bool LocalPlayer::charGenThread() // todo: need fix { MWBase::WindowManager *windowManager = MWBase::Environment::get().getWindowManager(); if (windowManager->isGuiMode()) return false; if (CharGenStage()->current >= CharGenStage()->end) { if (GetNetworking()->isConnected() && CharGenStage()->current == CharGenStage()->end && CharGenStage()->end != 0) { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); (*Npc()) = *player.get()->mBase; (*BirthSign()) = world->getPlayer().getBirthSign(); LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "%s", "Sending ID_GAME_BASE_INFO to server with my CharGen info"); GetNetworking()->GetPlayerPacket(ID_GAME_BASE_INFO)->Send(this); if (CharGenStage()->end != 1) { updateDynamicStats(true); updateAttributes(true); updateSkills(true); updateLevel(true); sendClass(); GetNetworking()->GetPlayerPacket(ID_GAME_CHARGEN)->Send(this); } CharGenStage()->end = 0; /*RakNet::BitStream bs; GetNetworking()->GetPlayerPacket(ID_GAME_BASE_INFO)->Packet(&bs, this, true); GetNetworking()->SendData(&bs);*/ } return true; } switch (CharGenStage()->current) { case 0: windowManager->pushGuiMode(MWGui::GM_Name); break; case 1: windowManager->pushGuiMode(MWGui::GM_Race); break; case 2: windowManager->pushGuiMode(MWGui::GM_Class); break; case 3: windowManager->pushGuiMode(MWGui::GM_Birth); break; default: windowManager->pushGuiMode(MWGui::GM_Review); break; } GetNetworking()->GetPlayerPacket(ID_GAME_CHARGEN)->Send(this); CharGenStage()->current++; return false; } void LocalPlayer::updateDynamicStats(bool forceUpdate) { MWWorld::Ptr player = GetPlayerPtr(); MWMechanics::CreatureStats *ptrCreatureStats = &player.getClass().getCreatureStats(player); MWMechanics::DynamicStat health(ptrCreatureStats->getHealth()); MWMechanics::DynamicStat magicka(ptrCreatureStats->getMagicka()); MWMechanics::DynamicStat fatigue(ptrCreatureStats->getFatigue()); static MWMechanics::DynamicStat oldHealth(ptrCreatureStats->getHealth()); static MWMechanics::DynamicStat oldMagicka(ptrCreatureStats->getMagicka()); static MWMechanics::DynamicStat oldFatigue(ptrCreatureStats->getFatigue()); static float timer = 0; if ((timer += MWBase::Environment::get().getFrameDuration()) >= 0.5 || forceUpdate) { if (oldHealth != health || oldMagicka != magicka || oldFatigue != fatigue || forceUpdate) { oldHealth = health; oldMagicka = magicka; oldFatigue = fatigue; health.writeState(CreatureStats()->mDynamic[0]); magicka.writeState(CreatureStats()->mDynamic[1]); fatigue.writeState(CreatureStats()->mDynamic[2]); timer = 0; GetNetworking()->GetPlayerPacket(ID_GAME_DYNAMICSTATS)->Send(this); } } } void LocalPlayer::updateAttributes(bool forceUpdate) { MWWorld::Ptr player = GetPlayerPtr(); const MWMechanics::NpcStats &ptrNpcStats = player.getClass().getNpcStats(player); bool isUpdating = false; for (int i = 0; i < 8; ++i) { if (ptrNpcStats.getAttribute(i).getBase() != CreatureStats()->mAttributes[i].mBase) { ptrNpcStats.getAttribute(i).writeState(CreatureStats()->mAttributes[i]); isUpdating = true; } } if (isUpdating || forceUpdate) { GetNetworking()->GetPlayerPacket(ID_GAME_ATTRIBUTE)->Send(this); } } void LocalPlayer::updateSkills(bool forceUpdate) { MWWorld::Ptr player = GetPlayerPtr(); const MWMechanics::NpcStats &ptrNpcStats = player.getClass().getNpcStats(player); bool isUpdating = false; for (int i = 0; i < 27; ++i) { if (ptrNpcStats.getSkill(i).getBase() != NpcStats()->mSkills[i].mBase) { ptrNpcStats.getSkill(i).writeState(NpcStats()->mSkills[i]); isUpdating = true; } // If we only have skill progress, update the state for relevant skills // but don't send a packet just because of this (to avoid spam) else if (ptrNpcStats.getSkill(i).getProgress() != NpcStats()->mSkills[i].mProgress) { ptrNpcStats.getSkill(i).writeState(NpcStats()->mSkills[i]); } } for (int i = 0; i < 8; i++) { if (ptrNpcStats.getSkillIncrease(i) != NpcStats()->mSkillIncrease[i]) { NpcStats()->mSkillIncrease[i] = ptrNpcStats.getSkillIncrease(i); } } if (isUpdating || forceUpdate) { NpcStats()->mLevelProgress = ptrNpcStats.getLevelProgress(); GetNetworking()->GetPlayerPacket(ID_GAME_SKILL)->Send(this); } } void LocalPlayer::updateLevel(bool forceUpdate) { MWWorld::Ptr player = GetPlayerPtr(); const MWMechanics::NpcStats &ptrNpcStats = player.getClass().getNpcStats(player); if (ptrNpcStats.getLevel() != CreatureStats()->mLevel || forceUpdate) { CreatureStats()->mLevel = ptrNpcStats.getLevel(); GetNetworking()->GetPlayerPacket(ID_GAME_LEVEL)->Send(this); // Also update skills to refresh level progress and attribute bonuses // for next level up updateSkills(true); } } void LocalPlayer::updatePosition(bool forceUpdate) { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); const MWMechanics::Movement &move = player.getClass().getMovementSettings(player); static bool posChanged = false; static bool isJumping = false; static bool sentJumpEnd = true; ESM::Position ptrPos = player.getRefData().getPosition(); const bool isChangedPos = (move.mPosition[0] != 0 || move.mPosition[1] != 0 || move.mPosition[2] != 0 || move.mRotation[0] != 0 || move.mRotation[1] != 0 || move.mRotation[2] != 0); if (isChangedPos || posChanged || forceUpdate) { posChanged = isChangedPos; if (!isJumping && !world->isOnGround(player) && !world->isFlying(player)) { isJumping = true; } (*Position()) = ptrPos; Dir()->pos[0] = move.mPosition[0]; Dir()->pos[1] = move.mPosition[1]; Dir()->pos[2] = move.mPosition[2]; GetNetworking()->GetPlayerPacket(ID_GAME_POS)->Send(this); } else if (isJumping && world->isOnGround(player)) { isJumping = false; sentJumpEnd = false; } // Packet with jump end position has to be sent one tick after above check else if (!sentJumpEnd) { sentJumpEnd = true; (*Position()) = ptrPos; GetNetworking()->GetPlayerPacket(ID_GAME_POS)->Send(this); } } void LocalPlayer::updateCell(bool forceUpdate) { const ESM::Cell *ptrCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()->getCell(); bool shouldUpdate = false; // Send a packet to server to update this LocalPlayer's cell if: // 1) forceUpdate is true // 2) The LocalPlayer's cell name does not equal the World Player's cell name // 3) The LocalPlayer's exterior cell coordinates do not equal the World Player's // exterior cell coordinates if (forceUpdate) { shouldUpdate = true; } else if (!Misc::StringUtils::ciEqual(ptrCell->mName, GetCell()->mName)) { shouldUpdate = true; } else if (ptrCell->isExterior()) { if (ptrCell->mData.mX != GetCell()->mData.mX) { shouldUpdate = true; } else if (ptrCell->mData.mY != GetCell()->mData.mY) { shouldUpdate = true; } } if (shouldUpdate) { LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "%s", "Sending ID_GAME_CELL to server"); LOG_APPEND(Log::LOG_INFO, "- Moved from %s to %s", GetCell()->getDescription().c_str(), ptrCell->getDescription().c_str()); (*GetCell()) = *ptrCell; // Make sure the position is updated before a cell packet is sent, or else // cell change events in server scripts will have the wrong player position updatePosition(true); RakNet::BitStream bs; GetNetworking()->GetPlayerPacket((RakNet::MessageID) ID_GAME_CELL)->Packet(&bs, this, true); GetNetworking()->SendData(&bs); // Also update skill progress updateSkills(true); } } void LocalPlayer::updateChar() { MWBase::Environment::get().getMechanicsManager()->setPlayerRace( Npc()->mRace, Npc()->isMale(), Npc()->mHead, Npc()->mHair ); MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(*BirthSign()); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); } void LocalPlayer::updateEquipped(bool forceUpdate) { MWWorld::Ptr player = GetPlayerPtr(); static bool equipChanged = false; if (forceUpdate) equipChanged = true; MWWorld::InventoryStore &invStore = player.getClass().getInventoryStore(player); for (int slot = 0; slot < MWWorld::InventoryStore::Slots; slot++) { MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); if (it != invStore.end() && !::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), EquipedItem(slot)->refid)) { equipChanged = true; EquipedItem(slot)->refid = it->getCellRef().getRefId(); EquipedItem(slot)->health = it->getCellRef().getCharge(); if (slot == MWWorld::InventoryStore::Slot_CarriedRight) { MWMechanics::WeaponType weaptype; MWMechanics::getActiveWeapon(player.getClass().getCreatureStats(player), player.getClass().getInventoryStore(player), &weaptype); if (weaptype != MWMechanics::WeapType_Thrown) EquipedItem(slot)->count = 1; } else EquipedItem(slot)->count = invStore.count(it->getCellRef().getRefId()); } else if (it == invStore.end() && !EquipedItem(slot)->refid.empty()) { equipChanged = true; EquipedItem(slot)->refid = ""; EquipedItem(slot)->count = 0; EquipedItem(slot)->health = 0; } } if (equipChanged) { RakNet::BitStream bs; bs.ResetWritePointer(); GetNetworking()->GetPlayerPacket((RakNet::MessageID) ID_GAME_EQUIPMENT)->Packet(&bs, this, true); GetNetworking()->SendData(&bs); equipChanged = false; } } void LocalPlayer::updateInventory(bool forceUpdate) { static bool invChanged = false; if (forceUpdate) invChanged = true; MWWorld::Ptr player = GetPlayerPtr(); MWWorld::InventoryStore &invStore = player.getClass().getInventoryStore(player); mwmp::Item item; if(!invChanged) for (vector::iterator iter = inventory.items.begin(); iter != inventory.items.end(); ++iter) { MWWorld::ContainerStoreIterator result(invStore.begin()); for (; result != invStore.end(); ++result) { item.refid = result->getCellRef().getRefId(); if(item.refid.find("$dynamic") != string::npos) // skip generated items (self enchanted for e.g.) continue; item.count = result->getRefData().getCount(); item.health = result->getCellRef().getCharge(); if(item == (*iter)) break; } if(result == invStore.end()) { invChanged = true; break; } } if (!invChanged) for (MWWorld::ContainerStoreIterator iter(invStore.begin()); iter != invStore.end(); ++iter) { item.refid = iter->getCellRef().getRefId(); if (item.refid.find("$dynamic") != string::npos) // skip generated items (self enchanted for e.g.) continue; item.count = iter->getRefData().getCount(); item.health = iter->getCellRef().getCharge(); vector::iterator result = inventory.items.begin(); for (; result != inventory.items.end(); result++) { if ((*result) == item) break; } if (result == inventory.items.end()) { invChanged = true; break; } } if (!invChanged) return; invChanged = false; inventory.items.clear(); for (MWWorld::ContainerStoreIterator iter(invStore.begin()); iter != invStore.end(); ++iter) { item.refid = iter->getCellRef().getRefId(); if (item.refid.find("$dynamic") != string::npos) // skip generated items (self enchanted for e.g.) continue; item.count = iter->getRefData().getCount(); item.health = iter->getCellRef().getCharge(); inventory.items.push_back(item); } inventory.count = (unsigned int) inventory.items.size(); inventory.action = Inventory::UPDATE; Main::get().getNetworking()->GetPlayerPacket(ID_GAME_INVENTORY)->Send(this); } void LocalPlayer::updateAttackState(bool forceUpdate) { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = GetPlayerPtr(); using namespace MWMechanics; static bool attackPressed = false; // prevent flood MWMechanics::DrawState_ state = player.getClass().getNpcStats(player).getDrawState(); //player.getClass().hit(player, 1, ESM::Weapon::AT_Chop); if (world->getPlayer().getAttackingOrSpell() && !attackPressed) { MWWorld::Ptr weapon = MWWorld::Ptr(); // hand-to-hand //player.getClass().onHit(player, 0.5, true, weapon, 0, 1); if (state == MWMechanics::DrawState_Spell) { const string &spell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); GetAttack()->attacker = guid; GetAttack()->type = 1; GetAttack()->pressed = true; GetAttack()->refid = spell; /*RakNet::BitStream bs; GetNetworking()->GetPlayerPacket((RakNet::MessageID) ID_GAME_ATTACK)->Packet(&bs, this, true); GetNetworking()->SendData(&bs);*/ } else if (state == MWMechanics::DrawState_Weapon) { //PrepareAttack(2); } attackPressed = true; } else if (!world->getPlayer().getAttackingOrSpell() && attackPressed) { if (/*state == MWMechanics::DrawState_Spell ||*/ state == MWMechanics::DrawState_Weapon) { //localNetPlayer->GetAttack()->success = false; //SendAttack(0); } attackPressed = false; } } void LocalPlayer::updateDeadState(bool forceUpdate) { MWWorld::Ptr player = GetPlayerPtr(); MWMechanics::NpcStats *ptrNpcStats = &player.getClass().getNpcStats(player); static bool isDead = false; if (ptrNpcStats->isDead() && !isDead) { CreatureStats()->mDead = true; RakNet::BitStream bs; GetNetworking()->GetPlayerPacket((RakNet::MessageID)ID_GAME_DIE)->Packet(&bs, this, true); GetNetworking()->SendData(&bs); isDead = true; } else if (ptrNpcStats->getHealth().getCurrent() > 0 && isDead) isDead = false; } void LocalPlayer::updateDrawStateAndFlags(bool forceUpdate) { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); MWMechanics::NpcStats ptrNpcStats = player.getClass().getNpcStats(player); using namespace MWMechanics; static bool oldRun = ptrNpcStats.getMovementFlag(CreatureStats::Flag_Run); static bool oldSneak = ptrNpcStats.getMovementFlag(CreatureStats::Flag_Sneak); static bool oldForceJump = ptrNpcStats.getMovementFlag(CreatureStats::Flag_ForceJump); static bool oldForceMoveJump = ptrNpcStats.getMovementFlag(CreatureStats::Flag_ForceMoveJump); bool run = ptrNpcStats.getMovementFlag(CreatureStats::Flag_Run); bool sneak = ptrNpcStats.getMovementFlag(CreatureStats::Flag_Sneak); bool forceJump = ptrNpcStats.getMovementFlag(CreatureStats::Flag_ForceJump); bool forceMoveJump = ptrNpcStats.getMovementFlag(CreatureStats::Flag_ForceMoveJump); bool jump = !world->isOnGround(player) && !world->isFlying(player); static bool onJump = false; MWMechanics::DrawState_ state = player.getClass().getNpcStats(player).getDrawState(); static MWMechanics::DrawState_ oldState = player.getClass().getNpcStats(player).getDrawState(); //static float timer = 0; if (oldRun != run || oldSneak != sneak || oldForceJump != forceJump || oldForceMoveJump != forceMoveJump || oldState != state || ((jump || onJump)/* && (timer += MWBase::Environment::get().getFrameDuration() )> 0.5*/) || forceUpdate) { oldSneak = sneak; oldRun = run; oldForceJump = forceJump; oldForceMoveJump = forceMoveJump; oldState = state; onJump = jump; movementFlags = 0; #define __SETFLAG(flag, value) (value) ? (movementFlags | flag) : (movementFlags & ~flag) movementFlags = __SETFLAG(CreatureStats::Flag_Sneak, sneak); movementFlags = __SETFLAG(CreatureStats::Flag_Run, run); movementFlags = __SETFLAG(CreatureStats::Flag_ForceJump, forceJump); movementFlags = __SETFLAG(CreatureStats::Flag_ForceJump, jump); movementFlags = __SETFLAG(CreatureStats::Flag_ForceMoveJump, forceMoveJump); #undef __SETFLAG if (state == MWMechanics::DrawState_Nothing) (*DrawState()) = 0; else if (state == MWMechanics::DrawState_Weapon) (*DrawState()) = 1; else if (state == MWMechanics::DrawState_Spell) (*DrawState()) = 2; if (jump) mwmp::Main::get().getLocalPlayer()->updatePosition(true); // fix position after jump; RakNet::BitStream bs; GetNetworking()->GetPlayerPacket((RakNet::MessageID) ID_GAME_DRAWSTATE)->Packet(&bs, this, true); GetNetworking()->SendData(&bs); //timer = 0; } } void LocalPlayer::setDynamicStats() { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); MWMechanics::CreatureStats *ptrCreatureStats = &player.getClass().getCreatureStats(player); MWMechanics::DynamicStat dynamicStat; for (int i = 0; i < 3; ++i) { dynamicStat = ptrCreatureStats->getDynamic(i); dynamicStat.setBase(CreatureStats()->mDynamic[i].mBase); dynamicStat.setCurrent(CreatureStats()->mDynamic[i].mCurrent); ptrCreatureStats->setDynamic(i, dynamicStat); } } void LocalPlayer::setAttributes() { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); MWMechanics::CreatureStats *ptrCreatureStats = &player.getClass().getCreatureStats(player); MWMechanics::AttributeValue attributeValue; for (int i = 0; i < 8; ++i) { attributeValue.readState(CreatureStats()->mAttributes[i]); ptrCreatureStats->setAttribute(i, attributeValue); } } void LocalPlayer::setSkills() { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); MWMechanics::NpcStats *ptrNpcStats = &player.getClass().getNpcStats(player); MWMechanics::SkillValue skillValue; for (int i = 0; i < 27; ++i) { skillValue.readState(NpcStats()->mSkills[i]); ptrNpcStats->setSkill(i, skillValue); } for (int i = 0; i < 8; ++i) { ptrNpcStats->setSkillIncrease(i, NpcStats()->mSkillIncrease[i]); } ptrNpcStats->setLevelProgress(NpcStats()->mLevelProgress); } void LocalPlayer::setLevel() { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); MWMechanics::CreatureStats *ptrCreatureStats = &player.getClass().getCreatureStats(player); ptrCreatureStats->setLevel(CreatureStats()->mLevel); } void LocalPlayer::setPosition() { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); world->getPlayer().setTeleported(true); world->moveObject(player, Position()->pos[0], Position()->pos[1], Position()->pos[2]); world->rotateObject(player, Position()->rot[0], Position()->rot[1], Position()->rot[2]); updatePosition(true); } void LocalPlayer::setCell() { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); ESM::Position pos; world->getPlayer().setTeleported(true); int x = GetCell()->mData.mX; int y = GetCell()->mData.mY; if (GetCell()->isExterior()) { world->indexToPosition(x, y, pos.pos[0], pos.pos[1], true); pos.pos[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; world->changeToExteriorCell(pos, true); world->fixPosition(player); } else if (world->findExteriorPosition(GetCell()->mName, pos)) { world->changeToExteriorCell(pos, true); world->fixPosition(player); } else { world->findInteriorPosition(GetCell()->mName, pos); world->changeToInteriorCell(GetCell()->mName, pos, true); } updateCell(true); } void LocalPlayer::setClass() { if (charClass.mId.empty()) // custom class { charClass.mData.mIsPlayable = 0x1; MWBase::Environment::get().getMechanicsManager()->setPlayerClass(charClass); MWBase::Environment::get().getWindowManager()->setPlayerClass(charClass); } else { MWBase::Environment::get().getMechanicsManager()->setPlayerClass(charClass.mId); const ESM::Class *existingCharClass = MWBase::Environment::get().getWorld()->getStore().get().find(charClass.mId); if (existingCharClass) MWBase::Environment::get().getWindowManager()->setPlayerClass(charClass); } } void LocalPlayer::setInventory() { MWWorld::Ptr ptrPlayer = GetPlayerPtr(); MWWorld::InventoryStore &ptrInventory = ptrPlayer.getClass().getInventoryStore(ptrPlayer); for (int slot = 0; slot < MWWorld::InventoryStore::Slots; slot++) { mwmp::Item *currentItem = EquipedItem(slot); if (!currentItem->refid.empty()) { MWWorld::ContainerStoreIterator it = ptrInventory.begin(); for (; it != ptrInventory.end(); ++it) // find item in inventory { if (::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), currentItem->refid)) break; } if (it == ptrInventory.end()) // if not exists add item ptrInventory.equip(slot, ptrInventory.ContainerStore::add(EquipedItem(slot)->refid.c_str(), 1, ptrPlayer), ptrPlayer); else ptrInventory.equip(slot, it, ptrPlayer); } } } void LocalPlayer::sendClass() { MWBase::World *world = MWBase::Environment::get().getWorld(); const ESM::NPC *cpl = world->getPlayerPtr().get()->mBase; const ESM::Class *cls = world->getStore().get().find(cpl->mClass); if (cpl->mClass.find("$dynamic") != string::npos) // custom class { charClass.mId = ""; charClass.mName = cls->mName; charClass.mDescription = cls->mDescription; charClass.mData = cls->mData; } else charClass.mId = cls->mId; GetNetworking()->GetPlayerPacket(ID_GAME_CHARCLASS)->Send(this); } void LocalPlayer::sendAttack(char type) { MWMechanics::DrawState_ state = GetPlayerPtr().getClass().getNpcStats(GetPlayerPtr()).getDrawState(); if (state == MWMechanics::DrawState_Spell) { } else { } GetAttack()->type = type; GetAttack()->pressed = false; RakNet::BitStream bs; GetNetworking()->GetPlayerPacket((RakNet::MessageID) ID_GAME_ATTACK)->Packet(&bs, this, true); GetNetworking()->SendData(&bs); } void LocalPlayer::prepareAttack(char type, bool state) { if (GetAttack()->pressed == state) return; MWMechanics::DrawState_ dstate = GetPlayerPtr().getClass().getNpcStats(GetPlayerPtr()).getDrawState(); if (dstate == MWMechanics::DrawState_Spell) { const string &spell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); GetAttack()->refid = spell; } else { } GetAttack()->pressed = state; GetAttack()->type = type; GetAttack()->knockdown = false; GetAttack()->success = false; GetAttack()->block = false; GetAttack()->target = RakNet::RakNetGUID(); GetAttack()->attacker = guid; RakNet::BitStream bs; GetNetworking()->GetPlayerPacket((RakNet::MessageID) ID_GAME_ATTACK)->Packet(&bs, this, true); GetNetworking()->SendData(&bs); }