mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 09:31:30 +00:00
Traps overhaul. New functionality has been added, while preserving the old functionality. Numerous bug fixes occurred as well.
Added column triggered_number. If this is set, then the trap will despawn after it has been triggered this number of times. If 0, the trap will never despawn on its own. Added group column. This allows developers to group traps together in a similar way as spawngroups for NPCs. When a trap that is grouped is despawned in anyway, a random trap in the group will take its place. Grouped traps do not have to be at the same coords or have the same type. This can allow for some spawning diversity if so required. If set to 0, the trap is not grouped and will always respawn. Added column despawn_when_triggered. If set to 1, then a trap will despawn when a player triggers it. If 0, then there will be a 5 second reset time and then the same trap will again be active. (Assuming triggered_number has not been reached.) The player that triggered the trap will not re-trigger it until they have left and re-enetered the trap's radius. Traps will no longer trigger on players that are currently zoning. This fixes some weirdness and at least one crash. The trap can trigger however after the connection is been completed. If a player camped out in a trap radius they can potentially still be hit. Alarm type traps were not using effectvalue2 to determine who should be aggroed. This is now fixed. Traps will no longer be broken by #repop, #depopzone, or #reloadworld. All 3 commands will now have the same effect on traps as they do for NPCs. Added command #reloadtraps. This reloads all of the traps in the zone. Added command #trapinfo. This gives some information about the traps currently spawned in the zone. Added Traps logsys category Required SQL: utils/sql/git/required/2017_10_26_traps.sql
This commit is contained in:
parent
10477d3795
commit
ed98aa45d2
@ -89,6 +89,7 @@ enum LogCategory {
|
|||||||
HP_Update,
|
HP_Update,
|
||||||
FixZ,
|
FixZ,
|
||||||
Food,
|
Food,
|
||||||
|
Traps,
|
||||||
MaxCategoryID /* Don't Remove this*/
|
MaxCategoryID /* Don't Remove this*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -142,7 +143,8 @@ static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
|
|||||||
"Headless Client",
|
"Headless Client",
|
||||||
"HP Update",
|
"HP Update",
|
||||||
"FixZ",
|
"FixZ",
|
||||||
"Food"
|
"Food",
|
||||||
|
"Traps"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
utils/sql/git/required/2017_10_28_traps.sql
Normal file
3
utils/sql/git/required/2017_10_28_traps.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
alter table `traps` add column `triggered_number` tinyint(4) not null default 0;
|
||||||
|
alter table `traps` add column `group` tinyint(4) not null default 0;
|
||||||
|
alter table `traps` add column `despawn_when_triggered` tinyint(4) not null default 0;
|
||||||
@ -331,6 +331,8 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
|
|
||||||
interrogateinv_flag = false;
|
interrogateinv_flag = false;
|
||||||
|
|
||||||
|
trapid = 0;
|
||||||
|
|
||||||
for (int i = 0; i < InnateSkillMax; ++i)
|
for (int i = 0; i < InnateSkillMax; ++i)
|
||||||
m_pp.InnateSkills[i] = InnateDisabled;
|
m_pp.InnateSkills[i] = InnateDisabled;
|
||||||
|
|
||||||
|
|||||||
@ -1302,6 +1302,8 @@ public:
|
|||||||
|
|
||||||
int32 CalcATK();
|
int32 CalcATK();
|
||||||
|
|
||||||
|
uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Mob;
|
friend class Mob;
|
||||||
void CalcItemBonuses(StatBonuses* newbon);
|
void CalcItemBonuses(StatBonuses* newbon);
|
||||||
|
|||||||
@ -5337,8 +5337,8 @@ void Client::Handle_OP_DisarmTraps(const EQApplicationPacket *app)
|
|||||||
{
|
{
|
||||||
Message(MT_Skills, "You disarm a trap.");
|
Message(MT_Skills, "You disarm a trap.");
|
||||||
trap->disarmed = true;
|
trap->disarmed = true;
|
||||||
trap->chkarea_timer.Disable();
|
Log(Logs::General, Logs::Traps, "Trap %d is disarmed.", trap->trap_id);
|
||||||
trap->respawn_timer.Start((trap->respawn_time + zone->random.Int(0, trap->respawn_var)) * 1000);
|
trap->UpdateTrap();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -321,6 +321,7 @@ int command_init(void)
|
|||||||
command_add("reloadqst", " - Clear quest cache (any argument causes it to also stop all timers)", 150, command_reloadqst) ||
|
command_add("reloadqst", " - Clear quest cache (any argument causes it to also stop all timers)", 150, command_reloadqst) ||
|
||||||
command_add("reloadrulesworld", "Executes a reload of all rules in world specifically.", 80, command_reloadworldrules) ||
|
command_add("reloadrulesworld", "Executes a reload of all rules in world specifically.", 80, command_reloadworldrules) ||
|
||||||
command_add("reloadstatic", "- Reload Static Zone Data", 150, command_reloadstatic) ||
|
command_add("reloadstatic", "- Reload Static Zone Data", 150, command_reloadstatic) ||
|
||||||
|
command_add("reloadtraps", "- Repops all traps in the current zone.", 80, command_reloadtraps) ||
|
||||||
command_add("reloadtitles", "- Reload player titles from the database", 150, command_reloadtitles) ||
|
command_add("reloadtitles", "- Reload player titles from the database", 150, command_reloadtitles) ||
|
||||||
command_add("reloadworld", "[0|1] - Clear quest cache (0 - no repop, 1 - repop)", 255, command_reloadworld) ||
|
command_add("reloadworld", "[0|1] - Clear quest cache (0 - no repop, 1 - repop)", 255, command_reloadworld) ||
|
||||||
command_add("reloadzps", "- Reload zone points from database", 150, command_reloadzps) ||
|
command_add("reloadzps", "- Reload zone points from database", 150, command_reloadzps) ||
|
||||||
@ -382,6 +383,7 @@ int command_init(void)
|
|||||||
command_add("title", "[text] [1 = create title table row] - Set your or your player target's title", 50, command_title) ||
|
command_add("title", "[text] [1 = create title table row] - Set your or your player target's title", 50, command_title) ||
|
||||||
command_add("titlesuffix", "[text] [1 = create title table row] - Set your or your player target's title suffix", 50, command_titlesuffix) ||
|
command_add("titlesuffix", "[text] [1 = create title table row] - Set your or your player target's title suffix", 50, command_titlesuffix) ||
|
||||||
command_add("traindisc", "[level] - Trains all the disciplines usable by the target, up to level specified. (may freeze client for a few seconds)", 150, command_traindisc) ||
|
command_add("traindisc", "[level] - Trains all the disciplines usable by the target, up to level specified. (may freeze client for a few seconds)", 150, command_traindisc) ||
|
||||||
|
command_add("trapinfo", "- Gets infomation about the traps currently spawned in the zone.", 81, command_trapinfo) ||
|
||||||
command_add("tune", "Calculate ideal statical values related to combat.", 100, command_tune) ||
|
command_add("tune", "Calculate ideal statical values related to combat.", 100, command_tune) ||
|
||||||
command_add("undyeme", "- Remove dye from all of your armor slots", 0, command_undyeme) ||
|
command_add("undyeme", "- Remove dye from all of your armor slots", 0, command_undyeme) ||
|
||||||
command_add("unfreeze", "- Unfreeze your target", 80, command_unfreeze) ||
|
command_add("unfreeze", "- Unfreeze your target", 80, command_unfreeze) ||
|
||||||
@ -10851,6 +10853,16 @@ void command_reloadperlexportsettings(Client *c, const Seperator *sep)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void command_trapinfo(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
entity_list.GetTrapInfo(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void command_reloadtraps(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
entity_list.UpdateAllTraps(true, true);
|
||||||
|
c->Message(CC_Default, "Traps reloaded for %s.", zone->GetShortName());
|
||||||
|
}
|
||||||
|
|
||||||
// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block.
|
// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block.
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
|
|||||||
@ -228,6 +228,7 @@ void command_reloadperlexportsettings(Client *c, const Seperator *sep);
|
|||||||
void command_reloadqst(Client *c, const Seperator *sep);
|
void command_reloadqst(Client *c, const Seperator *sep);
|
||||||
void command_reloadstatic(Client *c, const Seperator *sep);
|
void command_reloadstatic(Client *c, const Seperator *sep);
|
||||||
void command_reloadtitles(Client *c, const Seperator *sep);
|
void command_reloadtitles(Client *c, const Seperator *sep);
|
||||||
|
void command_reloadtraps(Client* c, const Seperator *sep);
|
||||||
void command_reloadworld(Client *c, const Seperator *sep);
|
void command_reloadworld(Client *c, const Seperator *sep);
|
||||||
void command_reloadworldrules(Client *c, const Seperator *sep);
|
void command_reloadworldrules(Client *c, const Seperator *sep);
|
||||||
void command_reloadzps(Client *c, const Seperator *sep);
|
void command_reloadzps(Client *c, const Seperator *sep);
|
||||||
@ -295,6 +296,7 @@ void command_timezone(Client *c, const Seperator *sep);
|
|||||||
void command_title(Client *c, const Seperator *sep);
|
void command_title(Client *c, const Seperator *sep);
|
||||||
void command_titlesuffix(Client *c, const Seperator *sep);
|
void command_titlesuffix(Client *c, const Seperator *sep);
|
||||||
void command_traindisc(Client *c, const Seperator *sep);
|
void command_traindisc(Client *c, const Seperator *sep);
|
||||||
|
void command_trapinfo(Client* c, const Seperator *sep);
|
||||||
void command_tune(Client *c, const Seperator *sep);
|
void command_tune(Client *c, const Seperator *sep);
|
||||||
void command_undye(Client *c, const Seperator *sep);
|
void command_undye(Client *c, const Seperator *sep);
|
||||||
void command_undyeme(Client *c, const Seperator *sep);
|
void command_undyeme(Client *c, const Seperator *sep);
|
||||||
|
|||||||
@ -473,6 +473,10 @@ public:
|
|||||||
void RefreshClientXTargets(Client *c);
|
void RefreshClientXTargets(Client *c);
|
||||||
void SendAlternateAdvancementStats();
|
void SendAlternateAdvancementStats();
|
||||||
|
|
||||||
|
void GetTrapInfo(Client* client);
|
||||||
|
bool IsTrapGroupSpawned(uint32 trap_id, uint8 group);
|
||||||
|
void UpdateAllTraps(bool respawn, bool repopnow = false);
|
||||||
|
void ClearTrapPointers();
|
||||||
protected:
|
protected:
|
||||||
friend class Zone;
|
friend class Zone;
|
||||||
void Depop(bool StartSpawnTimer = false);
|
void Depop(bool StartSpawnTimer = false);
|
||||||
|
|||||||
271
zone/trap.cpp
271
zone/trap.cpp
@ -52,10 +52,12 @@ CREATE TABLE traps (
|
|||||||
Trap::Trap() :
|
Trap::Trap() :
|
||||||
Entity(),
|
Entity(),
|
||||||
respawn_timer(600000),
|
respawn_timer(600000),
|
||||||
chkarea_timer(500),
|
chkarea_timer(1000),
|
||||||
|
reset_timer(5000),
|
||||||
m_Position(glm::vec3())
|
m_Position(glm::vec3())
|
||||||
{
|
{
|
||||||
trap_id = 0;
|
trap_id = 0;
|
||||||
|
db_id = 0;
|
||||||
maxzdiff = 0;
|
maxzdiff = 0;
|
||||||
radius = 0;
|
radius = 0;
|
||||||
effect = 0;
|
effect = 0;
|
||||||
@ -64,12 +66,19 @@ Trap::Trap() :
|
|||||||
skill = 0;
|
skill = 0;
|
||||||
level = 0;
|
level = 0;
|
||||||
respawn_timer.Disable();
|
respawn_timer.Disable();
|
||||||
|
reset_timer.Disable();
|
||||||
detected = false;
|
detected = false;
|
||||||
disarmed = false;
|
disarmed = false;
|
||||||
respawn_time = 0;
|
respawn_time = 0;
|
||||||
respawn_var = 0;
|
respawn_var = 0;
|
||||||
hiddenTrigger = nullptr;
|
hiddenTrigger = nullptr;
|
||||||
ownHiddenTrigger = false;
|
ownHiddenTrigger = false;
|
||||||
|
chance = 0;
|
||||||
|
triggered_number = 0;
|
||||||
|
times_triggered = 0;
|
||||||
|
group = 0;
|
||||||
|
despawn_when_triggered = false;
|
||||||
|
charid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trap::~Trap()
|
Trap::~Trap()
|
||||||
@ -80,8 +89,7 @@ Trap::~Trap()
|
|||||||
|
|
||||||
bool Trap::Process()
|
bool Trap::Process()
|
||||||
{
|
{
|
||||||
if (chkarea_timer.Enabled() && chkarea_timer.Check()
|
if (chkarea_timer.Enabled() && chkarea_timer.Check() && !reset_timer.Enabled())
|
||||||
/*&& zone->GetClientCount() > 0*/ )
|
|
||||||
{
|
{
|
||||||
Mob* trigger = entity_list.GetTrapTrigger(this);
|
Mob* trigger = entity_list.GetTrapTrigger(this);
|
||||||
if (trigger && !(trigger->IsClient() && trigger->CastToClient()->GetGM()))
|
if (trigger && !(trigger->IsClient() && trigger->CastToClient()->GetGM()))
|
||||||
@ -89,6 +97,13 @@ bool Trap::Process()
|
|||||||
Trigger(trigger);
|
Trigger(trigger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (reset_timer.Enabled() && reset_timer.Check())
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Reset timer disabled in Reset Check Process for trap %d.", trap_id);
|
||||||
|
reset_timer.Disable();
|
||||||
|
charid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (respawn_timer.Enabled() && respawn_timer.Check())
|
if (respawn_timer.Enabled() && respawn_timer.Check())
|
||||||
{
|
{
|
||||||
detected = false;
|
detected = false;
|
||||||
@ -96,11 +111,15 @@ bool Trap::Process()
|
|||||||
chkarea_timer.Enable();
|
chkarea_timer.Enable();
|
||||||
respawn_timer.Disable();
|
respawn_timer.Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trap::Trigger(Mob* trigger)
|
void Trap::Trigger(Mob* trigger)
|
||||||
{
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap %d triggered by %s for the %d time!", trap_id, trigger->GetName(), times_triggered + 1);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
const NPCType* tmp = 0;
|
const NPCType* tmp = 0;
|
||||||
switch (effect)
|
switch (effect)
|
||||||
@ -128,7 +147,7 @@ void Trap::Trigger(Mob* trigger)
|
|||||||
entity_list.MessageClose(trigger,false,effectvalue,13,"%s",message.c_str());
|
entity_list.MessageClose(trigger,false,effectvalue,13,"%s",message.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_list.SendAlarm(this,trigger,effectvalue);
|
entity_list.SendAlarm(this,trigger, effectvalue2);
|
||||||
break;
|
break;
|
||||||
case trapTypeMysticSpawn:
|
case trapTypeMysticSpawn:
|
||||||
if (message.empty())
|
if (message.empty())
|
||||||
@ -201,12 +220,41 @@ void Trap::Trigger(Mob* trigger)
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
respawn_timer.Start((respawn_time + zone->random.Int(0, respawn_var)) * 1000);
|
|
||||||
chkarea_timer.Disable();
|
if (trigger && trigger->IsClient())
|
||||||
disarmed = true;
|
{
|
||||||
|
trigger->CastToClient()->trapid = trap_id;
|
||||||
|
charid = trigger->CastToClient()->CharacterID();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update = false;
|
||||||
|
if (despawn_when_triggered)
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap %d is despawning after being triggered.", trap_id);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reset_timer.Start(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triggered_number > 0)
|
||||||
|
++times_triggered;
|
||||||
|
|
||||||
|
if (triggered_number > 0 && triggered_number <= times_triggered)
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "Triggered number for trap %d reached. %d/%d", trap_id, times_triggered, triggered_number);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update)
|
||||||
|
{
|
||||||
|
UpdateTrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Trap* EntityList::FindNearbyTrap(Mob* searcher, float max_dist) {
|
Trap* EntityList::FindNearbyTrap(Mob* searcher, float max_dist)
|
||||||
|
{
|
||||||
float dist = 999999;
|
float dist = 999999;
|
||||||
Trap* current_trap = nullptr;
|
Trap* current_trap = nullptr;
|
||||||
|
|
||||||
@ -231,45 +279,135 @@ Trap* EntityList::FindNearbyTrap(Mob* searcher, float max_dist) {
|
|||||||
return current_trap;
|
return current_trap;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mob* EntityList::GetTrapTrigger(Trap* trap) {
|
Mob* EntityList::GetTrapTrigger(Trap* trap)
|
||||||
Mob* savemob = 0;
|
{
|
||||||
|
|
||||||
float maxdist = trap->radius * trap->radius;
|
float maxdist = trap->radius * trap->radius;
|
||||||
|
for (auto it = client_list.begin(); it != client_list.end(); ++it)
|
||||||
for (auto it = client_list.begin(); it != client_list.end(); ++it) {
|
{
|
||||||
Client* cur = it->second;
|
Client* cur = it->second;
|
||||||
|
|
||||||
auto diff = glm::vec3(cur->GetPosition()) - trap->m_Position;
|
auto diff = glm::vec3(cur->GetPosition()) - trap->m_Position;
|
||||||
diff.z = std::abs(diff.z);
|
diff.z = std::abs(diff.z);
|
||||||
|
|
||||||
if ((diff.x*diff.x + diff.y*diff.y) <= maxdist
|
if ((diff.x*diff.x + diff.y*diff.y) <= maxdist
|
||||||
&& diff.z < trap->maxzdiff)
|
&& diff.z <= trap->maxzdiff)
|
||||||
{
|
{
|
||||||
if (zone->random.Roll(trap->chance))
|
//This prevents the trap from triggering on players while zoning.
|
||||||
return(cur);
|
if (strcmp(cur->GetName(), "No name") == 0)
|
||||||
else
|
continue;
|
||||||
savemob = cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (cur->trapid == 0 && !cur->GetGM() && (trap->chance == 0 || zone->random.Roll(trap->chance)))
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "%s is about to trigger trap %d of chance %d. diff: %0.2f maxdist: %0.2f zdiff: %0.2f maxzdiff: %0.2f", cur->GetName(), trap->trap_id, trap->chance, (diff.x*diff.x + diff.y*diff.y), maxdist, diff.z, trap->maxzdiff);
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (cur->trapid == trap->trap_id)
|
||||||
|
{
|
||||||
|
Log(Logs::General, Logs::Traps, "%s is clearing trapid for trap %d", cur->GetName(), trap->trap_id);
|
||||||
|
cur->trapid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return savemob;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: rewrite this to not need direct access to trap members.
|
bool EntityList::IsTrapGroupSpawned(uint32 trap_id, uint8 group)
|
||||||
|
{
|
||||||
|
auto it = trap_list.begin();
|
||||||
|
while (it != trap_list.end())
|
||||||
|
{
|
||||||
|
Trap* cur = it->second;
|
||||||
|
if (cur->IsTrap() && cur->group == group && cur->trap_id != trap_id)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityList::UpdateAllTraps(bool respawn, bool repopnow)
|
||||||
|
{
|
||||||
|
auto it = trap_list.begin();
|
||||||
|
while (it != trap_list.end())
|
||||||
|
{
|
||||||
|
Trap* cur = it->second;
|
||||||
|
if (cur->IsTrap())
|
||||||
|
{
|
||||||
|
cur->UpdateTrap(respawn, repopnow);
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(Logs::General, Logs::Traps, "All traps updated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityList::GetTrapInfo(Client* client)
|
||||||
|
{
|
||||||
|
uint8 count = 0;
|
||||||
|
auto it = trap_list.begin();
|
||||||
|
while (it != trap_list.end())
|
||||||
|
{
|
||||||
|
Trap* cur = it->second;
|
||||||
|
if (cur->IsTrap())
|
||||||
|
{
|
||||||
|
bool isset = (cur->chkarea_timer.Enabled() && !cur->reset_timer.Enabled());
|
||||||
|
client->Message(CC_Default, " Trap: (%d) found at %0.2f,%0.2f,%0.2f. Times Triggered: %d Is Active: %d Group: %d Message: %s", cur->trap_id, cur->m_Position.x, cur->m_Position.y, cur->m_Position.z, cur->times_triggered, isset, cur->group, cur->message.c_str());
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
client->Message(CC_Default, "%d traps found.", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityList::ClearTrapPointers()
|
||||||
|
{
|
||||||
|
auto it = trap_list.begin();
|
||||||
|
while (it != trap_list.end())
|
||||||
|
{
|
||||||
|
Trap* cur = it->second;
|
||||||
|
if (cur->IsTrap())
|
||||||
|
{
|
||||||
|
cur->DestroyHiddenTrigger();
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
|
bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
|
||||||
|
|
||||||
std::string query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
std::string query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||||
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level "
|
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
|
||||||
"FROM traps WHERE zone='%s' AND version=%u", zonename, version);
|
"`group`, triggered_number, despawn_when_triggered FROM traps WHERE zone='%s' AND version=%u", zonename, version);
|
||||||
|
|
||||||
auto results = QueryDatabase(query);
|
auto results = QueryDatabase(query);
|
||||||
if (!results.Success()) {
|
if (!results.Success()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
uint32 tid = atoi(row[0]);
|
||||||
|
uint8 grp = atoi(row[15]);
|
||||||
|
|
||||||
|
if (grp > 0)
|
||||||
|
{
|
||||||
|
// If a member of our group is already spawned skip loading this trap.
|
||||||
|
if (entity_list.IsTrapGroupSpawned(tid, grp))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
auto trap = new Trap();
|
auto trap = new Trap();
|
||||||
trap->trap_id = atoi(row[0]);
|
trap->trap_id = tid;
|
||||||
|
trap->db_id = tid;
|
||||||
trap->m_Position = glm::vec3(atof(row[1]), atof(row[2]), atof(row[3]));
|
trap->m_Position = glm::vec3(atof(row[1]), atof(row[2]), atof(row[3]));
|
||||||
trap->effect = atoi(row[4]);
|
trap->effect = atoi(row[4]);
|
||||||
trap->effectvalue = atoi(row[5]);
|
trap->effectvalue = atoi(row[5]);
|
||||||
@ -282,8 +420,12 @@ bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
|
|||||||
trap->respawn_time = atoi(row[12]);
|
trap->respawn_time = atoi(row[12]);
|
||||||
trap->respawn_var = atoi(row[13]);
|
trap->respawn_var = atoi(row[13]);
|
||||||
trap->level = atoi(row[14]);
|
trap->level = atoi(row[14]);
|
||||||
|
trap->group = grp;
|
||||||
|
trap->triggered_number = atoi(row[16]);
|
||||||
|
trap->despawn_when_triggered = atoi(row[17]);
|
||||||
entity_list.AddTrap(trap);
|
entity_list.AddTrap(trap);
|
||||||
trap->CreateHiddenTrigger();
|
trap->CreateHiddenTrigger();
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap %d successfully loaded.", trap->trap_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -318,3 +460,86 @@ void Trap::CreateHiddenTrigger()
|
|||||||
hiddenTrigger = npca;
|
hiddenTrigger = npca;
|
||||||
ownHiddenTrigger = true;
|
ownHiddenTrigger = true;
|
||||||
}
|
}
|
||||||
|
bool ZoneDatabase::SetTrapData(Trap* trap, bool repopnow) {
|
||||||
|
|
||||||
|
uint32 dbid = trap->db_id;
|
||||||
|
std::string query;
|
||||||
|
|
||||||
|
if (trap->group > 0)
|
||||||
|
{
|
||||||
|
query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||||
|
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
|
||||||
|
"triggered_number, despawn_when_triggered FROM traps WHERE zone='%s' AND `group`=%d AND id != %d ORDER BY RAND() LIMIT 1", zone->GetShortName(), trap->group, dbid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We could just use the existing data here, but querying the DB is not expensive, and allows content developers to change traps without rebooting.
|
||||||
|
query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||||
|
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
|
||||||
|
"triggered_number, despawn_when_triggered FROM traps WHERE zone='%s' AND id = %d", zone->GetShortName(), dbid);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
|
||||||
|
trap->db_id = atoi(row[0]);
|
||||||
|
trap->m_Position = glm::vec3(atof(row[1]), atof(row[2]), atof(row[3]));
|
||||||
|
trap->effect = atoi(row[4]);
|
||||||
|
trap->effectvalue = atoi(row[5]);
|
||||||
|
trap->effectvalue2 = atoi(row[6]);
|
||||||
|
trap->skill = atoi(row[7]);
|
||||||
|
trap->maxzdiff = atof(row[8]);
|
||||||
|
trap->radius = atof(row[9]);
|
||||||
|
trap->chance = atoi(row[10]);
|
||||||
|
trap->message = row[11];
|
||||||
|
trap->respawn_time = atoi(row[12]);
|
||||||
|
trap->respawn_var = atoi(row[13]);
|
||||||
|
trap->level = atoi(row[14]);
|
||||||
|
trap->triggered_number = atoi(row[15]);
|
||||||
|
trap->despawn_when_triggered = atoi(row[16]);
|
||||||
|
trap->CreateHiddenTrigger();
|
||||||
|
|
||||||
|
if (repopnow)
|
||||||
|
{
|
||||||
|
trap->chkarea_timer.Enable();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trap->respawn_timer.Start((trap->respawn_time + zone->random.Int(0, trap->respawn_var)) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trap->trap_id != trap->db_id)
|
||||||
|
Log(Logs::General, Logs::Traps, "Trap (%d) DBID has changed from %d to %d", trap->trap_id, dbid, trap->db_id);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trap::UpdateTrap(bool respawn, bool repopnow)
|
||||||
|
{
|
||||||
|
respawn_timer.Disable();
|
||||||
|
chkarea_timer.Disable();
|
||||||
|
reset_timer.Disable();
|
||||||
|
if (hiddenTrigger)
|
||||||
|
{
|
||||||
|
hiddenTrigger->Depop();
|
||||||
|
hiddenTrigger = nullptr;
|
||||||
|
}
|
||||||
|
times_triggered = 0;
|
||||||
|
Client* trigger = entity_list.GetClientByCharID(charid);
|
||||||
|
if (trigger)
|
||||||
|
{
|
||||||
|
trigger->trapid = 0;
|
||||||
|
}
|
||||||
|
charid = 0;
|
||||||
|
if (respawn)
|
||||||
|
{
|
||||||
|
database.SetTrapData(this, repopnow);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
zone/trap.h
13
zone/trap.h
@ -49,11 +49,15 @@ public:
|
|||||||
NPC * GetHiddenTrigger() { return hiddenTrigger; }
|
NPC * GetHiddenTrigger() { return hiddenTrigger; }
|
||||||
void SetHiddenTrigger(NPC* n) { hiddenTrigger = n; }
|
void SetHiddenTrigger(NPC* n) { hiddenTrigger = n; }
|
||||||
void CreateHiddenTrigger();
|
void CreateHiddenTrigger();
|
||||||
|
void DestroyHiddenTrigger() { hiddenTrigger = nullptr; }
|
||||||
|
void SetTrapData();
|
||||||
|
void UpdateTrap(bool respawn = true, bool repopnow = false);
|
||||||
//Trap data, leave this unprotected
|
//Trap data, leave this unprotected
|
||||||
Timer respawn_timer; //Respawn Time when Trap's been disarmed
|
Timer respawn_timer; //Respawn Time when Trap's been disarmed
|
||||||
Timer chkarea_timer;
|
Timer chkarea_timer;
|
||||||
uint32 trap_id; //Database ID of trap
|
Timer reset_timer; //How long a trap takes to reset before triggering again.
|
||||||
|
uint32 trap_id; //Original ID of the trap from DB. This value never changes.
|
||||||
|
uint32 db_id; //The DB ID of the trap that currently is spawned.
|
||||||
glm::vec3 m_Position;
|
glm::vec3 m_Position;
|
||||||
float maxzdiff; //maximum z diff to be triggerable
|
float maxzdiff; //maximum z diff to be triggerable
|
||||||
float radius; //radius around trap to be triggerable
|
float radius; //radius around trap to be triggerable
|
||||||
@ -67,6 +71,11 @@ public:
|
|||||||
bool disarmed;
|
bool disarmed;
|
||||||
uint32 respawn_time;
|
uint32 respawn_time;
|
||||||
uint32 respawn_var;
|
uint32 respawn_var;
|
||||||
|
uint8 triggered_number;
|
||||||
|
uint8 times_triggered;
|
||||||
|
uint8 group;
|
||||||
|
bool despawn_when_triggered;
|
||||||
|
uint32 charid; //ID of character that triggered trap. This is cleared when the trap despawns are resets.
|
||||||
|
|
||||||
std::string message;
|
std::string message;
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@ -1428,7 +1428,8 @@ void Zone::StartShutdownTimer(uint32 set_time) {
|
|||||||
bool Zone::Depop(bool StartSpawnTimer) {
|
bool Zone::Depop(bool StartSpawnTimer) {
|
||||||
std::map<uint32,NPCType *>::iterator itr;
|
std::map<uint32,NPCType *>::iterator itr;
|
||||||
entity_list.Depop(StartSpawnTimer);
|
entity_list.Depop(StartSpawnTimer);
|
||||||
|
entity_list.ClearTrapPointers();
|
||||||
|
entity_list.UpdateAllTraps(false);
|
||||||
/* Refresh npctable (cache), getting current info from database. */
|
/* Refresh npctable (cache), getting current info from database. */
|
||||||
while(!npctable.empty()) {
|
while(!npctable.empty()) {
|
||||||
itr = npctable.begin();
|
itr = npctable.begin();
|
||||||
@ -1496,6 +1497,8 @@ void Zone::Repop(uint32 delay) {
|
|||||||
iterator.RemoveCurrent();
|
iterator.RemoveCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entity_list.ClearTrapPointers();
|
||||||
|
|
||||||
quest_manager.ClearAllTimers();
|
quest_manager.ClearAllTimers();
|
||||||
|
|
||||||
if (!database.PopulateZoneSpawnList(zoneid, spawn2_list, GetInstanceVersion(), delay))
|
if (!database.PopulateZoneSpawnList(zoneid, spawn2_list, GetInstanceVersion(), delay))
|
||||||
@ -1503,6 +1506,8 @@ void Zone::Repop(uint32 delay) {
|
|||||||
|
|
||||||
initgrids_timer.Start();
|
initgrids_timer.Start();
|
||||||
|
|
||||||
|
entity_list.UpdateAllTraps(true, true);
|
||||||
|
|
||||||
//MODDING HOOK FOR REPOP
|
//MODDING HOOK FOR REPOP
|
||||||
mod_repop();
|
mod_repop();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ class NPC;
|
|||||||
class Petition;
|
class Petition;
|
||||||
class Spawn2;
|
class Spawn2;
|
||||||
class SpawnGroupList;
|
class SpawnGroupList;
|
||||||
|
class Trap;
|
||||||
struct CharacterEventLog_Struct;
|
struct CharacterEventLog_Struct;
|
||||||
struct Door;
|
struct Door;
|
||||||
struct ExtendedProfile_Struct;
|
struct ExtendedProfile_Struct;
|
||||||
@ -478,7 +479,7 @@ public:
|
|||||||
|
|
||||||
/* Traps */
|
/* Traps */
|
||||||
bool LoadTraps(const char* zonename, int16 version);
|
bool LoadTraps(const char* zonename, int16 version);
|
||||||
char* GetTrapMessage(uint32 trap_id);
|
bool SetTrapData(Trap* trap, bool repopnow = false);
|
||||||
|
|
||||||
/* Time */
|
/* Time */
|
||||||
uint32 GetZoneTZ(uint32 zoneid, uint32 version);
|
uint32 GetZoneTZ(uint32 zoneid, uint32 version);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user