[11558] Fixes and way work chnages for GO lock/interact state

* Not reset lock/interact state in instances (so until instance reset)
* Do unti-cheating checks for use attempts locked/non-intareactive GOs
* Implement SCRIPT_COMMAND_GO_LOCK_STATE for control lock/interact state of GOs from scripts.

Signed-off-by: VladimirMangos <vladimir@getmangos.com>
This commit is contained in:
Schmoozerd 2011-05-29 04:25:50 +04:00 committed by VladimirMangos
parent 4a087e6bda
commit 0de4e302b3
8 changed files with 98 additions and 10 deletions

View file

@ -218,9 +218,8 @@ spell_scripts
* datalong3 = creature search radius
* data_flags = flag_original_source_as_target = 0x02
flag_buddy_as_target = 0x04 (When this flag is not set, buddy will be the attacker when buddy is defined)
27 SCRIPT_COMMAND_GO_LOCK_STATE source or target must be WorldObject
* datalong = flag_go_lock = 0x01, flag_go_unlock = 0x02,
flag_go_nonInteract = 0x04, flag_go_interact = 0x08
* datalong2 = go entry (searching closest to source (if worldobject) or target
* datalong3 = go search radius

View file

@ -398,7 +398,10 @@ void GameObject::Update(uint32 update_diff, uint32 /*p_time*/)
if (GetGOInfo()->IsDespawnAtAction() || GetGoAnimProgress() > 0)
{
SendObjectDeSpawnAnim(GetObjectGuid());
//reset flags
// reset flags: In Instances do not restore GO_FLAG_LOCKED or GO_FLAG_NO_INTERACT
if (GetMap()->Instanceable())
SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags & ~(GO_FLAG_LOCKED | GO_FLAG_NO_INTERACT));
else
SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags);
}

View file

@ -2869,6 +2869,42 @@ void Map::ScriptsProcess()
sLog.outError("SCRIPT_COMMAND_ATTACK_START (script id %u) unexpected error, attacker or victim could not be found, no action.", step.script->id);
break;
}
case SCRIPT_COMMAND_GO_LOCK_STATE:
{
if ((!source || !source->isType(TYPEMASK_WORLDOBJECT)) && (!target || !target->isType(TYPEMASK_WORLDOBJECT)))
{
sLog.outError("SCRIPT_COMMAND_GO_LOCK_STATE (script id %u) call for non-worldobject (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0);
break;
}
WorldObject* pSearcher = source && source->isType(TYPEMASK_WORLDOBJECT) ? (WorldObject*)source : (WorldObject*)target;
GameObject* pGo = NULL;
MaNGOS::NearestGameObjectEntryInObjectRangeCheck u_check(*pSearcher, step.script->goLockState.goEntry, step.script->goLockState.searchRadius);
MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> searcher(pGo, u_check);
Cell::VisitGridObjects(pSearcher, searcher, step.script->goLockState.searchRadius);
/* flag lockState
* go_lock 0x01
* go_unlock 0x02
* go_nonInteract 0x04
* go_Interact 0x08
*/
if (pGo)
{
// Lock or Unlock
if (step.script->goLockState.lockState & 0x01)
pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED);
else if (step.script->goLockState.lockState & 0x02)
pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED);
// Set Non Interactable or Set Interactable
if (step.script->goLockState.lockState & 0x04)
pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT);
else if (step.script->goLockState.lockState & 0x08)
pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT);
}
}
default:
sLog.outError("Unknown SCRIPT_COMMAND_ %u called for script id %u.",step.script->command, step.script->id);
break;

View file

@ -533,6 +533,32 @@ void ScriptMgr::LoadScripts(ScriptMapMap& scripts, const char* tablename)
}
break;
}
case SCRIPT_COMMAND_GO_LOCK_STATE:
{
if (!ObjectMgr::GetGameObjectInfo(tmp.goLockState.goEntry))
{
sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_GO_LOCK_STATE for script id %u, but this gameobject_template does not exist.", tablename, tmp.goLockState.goEntry, tmp.id);
continue;
}
if (!tmp.goLockState.searchRadius)
{
sLog.outErrorDb("Table `%s` has invalid search radius (datalong3 = %u) in SCRIPT_COMMAND_GO_LOCK_STATE for script id %u.", tablename, tmp.goLockState.searchRadius, tmp.id);
continue;
}
if (// lock(0x01) and unlock(0x02) together
((tmp.goLockState.lockState & 0x01) && (tmp.goLockState.lockState & 0x02)) ||
// non-interact (0x4) and interact (0x08) together
((tmp.goLockState.lockState & 0x04) && (tmp.goLockState.lockState & 0x08)) ||
// no setting
!tmp.goLockState.lockState ||
// invalid number
tmp.goLockState.lockState >= 0x10)
{
sLog.outErrorDb("Table `%s` has invalid lock state (datalong = %u) in SCRIPT_COMMAND_GO_LOCK_STATE for script id %u.", tablename, tmp.goLockState.lockState, tmp.id);
continue;
}
break;
}
}
if (scripts.find(tmp.id) == scripts.end())

View file

@ -92,6 +92,9 @@ enum eScriptCommand
// datalong2=creature entry, datalong3=search radius
SCRIPT_COMMAND_ATTACK_START = 26, // source = Creature (or WorldObject when creature entry are defined), target = Player
// datalong2 = creature entry (searching for a buddy, closest to source), datalong3 = creature search radius
SCRIPT_COMMAND_GO_LOCK_STATE = 27, // source or target must be WorldObject
// datalong= 1=lock, 2=unlock, 4=set not-interactable, 8=set interactable
// datalong2= go entry, datalong3= go search radius
};
#define MAX_TEXT_ID 4 // used for SCRIPT_COMMAND_TALK
@ -284,6 +287,13 @@ struct ScriptInfo
uint32 flags; // data_flags
} attack;
struct // SCRIPT_COMMAND_GO_LOCK_STATE (27)
{
uint32 lockState; // datalong
uint32 goEntry; // datalong2
uint32 searchRadius; // datalong3
} goLockState;
struct
{
uint32 data[9];

View file

@ -1258,7 +1258,7 @@ enum GameObjectFlags
GO_FLAG_LOCKED = 0x00000002, //require key, spell, event, etc to be opened. Makes "Locked" appear in tooltip
GO_FLAG_INTERACT_COND = 0x00000004, //cannot interact (condition to interact)
GO_FLAG_TRANSPORT = 0x00000008, //any kind of transport? Object can transport (elevator, boat, car)
GO_FLAG_UNK1 = 0x00000010, //
GO_FLAG_NO_INTERACT = 0x00000010, //players cannot interact with this go (often need to remove flag in event)
GO_FLAG_NODESPAWN = 0x00000020, //never despawn, typically for doors, they just change state
GO_FLAG_TRIGGERED = 0x00000040, //typically, summoned objects. Triggered by spell or other events
GO_FLAG_UNK_8 = 0x00000080,

View file

@ -289,6 +289,13 @@ void WorldSession::HandleGameObjectUseOpcode( WorldPacket & recv_data )
if(!obj)
return;
// Additional check preventing exploits (ie loot despawned chests)
if (!obj->isSpawned())
{
sLog.outError("HandleGameObjectUseOpcode: CMSG_GAMEOBJ_USE for despawned GameObject (Entry %u), didn't expect this to happen.", obj->GetEntry());
return;
}
// Never expect this opcode for some type GO's
if (obj->GetGoType() == GAMEOBJECT_TYPE_GENERIC)
{
@ -296,6 +303,13 @@ void WorldSession::HandleGameObjectUseOpcode( WorldPacket & recv_data )
return;
}
// Never expect this opcode for non intractable GO's
if (obj->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT))
{
sLog.outError("HandleGameObjectUseOpcode: CMSG_GAMEOBJ_USE for GameObject (Entry %u) with non intractable flag (Flags %u), didn't expect this to happen.", obj->GetEntry(), obj->GetUInt32Value(GAMEOBJECT_FLAGS));
return;
}
obj->Use(_player);
}

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "11557"
#define REVISION_NR "11558"
#endif // __REVISION_NR_H__