mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-25 18:21:28 +00:00
Merge branch 'master' of github.com:EQEmu/Server into wp
This commit is contained in:
commit
6a79694fa1
@ -617,7 +617,7 @@ struct NewZone_Struct {
|
||||
/*0704*/ char zone_short_name2[32]; //zone file name? excludes instance number which can be in previous version.
|
||||
/*0736*/ char WeatherString[32];
|
||||
/*0768*/ char SkyString2[32];
|
||||
/*0800*/ int32 SkyRelated2; //seen -1
|
||||
/*0800*/ int32 SkyRelated2; //seen -1 -- maybe some default sky time?
|
||||
/*0804*/ char WeatherString2[32]; //
|
||||
/*0836*/ float WeatherChangeTime; // not sure :P
|
||||
/*0840*/ uint32 Climate;
|
||||
|
||||
@ -563,6 +563,8 @@ RULE_INT(Range, DamageMessages, 50)
|
||||
RULE_INT(Range, SpellMessages, 75)
|
||||
RULE_INT(Range, SongMessages, 75)
|
||||
RULE_INT(Range, MobPositionUpdates, 600)
|
||||
RULE_INT(Range, ClientPositionUpdates, 300)
|
||||
RULE_INT(Range, ClientForceSpawnUpdateRange, 1000)
|
||||
RULE_INT(Range, CriticalDamage, 80)
|
||||
RULE_INT(Range, ClientNPCScan, 300)
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
@ -357,7 +357,7 @@
|
||||
9101|2016_12_01_pcnpc_only.sql|SHOW COLUMNS FROM `spells_new` LIKE 'pcnpc_only_flag'|empty|
|
||||
9102|2017_01_10_book_languages.sql|SHOW COLUMNS FROM `books` LIKE 'language'|empty|
|
||||
9103|2017_01_30_book_languages_fix.sql|SELECT `language` from `books` WHERE `language` IS NULL|not_empty|
|
||||
9104|2017_02_09_npc_spells_entries_type_update.sql|SHOW COLUMNS IN `npc_spells_entries` LIKE `type`|contains|smallint(5) unsigned
|
||||
9104|2017_02_09_npc_spells_entries_type_update.sql|SHOW COLUMNS IN `npc_spells_entries` LIKE 'type'|contains|smallint(5) unsigned
|
||||
9105|2017_02_15_bot_spells_entries.sql|SELECT `id` FROM `npc_spells_entries` WHERE `npc_spells_id` >= 701 AND `npc_spells_id` <= 712|not_empty|
|
||||
9106|2017_02_26_npc_spells_update_for_bots.sql|SELECT * FROM `npc_spells` WHERE `id` = '701' AND `name` = 'Cleric Bot'|not_empty|
|
||||
9107|2017_03_09_inventory_version.sql|SHOW TABLES LIKE 'inventory_version'|empty|
|
||||
|
||||
@ -1003,6 +1003,15 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
case SE_RiposteChance:
|
||||
newbon->RiposteChance += base1;
|
||||
break;
|
||||
case SE_DodgeChance:
|
||||
newbon->DodgeChance += base1;
|
||||
break;
|
||||
case SE_ParryChance:
|
||||
newbon->ParryChance += base1;
|
||||
break;
|
||||
case SE_IncreaseBlockChance:
|
||||
newbon->IncreaseBlockChance += base1;
|
||||
break;
|
||||
case SE_Flurry:
|
||||
newbon->FlurryChance += base1;
|
||||
break;
|
||||
@ -2495,7 +2504,12 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
break;
|
||||
|
||||
case SE_IncreaseBlockChance:
|
||||
new_bonus->IncreaseBlockChance += effect_value;
|
||||
if (AdditiveWornBonus)
|
||||
new_bonus->IncreaseBlockChance += effect_value;
|
||||
else if (effect_value < 0 && new_bonus->IncreaseBlockChance > effect_value)
|
||||
new_bonus->IncreaseBlockChance = effect_value;
|
||||
else if (new_bonus->IncreaseBlockChance < effect_value)
|
||||
new_bonus->IncreaseBlockChance = effect_value;
|
||||
break;
|
||||
|
||||
case SE_PersistantCasting:
|
||||
|
||||
@ -1489,7 +1489,9 @@ private:
|
||||
Timer hp_self_update_throttle_timer; /* This is to prevent excessive packet sending under trains/fast combat */
|
||||
Timer hp_other_update_throttle_timer; /* This is to keep clients from DOSing the server with macros that change client targets constantly */
|
||||
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
|
||||
glm::vec3 m_Proximity;
|
||||
|
||||
glm::vec3 m_Proximity;
|
||||
glm::vec4 last_major_update_position;
|
||||
|
||||
void BulkSendInventoryItems();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -243,15 +243,21 @@ bool Client::Process() {
|
||||
|
||||
/* Build a close range list of NPC's */
|
||||
if (npc_close_scan_timer.Check()) {
|
||||
|
||||
close_mobs.clear();
|
||||
|
||||
auto &mob_list = entity_list.GetMobList();
|
||||
float scan_range = (RuleI(Range, ClientNPCScan) * RuleI(Range, ClientNPCScan));
|
||||
float client_update_range = (RuleI(Range, MobPositionUpdates) * RuleI(Range, MobPositionUpdates));
|
||||
/* Force spawn updates when traveled far */
|
||||
bool force_spawn_updates = false;
|
||||
float client_update_range = (RuleI(Range, ClientForceSpawnUpdateRange) * RuleI(Range, ClientForceSpawnUpdateRange));
|
||||
if (DistanceSquared(last_major_update_position, m_Position) >= client_update_range) {
|
||||
last_major_update_position = m_Position;
|
||||
force_spawn_updates = true;
|
||||
}
|
||||
|
||||
float scan_range = (RuleI(Range, ClientNPCScan) * RuleI(Range, ClientNPCScan));
|
||||
auto &mob_list = entity_list.GetMobList();
|
||||
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
|
||||
Mob* mob = itr->second;
|
||||
|
||||
float distance = DistanceSquared(m_Position, mob->GetPosition());
|
||||
if (mob->IsNPC()) {
|
||||
if (distance <= scan_range) {
|
||||
@ -261,6 +267,10 @@ bool Client::Process() {
|
||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||
}
|
||||
}
|
||||
|
||||
if (force_spawn_updates && mob != this && distance <= client_update_range)
|
||||
mob->SendPositionUpdateToClient(this);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3894,6 +3894,8 @@ void command_depopzone(Client *c, const Seperator *sep)
|
||||
void command_repop(Client *c, const Seperator *sep)
|
||||
{
|
||||
int timearg = 1;
|
||||
int delay = 0;
|
||||
|
||||
if (sep->arg[1] && strcasecmp(sep->arg[1], "force") == 0) {
|
||||
timearg++;
|
||||
|
||||
@ -3912,13 +3914,19 @@ void command_repop(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
if (!sep->IsNumber(timearg)) {
|
||||
c->Message(0, "Zone depoped. Repoping now.");
|
||||
c->Message(0, "Zone depopped - repopping now.");
|
||||
|
||||
zone->Repop();
|
||||
|
||||
/* Force a spawn2 timer trigger so we don't delay actually spawning the NPC's */
|
||||
zone->spawn2_timer.Trigger();
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(0, "Zone depoped. Repop in %i seconds", atoi(sep->arg[timearg]));
|
||||
zone->Repop(atoi(sep->arg[timearg])*1000);
|
||||
zone->Repop(atoi(sep->arg[timearg]) * 1000);
|
||||
|
||||
zone->spawn2_timer.Trigger();
|
||||
}
|
||||
|
||||
void command_repopclose(Client *c, const Seperator *sep)
|
||||
|
||||
@ -613,7 +613,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
|
||||
|
||||
//Check the disc timer
|
||||
pTimerType DiscTimer = pTimerDisciplineReuseStart + spell.EndurTimerIndex;
|
||||
if(!p_timers.Expired(&database, DiscTimer)) {
|
||||
if(!p_timers.Expired(&database, DiscTimer, false)) { // lets not set the reuse timer in case CastSpell fails (or we would have to turn off the timer, but CastSpell will set it as well)
|
||||
/*char val1[20]={0};*/ //unused
|
||||
/*char val2[20]={0};*/ //unused
|
||||
uint32 remain = p_timers.GetRemainingTime(DiscTimer);
|
||||
|
||||
@ -119,7 +119,7 @@ void Embperl::DoInit() {
|
||||
perl_run(my_perl);
|
||||
|
||||
//a little routine we use a lot.
|
||||
eval_pv("sub my_eval {eval $_[0];}", TRUE); //dies on error
|
||||
eval_pv("sub my_eval { eval $_[0];}", TRUE); //dies on error
|
||||
|
||||
//ruin the perl exit and command:
|
||||
eval_pv("sub my_exit {}",TRUE);
|
||||
@ -149,7 +149,7 @@ void Embperl::DoInit() {
|
||||
//make a tieable class to capture IO and pass it into EQEMuLog
|
||||
eval_pv(
|
||||
"package EQEmuIO; "
|
||||
"sub TIEHANDLE { my $me = bless {}, $_[0]; $me->PRINT('Creating '.$me); return($me); } "
|
||||
"sub TIEHANDLE { my $me = bless {}, $_[0]; $me->PRINT('Creating '. $me); return($me); } "
|
||||
"sub WRITE { } "
|
||||
//dunno why I need to shift off fmt here, but it dosent like without it
|
||||
"sub PRINTF { my $me = shift; my $fmt = shift; $me->PRINT(sprintf($fmt, @_)); } "
|
||||
@ -237,6 +237,7 @@ void Embperl::init_eval_file(void)
|
||||
{
|
||||
eval_pv(
|
||||
"our %Cache;"
|
||||
"no warnings;"
|
||||
"use Symbol qw(delete_package);"
|
||||
"sub eval_file {"
|
||||
"my($package, $filename) = @_;"
|
||||
@ -246,8 +247,9 @@ void Embperl::init_eval_file(void)
|
||||
"if(defined $Cache{$package}{mtime}&&$Cache{$package}{mtime} <= $mtime && !($package eq 'plugin')){"
|
||||
" return;"
|
||||
"} else {"
|
||||
//we 'my' $filename,$mtime,$package,$sub to prevent them from changing our state up here.
|
||||
" eval(\"package $package; my(\\$filename,\\$mtime,\\$package,\\$sub); \\$isloaded = 1; require '$filename'; \");"
|
||||
// we 'my' $filename,$mtime,$package,$sub to prevent them from changing our state up here.
|
||||
" eval(\"package $package; my(\\$filename,\\$mtime,\\$package,\\$sub); \\$isloaded = 1; require './$filename'; \");"
|
||||
// " print $@ if $@;"
|
||||
/* "local *FH;open FH, $filename or die \"open '$filename' $!\";"
|
||||
"local($/) = undef;my $sub = <FH>;close FH;"
|
||||
"my $eval = qq{package $package; sub handler { $sub; }};"
|
||||
|
||||
@ -99,6 +99,10 @@ XS(XS_EQEmuIO_PRINT)
|
||||
/* Strip newlines from log message 'str' */
|
||||
*std::remove(str, str + strlen(str), '\n') = '\0';
|
||||
|
||||
std::string log_string = str;
|
||||
if (log_string.find("did not return a true") != std::string::npos)
|
||||
return;;
|
||||
|
||||
int i;
|
||||
int pos = 0;
|
||||
int len = 0;
|
||||
|
||||
@ -648,6 +648,8 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
|
||||
|
||||
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
|
||||
|
||||
npc->FixZ();
|
||||
|
||||
uint16 emoteid = npc->GetEmoteID();
|
||||
if (emoteid != 0)
|
||||
npc->DoNPCEmote(ONSPAWN, emoteid);
|
||||
|
||||
@ -2464,3 +2464,30 @@ bool Group::HasRole(Mob *m, uint8 Role)
|
||||
return false;
|
||||
}
|
||||
|
||||
void Group::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/) {
|
||||
if (sender && sender->IsClient()) {
|
||||
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
|
||||
if (!members[i])
|
||||
continue;
|
||||
|
||||
if (ignore_sender && members[i] == sender)
|
||||
continue;
|
||||
|
||||
/* If we don't have a distance requirement - send to all members */
|
||||
if (distance == 0) {
|
||||
members[i]->CastToClient()->QueuePacket(app, ack_required);
|
||||
}
|
||||
else {
|
||||
/* If negative distance - we check if current distance is greater than X */
|
||||
if (distance <= 0 && DistanceSquared(sender->GetPosition(), members[i]->GetPosition()) >= (distance * distance)) {
|
||||
members[i]->CastToClient()->QueuePacket(app, ack_required);
|
||||
}
|
||||
/* If positive distance - we check if current distance is less than X */
|
||||
else if (distance >= 0 && DistanceSquared(sender->GetPosition(), members[i]->GetPosition()) <= (distance * distance)) {
|
||||
members[i]->CastToClient()->QueuePacket(app, ack_required);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,6 +140,7 @@ public:
|
||||
inline int GetLeadershipAA(int AAID) { return LeaderAbilities.ranks[AAID]; }
|
||||
void ClearAllNPCMarks();
|
||||
void QueueHPPacketsForNPCHealthAA(Mob* sender, const EQApplicationPacket* app);
|
||||
void QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required = true, bool ignore_sender = true, float distance = 0);
|
||||
void ChangeLeader(Mob* newleader);
|
||||
const char *GetClientNameByIndex(uint8 index);
|
||||
void UpdateXTargetMarkedNPC(uint32 Number, Mob *m);
|
||||
|
||||
18
zone/mob.cpp
18
zone/mob.cpp
@ -1375,7 +1375,7 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
if(IsClient()){
|
||||
Raid *raid = entity_list.GetRaidByClient(CastToClient());
|
||||
if (raid)
|
||||
raid->SendHPPacketsFrom(this);
|
||||
raid->SendHPManaEndPacketsFrom(this);
|
||||
}
|
||||
|
||||
/* Pet - Update master - group and raid if exists */
|
||||
@ -1388,7 +1388,7 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
|
||||
Raid *raid = entity_list.GetRaidByClient(GetOwner()->CastToClient());
|
||||
if(raid)
|
||||
raid->SendHPPacketsFrom(this);
|
||||
raid->SendHPManaEndPacketsFrom(this);
|
||||
}
|
||||
|
||||
/* Send to pet */
|
||||
@ -1447,6 +1447,20 @@ void Mob::SendPosition() {
|
||||
safe_delete(app);
|
||||
}
|
||||
|
||||
void Mob::SendPositionUpdateToClient(Client *client) {
|
||||
auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct* spawn_update = (PlayerPositionUpdateServer_Struct*)app->pBuffer;
|
||||
|
||||
if(this->IsMoving())
|
||||
MakeSpawnUpdate(spawn_update);
|
||||
else
|
||||
MakeSpawnUpdateNoDelta(spawn_update);
|
||||
|
||||
client->QueuePacket(app, false);
|
||||
|
||||
safe_delete(app);
|
||||
}
|
||||
|
||||
/* Position updates for mobs on the move */
|
||||
void Mob::SendPositionUpdate(uint8 iSendToSelf) {
|
||||
auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
|
||||
@ -543,6 +543,7 @@ public:
|
||||
virtual void GMMove(float x, float y, float z, float heading = 0.01, bool SendUpdate = true);
|
||||
void SetDelta(const glm::vec4& delta);
|
||||
void SetTargetDestSteps(uint8 target_steps) { tar_ndx = target_steps; }
|
||||
void SendPositionUpdateToClient(Client *client);
|
||||
void SendPositionUpdate(uint8 iSendToSelf = 0);
|
||||
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
|
||||
void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);
|
||||
|
||||
@ -997,10 +997,9 @@ void Mob::AI_Process() {
|
||||
if (this->GetTarget()) {
|
||||
/* If we are engaged, moving and following client, let's look for best Z more often */
|
||||
float target_distance = DistanceNoZ(this->GetPosition(), this->GetTarget()->GetPosition());
|
||||
if (target_distance >= 25) {
|
||||
this->FixZ();
|
||||
}
|
||||
else if (!this->CheckLosFN(this->GetTarget())) {
|
||||
this->FixZ();
|
||||
|
||||
if (target_distance <= 15 && !this->CheckLosFN(this->GetTarget())) {
|
||||
Mob* target = this->GetTarget();
|
||||
|
||||
m_Position.x = target->GetX();
|
||||
|
||||
@ -149,7 +149,7 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
raid_update = c->GetRaid();
|
||||
if (raid_update) {
|
||||
raid_update->SendHPManaEndPacketsTo(c);
|
||||
raid_update->SendHPPacketsFrom(c);
|
||||
raid_update->SendHPManaEndPacketsFrom(c);
|
||||
}
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct));
|
||||
@ -1591,7 +1591,7 @@ void Raid::SendHPManaEndPacketsTo(Client *client)
|
||||
}
|
||||
}
|
||||
|
||||
void Raid::SendHPPacketsFrom(Mob *mob)
|
||||
void Raid::SendHPManaEndPacketsFrom(Mob *mob)
|
||||
{
|
||||
if(!mob)
|
||||
return;
|
||||
@ -1779,3 +1779,42 @@ void Raid::SetDirtyAutoHaters()
|
||||
|
||||
}
|
||||
|
||||
void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/, bool group_only /*= true*/) {
|
||||
if (sender && sender->IsClient()) {
|
||||
|
||||
uint32 group_id = this->GetGroup(sender->CastToClient());
|
||||
|
||||
/* If this is a group only packet and we're not in a group -- return */
|
||||
if (!group_id == 0xFFFFFFFF && group_only)
|
||||
return;
|
||||
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) {
|
||||
if (!members[i].member)
|
||||
continue;
|
||||
|
||||
if (!members[i].member->IsClient())
|
||||
continue;
|
||||
|
||||
if (ignore_sender && members[i].member == sender)
|
||||
continue;
|
||||
|
||||
if (group_only && members[i].GroupNumber != group_id)
|
||||
continue;
|
||||
|
||||
/* If we don't have a distance requirement - send to all members */
|
||||
if (distance == 0) {
|
||||
members[i].member->CastToClient()->QueuePacket(app, ack_required);
|
||||
}
|
||||
else {
|
||||
/* If negative distance - we check if current distance is greater than X */
|
||||
if (distance <= 0 && DistanceSquared(sender->GetPosition(), members[i].member->GetPosition()) >= (distance * distance)) {
|
||||
members[i].member->CastToClient()->QueuePacket(app, ack_required);
|
||||
}
|
||||
/* If positive distance - we check if current distance is less than X */
|
||||
else if (distance >= 0 && DistanceSquared(sender->GetPosition(), members[i].member->GetPosition()) <= (distance * distance)) {
|
||||
members[i].member->CastToClient()->QueuePacket(app, ack_required);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,7 +174,7 @@ public:
|
||||
void VerifyRaid();
|
||||
void MemberZoned(Client *c);
|
||||
void SendHPManaEndPacketsTo(Client *c);
|
||||
void SendHPPacketsFrom(Mob *mob);
|
||||
void SendHPManaEndPacketsFrom(Mob *mob);
|
||||
void SendManaPacketFrom(Mob *mob);
|
||||
void SendEndurancePacketFrom(Mob *mob);
|
||||
void RaidSay(const char *msg, Client *c);
|
||||
@ -237,6 +237,8 @@ public:
|
||||
void SetDirtyAutoHaters();
|
||||
inline XTargetAutoHaters *GetXTargetAutoMgr() { return &m_autohatermgr; }
|
||||
|
||||
void QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required = true, bool ignore_sender = true, float distance = 0, bool group_only = true);
|
||||
|
||||
RaidMember members[MAX_RAID_MEMBERS];
|
||||
char leadername[64];
|
||||
protected:
|
||||
|
||||
@ -1427,8 +1427,10 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
||||
ZeroCastingVars();
|
||||
|
||||
// set the rapid recast timer for next time around
|
||||
// Why do we have this? It mostly just causes issues when things are working correctly
|
||||
// It also needs to be <users's ping to not cause issues
|
||||
delaytimer = true;
|
||||
spellend_timer.Start(400,true);
|
||||
spellend_timer.Start(10, true);
|
||||
|
||||
Log(Logs::Detail, Logs::Spells, "Spell casting of %d is finished.", spell_id);
|
||||
|
||||
|
||||
@ -1170,10 +1170,13 @@ bool Zone::Process() {
|
||||
spawn_conditions.Process();
|
||||
|
||||
if(spawn2_timer.Check()) {
|
||||
|
||||
LinkedListIterator<Spawn2*> iterator(spawn2_list);
|
||||
|
||||
EQEmu::InventoryProfile::CleanDirty();
|
||||
|
||||
Log(Logs::Detail, Logs::Spawns, "Running Zone::Process -> Spawn2::Process");
|
||||
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements()) {
|
||||
if (iterator.GetData()->Process()) {
|
||||
@ -1183,10 +1186,10 @@ bool Zone::Process() {
|
||||
iterator.RemoveCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
if(adv_data && !did_adventure_actions)
|
||||
{
|
||||
DoAdventureActions();
|
||||
}
|
||||
|
||||
}
|
||||
if(initgrids_timer.Check()) {
|
||||
//delayed grid loading stuff.
|
||||
|
||||
@ -106,6 +106,7 @@ public:
|
||||
inline const uint8 GetZoneType() const { return zone_type; }
|
||||
|
||||
inline Timer* GetInstanceTimer() { return Instance_Timer; }
|
||||
Timer spawn2_timer;
|
||||
|
||||
inline glm::vec3 GetSafePoint() { return m_SafePoint; }
|
||||
inline const uint32& graveyard_zoneid() { return pgraveyard_zoneid; }
|
||||
@ -336,7 +337,6 @@ private:
|
||||
|
||||
Timer autoshutdown_timer;
|
||||
Timer clientauth_timer;
|
||||
Timer spawn2_timer;
|
||||
Timer qglobal_purge_timer;
|
||||
Timer* Weather_Timer;
|
||||
Timer* Instance_Timer;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user