diff --git a/src/Client/DefScriptInterface.cpp b/src/Client/DefScriptInterface.cpp index e507bcc..2194c7a 100644 --- a/src/Client/DefScriptInterface.cpp +++ b/src/Client/DefScriptInterface.cpp @@ -176,10 +176,7 @@ bool DefScriptPackage::SCcastspell(CmdSet Set) return false; } - uint32 spellId = 0;// = atoi(Set.defaultarg.c_str()); - uint64 spellTarget = 0;// atoi(Set.arg[0]); - - spellId = atoi(Set.defaultarg.c_str()); + uint32 spellId = atoi(Set.defaultarg.c_str()); if (spellId <= 0) { @@ -187,12 +184,7 @@ bool DefScriptPackage::SCcastspell(CmdSet Set) return false; } - if (spellTarget <= 0) - { - spellTarget = ((PseuInstance*)parentMethod)->GetWSession()->GetGuid(); - } - -// ((PseuInstance*)parentMethod)->GetWSession()->GetPlayerSettings()->CastSpell(spellId, spellTarget); + ((PseuInstance*)parentMethod)->GetWSession()->SendCastSpell(spellId); return true; } diff --git a/src/Client/PseuWoW.cpp b/src/Client/PseuWoW.cpp index bd8d645..126480f 100644 --- a/src/Client/PseuWoW.cpp +++ b/src/Client/PseuWoW.cpp @@ -271,6 +271,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v) enablechatai=(bool)atoi(v.Get("ENABLECHATAI").c_str()); notifyping=(bool)atoi(v.Get("NOTIFYPING").c_str()); showmyopcodes=(bool)atoi(v.Get("SHOWMYOPCODES").c_str()); + disablespellcheck=(bool)atoi(v.Get("DISABLESPELLCHECK").c_str()); // clientversion is a bit more complicated to add { diff --git a/src/Client/PseuWoW.h b/src/Client/PseuWoW.h index 5fb6550..3d495ae 100644 --- a/src/Client/PseuWoW.h +++ b/src/Client/PseuWoW.h @@ -47,6 +47,7 @@ class PseuInstanceConf bool enablechatai; bool notifyping; bool showmyopcodes; + bool disablespellcheck; }; diff --git a/src/Client/World/CMSGConstructor.cpp b/src/Client/World/CMSGConstructor.cpp index 550604f..976eccd 100644 --- a/src/Client/World/CMSGConstructor.cpp +++ b/src/Client/World/CMSGConstructor.cpp @@ -76,9 +76,12 @@ void WorldSession::SendQueryItem(uint32 id, uint64 guid) // is it a guid? not su SendWorldPacket(packet); } +// use ONLY this function to target objects and notify the server about it. +// (server & client need to stay synced) void WorldSession::SendSetSelection(uint64 guid) { - // TODO: MyCharacter.SetTarget(guid); + ASSERT(GetMyChar()) // we need to be logged in to select something + GetMyChar()->SetTarget(guid); logdebug("SetSelection GUID="I64FMT,guid); WorldPacket packet; packet << guid; @@ -86,5 +89,54 @@ void WorldSession::SendSetSelection(uint64 guid) SendWorldPacket(packet); } +void WorldSession::SendCastSpell(uint32 spellid) +{ + if(!spellid) + return; + MyCharacter *my = GetMyChar(); + bool known = my->HasSpell(spellid); + if( (!known) && (!GetInstance()->GetConf()->disablespellcheck) ) + { + logerror("Attempt to cast not-known spell %u",spellid); + return; + } + + Object *target = objmgr.GetObj(my->GetTarget()); + + if(!target) // this is wrong, some spells dont require a target (areaspells, self-only spells) + return; // but for now, this should be ok, until a db is used that provides spell info + + WorldPacket packet; + ByteBuffer temp; + uint16 flags=TARGET_FLAG_SELF; // target mask. spellcast implementeation needs to be changed if TARGET_MASK_SELF is != 0 + packet << spellid; + if(my->GetTarget() != GetGuid()) // self cast? + { + if(target->GetTypeId() == TYPEID_PLAYER || target->GetTypeId() == TYPEID_UNIT) + { + flags |= TARGET_FLAG_UNIT; + temp << (uint8)0xFF << my->GetTarget(); // need to send packed guid? + } + if(target->GetTypeId() == TYPEID_OBJECT) + { + flags |= TARGET_FLAG_OBJECT; + temp << (uint8)0xFF <GetTarget(); // need to send packed guid? + } + // TODO: need implementation of areaspells & item targets (enchant) here (temp << itemGUID)! + // TODO: append floats x,y,z according to target type srcloc & dstloc to temp + // TODO: append string to temp if TARGET_FLAG_STRING is set. what string for what purpose?? + // and whats with TARGET_CORPSE? + } + packet << flags; + packet.append(temp); + + // cast it + packet.SetOpcode(CMSG_CAST_SPELL); + SendWorldPacket(packet); + logdetail("Casting spell %u on target "I64FMT,spellid,my->GetTarget()); + if(!known) + logerror(" - WARNING: spell is NOT known!"); +} + diff --git a/src/Client/World/Item.h b/src/Client/World/Item.h index ba1456e..bf5af58 100644 --- a/src/Client/World/Item.h +++ b/src/Client/World/Item.h @@ -398,13 +398,13 @@ public: uint8 GetSlot(void) { return _slot; } void SetSlot(uint8 nr) { _slot = nr; } uint32 GetEntry() const { return GetUInt32Value(OBJECT_FIELD_ENTRY); } - uint32 GetCount() const { return GetUInt32Value (ITEM_FIELD_STACK_COUNT); } + uint32 GetCount() const { return GetUInt32Value(ITEM_FIELD_STACK_COUNT); } Bag *GetBag(void) { return _bag; } bool IsInBag() const { return _bag != NULL; } protected: uint8 _slot; - Bag *_bag; // not yet implemented + Bag *_bag; }; diff --git a/src/Client/World/ObjMgr.cpp b/src/Client/World/ObjMgr.cpp index 55234ce..1b86e73 100644 --- a/src/Client/World/ObjMgr.cpp +++ b/src/Client/World/ObjMgr.cpp @@ -1,6 +1,11 @@ #include "ObjMgr.h" ObjMgr::~ObjMgr() +{ + RemoveAll(); +} + +void ObjMgr::RemoveAll(void) { for(ItemProtoList::iterator i = _iproto.begin(); i!=_iproto.end(); i++) { @@ -31,6 +36,8 @@ void ObjMgr::Add(Object *o) Object *ObjMgr::GetObj(uint64 guid) { + if(!guid) + return NULL; for(ObjectList::iterator i = _obj.begin(); i!=_obj.end(); i++) if((*i)->GetGUID() == guid) return (*i); diff --git a/src/Client/World/ObjMgr.h b/src/Client/World/ObjMgr.h index f3b36bf..8dd981d 100644 --- a/src/Client/World/ObjMgr.h +++ b/src/Client/World/ObjMgr.h @@ -13,6 +13,7 @@ class ObjMgr { public: ~ObjMgr(); + void RemoveAll(void); // TODO: this needs to be called on SMSG_LOGOUT_COMPLETE once implemented. // Item Prototype functions uint32 GetItemProtoCount(void) { return _iproto.size(); } diff --git a/src/Client/World/Player.cpp b/src/Client/World/Player.cpp index 9befed4..0cc23cd 100644 --- a/src/Client/World/Player.cpp +++ b/src/Client/World/Player.cpp @@ -22,9 +22,9 @@ void Player::Create(uint64 guid) Object::Create(guid); } -MyCharacter::MyCharacter() +MyCharacter::MyCharacter() : Player() { - _castingSpell = false; + SetTarget(0); } void MyCharacter::SetActionButtons(WorldPacket &data) @@ -43,53 +43,20 @@ void MyCharacter::SetSpells(WorldPacket &data) data >> spellid >> spellslot; logdebug("Initial Spell: id=%u slot=%u",spellid,spellslot); - spell _spell; - _spell.spellId = spellid; - _spell.spellSlot = spellslot; + SpellBookEntry _spell; + _spell.id = spellid; + _spell.slot = spellslot; _spells.push_back(_spell); } } -void MyCharacter::CastSpell(uint32 spellId, uint64 target) +uint16 MyCharacter::GetSpellSlot(uint32 spellid) { - /* - if (_castingSpell) - return; - - _castingSpell = !_castingSpell; - - WorldPacket packet; - packet.SetOpcode(CMSG_CAST_SPELL); - packet << spellId << (uint16)2 << (uint8)1 << (uint8)target; // 2 = TARGET_FLAG_UNIT - // Can be bugged, not fully tested, probably doesn't work when the guid is high - // Damn packed guid stuff! xD - - _worldSession->SendWorldPacket(packet); - */ + for(std::vector::iterator i=_spells.begin(); i != _spells.end(); i++) + if(i->id == spellid) + return i->slot; + return 0; } -void MyCharacter::HandleCastResultOpcode(WorldPacket &packet) -{ - /* - uint32 spellId; - uint8 statusFail; - uint8 failProblem; - char l[150]; - - packet >> spellId >> statusFail; - - _castingSpell = false; - - sprintf(l, "Received cast result opcode. Spell = %d, statusFail = %d", spellId, statusFail); - - if (statusFail == 2) // Spell cast failed - { - packet >> failProblem; - sprintf(l, "%s, failProblem = %d", l, failProblem); - } - - - //logdetail(l); - */ -} \ No newline at end of file + \ No newline at end of file diff --git a/src/Client/World/Player.h b/src/Client/World/Player.h index 93919ba..2c15c17 100644 --- a/src/Client/World/Player.h +++ b/src/Client/World/Player.h @@ -175,6 +175,12 @@ private: }; +struct SpellBookEntry +{ + uint32 id; + uint16 slot; +}; + class Player : public Unit { public: @@ -197,19 +203,18 @@ public: void SetActionButtons(WorldPacket &data); void SetSpells(WorldPacket &data); - void CastSpell(uint32 spellId, uint64 target); - void HandleCastResultOpcode(WorldPacket &packet); + uint64 GetTarget(void) { return _target; } + void SetTarget(uint64 guid) { _target = guid; } // should only be called by WorldSession::SendSetSelection() !! + bool HasSpell(uint32 spellid) { return GetSpellSlot(spellid) != 0; } + uint16 GetSpellSlot(uint32 spellid); private: - bool _castingSpell; + // bool _castingSpell; // this is something we dont really need for now - typedef struct - { - uint16 spellId; - uint16 spellSlot; - } spell; - std::vector _spells; + + std::vector _spells; + uint64 _target; // currently targeted object }; diff --git a/src/Client/World/SharedDefines.h b/src/Client/World/SharedDefines.h index 4bf26cb..571e818 100644 --- a/src/Client/World/SharedDefines.h +++ b/src/Client/World/SharedDefines.h @@ -988,4 +988,15 @@ enum ChatMsg CHAT_MSG_LOOT = 0x18, }; +enum SpellCastTargetFlags +{ + TARGET_FLAG_SELF = 0x0000, + TARGET_FLAG_UNIT = 0x0002, + TARGET_FLAG_OBJECT = 0x0800, + TARGET_FLAG_ITEM = 0x1010, + TARGET_FLAG_SOURCE_LOCATION = 0x0020, + TARGET_FLAG_DEST_LOCATION = 0x0040, + TARGET_FLAG_STRING = 0x2000 +}; + #endif diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index ca6c2d1..5c08d77 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -24,10 +24,8 @@ WorldSession::WorldSession(PseuInstance *in) _myGUID=0; // i dont have a guid yet plrNameCache.ReadFromFile(); // load names/guids of known players ItemProtoCache_InsertDataToSession(this); - myCharacter = new MyCharacter(); _deleteme = false; _channels = new Channel(this); -// _playerSettings->Init(this); //... } @@ -366,13 +364,14 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket) return; } else { log("Entering World with Character \"%s\"...",GetInstance()->GetConf()->charname.c_str()); -// _player->Init(plr[i]); + // create the character and add it to the objmgr. + MyCharacter *my = new MyCharacter(); + my->Create(_myGUID); + objmgr.Add(my); WorldPacket pkt; pkt.SetOpcode(CMSG_PLAYER_LOGIN); pkt << _myGUID; - _targetGUID=0; - _followGUID=0; SendWorldPacket(pkt); } } @@ -632,11 +631,23 @@ void WorldSession::_HandleChannelNotifyOpcode(WorldPacket& recvPacket) void WorldSession::_HandleCastResultOpcode(WorldPacket& recvPacket) { -// _playerSettings->HandleCastResultOpcode(recvPacket); + uint32 spellid; + uint8 flag,result; + recvPacket >> spellid >> flag; + if(flag) + { + recvPacket >> result; + logdetail("Cast of spell %u failed. flag=%u, result=%u",spellid,flag,result); + } + else + { + logdetail("Cast of spell %u successful.",spellid); + } } void WorldSession::_HandleInitialSpellsOpcode(WorldPacket& recvPacket) { - myCharacter->SetSpells(recvPacket); + // suggestion for later: what about MyCharacter->AddSpellBookEntry() ? + GetMyChar()->SetSpells(recvPacket); } diff --git a/src/Client/World/WorldSession.h b/src/Client/World/WorldSession.h index 9d3ebc8..0f689e1 100644 --- a/src/Client/World/WorldSession.h +++ b/src/Client/World/WorldSession.h @@ -50,8 +50,7 @@ public: uint64 GetFollowTarget(void) { return _followGUID; } uint64 GetGuid(void) { return _myGUID; } Channel *GetChannels(void) { return _channels; } -// Player *GetPlayer(void) { return _player; } -// PlayerSettings *GetPlayerSettings(void) { return _playerSettings; } + MyCharacter *GetMyChar(void) { ASSERT(_myGUID > 0); return (MyCharacter*)objmgr.GetObj(_myGUID); } // CMSGConstructor @@ -61,9 +60,9 @@ public: void SendEmote(uint32); void SendQueryItem(uint32, uint64); void SendSetSelection(uint64); + void SendCastSpell(uint32); PlayerNameCache plrNameCache; - MyCharacter *myCharacter; ObjMgr objmgr; private: