1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-15 22:49:55 +00:00
openmw-tes3mp/apps/openmw/mwmp/LocalPlayer.cpp

749 lines
24 KiB
C++

//
// Created by koncord on 14.01.16.
//
#include <apps/openmw/mwworld/manualref.hpp>
#include <apps/openmw/mwmechanics/aitravel.hpp>
#include <components/esm/esmwriter.hpp>
#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 <apps/openmw/mwdialogue/dialoguemanagerimp.hpp>
#include <apps/openmw/mwworld/inventorystore.hpp>
#include <apps/openmw/mwmechanics/spellcasting.hpp>
#include <apps/openmw/mwgui/inventorywindow.hpp>
#include <components/openmw-mp/Log.hpp>
#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();
updateInventory();
updateDynamicStats();
updateAttributes();
updateSkills();
updateLevel();
}
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<ESM::NPC>()->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<float> health(ptrCreatureStats->getHealth());
MWMechanics::DynamicStat<float> magicka(ptrCreatureStats->getMagicka());
MWMechanics::DynamicStat<float> fatigue(ptrCreatureStats->getFatigue());
static MWMechanics::DynamicStat<float> oldHealth(ptrCreatureStats->getHealth());
static MWMechanics::DynamicStat<float> oldMagicka(ptrCreatureStats->getMagicka());
static MWMechanics::DynamicStat<float> 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->mCellId.mIndex.mX != GetCell()->mCellId.mIndex.mX)
{
shouldUpdate = true;
}
else if (ptrCell->mCellId.mIndex.mY != GetCell()->mCellId.mIndex.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::updateInventory(bool forceUpdate)
{
MWWorld::Ptr player = GetPlayerPtr();
static bool invChanged = false;
if (forceUpdate)
invChanged = 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))
{
invChanged = true;
EquipedItem(slot)->refid = it->getCellRef().getRefId();
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())
{
invChanged = true;
EquipedItem(slot)->refid = "";
EquipedItem(slot)->count = 0;
}
}
if (invChanged)
{
RakNet::BitStream bs;
bs.ResetWritePointer();
GetNetworking()->GetPlayerPacket((RakNet::MessageID) ID_GAME_EQUIPMENT)->Packet(&bs, this, true);
GetNetworking()->SendData(&bs);
invChanged = false;
}
}
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<float> 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()->mCellId.mIndex.mX;
int y = GetCell()->mCellId.mIndex.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<ESM::Class>().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);
ptrInventory.clear();
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; slot++)
{
mwmp::Item *currentItem = EquipedItem(slot);
//printf("Setting currentItem: %s in slot %i\n", currentItem->refid, slot);
if (!currentItem->refid.empty())
{
ptrInventory.equip(slot, ptrInventory.ContainerStore::add(EquipedItem(slot)->refid.c_str(), 1, ptrPlayer), ptrPlayer);
}
}
}
void LocalPlayer::sendClass()
{
MWBase::World *world = MWBase::Environment::get().getWorld();
const ESM::NPC *cpl = world->getPlayerPtr().get<ESM::NPC>()->mBase;
const ESM::Class *cls = world->getStore().get<ESM::Class>().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);
}