diff --git a/src/engine/core/handler.cpp b/src/engine/core/handler.cpp index 543547890..1534bc494 100644 --- a/src/engine/core/handler.cpp +++ b/src/engine/core/handler.cpp @@ -125,17 +125,15 @@ void CheckLight(CharData *ch, int was_equip, int was_single, int was_holylight, } void DecreaseFeatTimer(CharData *ch, EFeat feat_id) { - for (auto *skj = ch->timed_feat; skj; skj = skj->next) { - if (skj->feat == feat_id) { - if (skj->time >= 1) { - --(skj->time); - } else { - ExpireTimedFeat(ch, skj); - } - return; + auto it = ch->timed_feat.find(feat_id); + if (it != ch->timed_feat.end()) { + if (it->second >= 1) { + --(it->second); + } else { + ch->timed_feat.erase(it); } } -}; +} template int GetTalentTimerMod(CharData *ch, TalentId id) { @@ -151,40 +149,23 @@ int GetTalentTimerMod(CharData *ch, TalentId id) { } void ImposeTimedFeat(CharData *ch, TimedFeat *timed) { - timed->time = std::max(1, timed->time + GetTalentTimerMod(ch, timed->feat)); - - struct TimedFeat *timed_alloc, *skj; - for (skj = ch->timed_feat; skj; skj = skj->next) { - if (skj->feat == timed->feat) { - skj->time = timed->time; - return; - } - } - - CREATE(timed_alloc, 1); - - *timed_alloc = *timed; - timed_alloc->next = ch->timed_feat; - ch->timed_feat = timed_alloc; + ch->timed_feat[timed->feat] = std::max(1, timed->time + GetTalentTimerMod(ch, timed->feat)); } -void ExpireTimedFeat(CharData *ch, TimedFeat *timed) { - if (ch->timed_feat == nullptr) { +void ExpireTimedFeat(CharData *ch, EFeat feat) { + if (ch->timed_feat.empty()) { log("SYSERR: timed_feat_from_char(%s) when no timed...", GET_NAME(ch)); return; } - REMOVE_FROM_LIST(timed, ch->timed_feat); - free(timed); + ch->timed_feat.erase(feat); } int IsTimedByFeat(CharData *ch, EFeat feat) { - struct TimedFeat *hjp; - - for (hjp = ch->timed_feat; hjp; hjp = hjp->next) - if (hjp->feat == feat) - return (hjp->time); - + auto it = ch->timed_feat.find(feat); + if (it != ch->timed_feat.end()) { + return it->second; + } return (0); } @@ -192,41 +173,25 @@ int IsTimedByFeat(CharData *ch, EFeat feat) { * Insert an TimedSkill in a char_data structure */ void ImposeTimedSkill(CharData *ch, struct TimedSkill *timed) { - timed->time = std::max(1, timed->time + GetTalentTimerMod(ch, timed->skill)); - - struct TimedSkill *timed_alloc, *skj; - for (skj = ch->timed; skj; skj = skj->next) { - if (skj->skill == timed->skill) { - skj->time = timed->time; - return; - } - } - - CREATE(timed_alloc, 1); - - *timed_alloc = *timed; - timed_alloc->next = ch->timed; - ch->timed = timed_alloc; + ch->timed_skill[timed->skill] = std::max(1, timed->time + GetTalentTimerMod(ch, timed->skill)); } -void ExpireTimedSkill(CharData *ch, struct TimedSkill *timed) { - if (ch->timed == nullptr) { +void ExpireTimedSkill(CharData *ch, ESkill skill) { + if (ch->timed_skill.empty()) { log("SYSERR: ExpireTimedSkill(%s) when no timed...", GET_NAME(ch)); // core_dump(); return; } - REMOVE_FROM_LIST(timed, ch->timed); - free(timed); + ch->timed_skill.erase(skill); } int IsTimedBySkill(CharData *ch, ESkill id) { - struct TimedSkill *hjp; - - for (hjp = ch->timed; hjp; hjp = hjp->next) - if (hjp->skill == id) - return (hjp->time); - + + auto it = ch->timed_skill.find(id); + if (it != ch->timed_skill.end()) { + return it->second; + } return (0); } diff --git a/src/engine/core/handler.h b/src/engine/core/handler.h index 84b0feb73..c20a91108 100644 --- a/src/engine/core/handler.h +++ b/src/engine/core/handler.h @@ -42,10 +42,10 @@ void CheckLight(CharData *ch, int was_equip, int was_single, int was_holylight, // handling the affected-structures // void ImposeTimedFeat(CharData *ch, TimedFeat *timed); -void ExpireTimedFeat(CharData *ch, TimedFeat *timed); +void ExpireTimedFeat(CharData *ch, EFeat feat); int IsTimedByFeat(CharData *ch, EFeat feat); -void ImposeTimedSkill(CharData *ch, struct TimedSkill *timed); -void ExpireTimedSkill(CharData *ch, struct TimedSkill *timed); +void ImposeTimedSkill(CharData *ch, TimedSkill *timed); +void ExpireTimedSkill(CharData *ch, ESkill skill); int IsTimedBySkill(CharData *ch, ESkill id); void DecreaseFeatTimer(CharData *ch, EFeat feat_id); diff --git a/src/engine/core/iosystem.cpp b/src/engine/core/iosystem.cpp index 1251d39ce..3cdb6c747 100644 --- a/src/engine/core/iosystem.cpp +++ b/src/engine/core/iosystem.cpp @@ -1163,10 +1163,10 @@ std::string MakePrompt(DescriptorData *d) { } if (ch->IsFlagged(EPrf::kDispTimed)) { - for (auto timed = ch->timed; timed; timed = timed->next) { - if (timed->skill != ESkill::kWarcry && timed->skill != ESkill::kTurnUndead) { + for (auto timed : ch->timed_skill) { + if (timed.first != ESkill::kWarcry && timed.first != ESkill::kTurnUndead) { fmt::format_to(std::back_inserter(out), "{}:{} ", - MUD::Skill(timed->skill).GetAbbr(), +timed->time); + MUD::Skill(timed.first).GetAbbr(), +timed.second); } } if (ch->GetSkill(ESkill::kWarcry)) { diff --git a/src/engine/entities/char_data.cpp b/src/engine/entities/char_data.cpp index e79dfb4d5..3c6a84cff 100644 --- a/src/engine/entities/char_data.cpp +++ b/src/engine/entities/char_data.cpp @@ -338,8 +338,6 @@ void CharData::zero_init() { punctual_wait = 0; last_comm.clear(); player_specials = nullptr; - timed = nullptr; - timed_feat = nullptr; carrying = nullptr; desc = nullptr; followers = nullptr; @@ -430,10 +428,7 @@ void CharData::purge() { free(this->mob_specials.Questor); } this->affected.clear(); - while (this->timed) { - ExpireTimedSkill(this, this->timed); - } - + this->timed_skill.clear(); celebrates::RemoveFromMobLists(this->get_uid()); const bool keep_player_specials = player_specials == player_special_data::s_for_mobiles ? true : false; diff --git a/src/engine/entities/char_data.h b/src/engine/entities/char_data.h index 00e1bf54f..25699fe4a 100644 --- a/src/engine/entities/char_data.h +++ b/src/engine/entities/char_data.h @@ -775,8 +775,8 @@ class CharData : public ProtectedCharData { int GetCarryingQuantity() const { return char_specials.carry_items; }; char_affects_list_t affected; // affected by what spells - struct TimedSkill *timed; // use which timed skill/spells - struct TimedFeat *timed_feat; // use which timed feats + std::unordered_map timed_skill; // use which timed skill/spells + std::unordered_map timed_feat; // use which timed feats ObjData *equipment[EEquipPos::kNumEquipPos]; // Equipment array ObjData *carrying; // Head of list diff --git a/src/engine/entities/char_player.cpp b/src/engine/entities/char_player.cpp index 9bb89a464..4823dc5d9 100644 --- a/src/engine/entities/char_player.cpp +++ b/src/engine/entities/char_player.cpp @@ -411,7 +411,6 @@ void Player::save_char() { int i; time_t li; ObjData *char_eq[EEquipPos::kNumEquipPos]; - struct TimedSkill *skj; int tmp = time(0) - this->player_data.time.logon; @@ -539,8 +538,8 @@ void Player::save_char() { if (GetRealLevel(this) < kLvlImmortal) { fprintf(saved, "FtTm:\n"); - for (auto tf = this->timed_feat; tf; tf = tf->next) { - fprintf(saved, "%d %d %s\n", to_underlying(tf->feat), tf->time, MUD::Feat(tf->feat).GetCName()); + for (auto tf : this->timed_feat) { + fprintf(saved, "%d %d %s\n", to_underlying(tf.first), tf.second, MUD::Feat(tf.first).GetCName()); } fprintf(saved, "0 0\n"); } @@ -566,8 +565,8 @@ void Player::save_char() { // Задержки на скилы if (GetRealLevel(this) < kLvlImmortal) { fprintf(saved, "SkTm:\n"); - for (skj = this->timed; skj; skj = skj->next) { - fprintf(saved, "%d %d\n", to_underlying(skj->skill), skj->time); + for (auto skj : this->timed_skill) { + fprintf(saved, "%d %d %s\n", to_underlying(skj.first), skj.second, MUD::Skill(skj.first).GetName()); } fprintf(saved, "0 0\n"); } @@ -956,7 +955,6 @@ int Player::load_char_ascii(const char *name, const int load_flags) { char filename[40]; char line[kMaxStringLength], tag[6]; char line1[kMaxStringLength]; - TimedSkill timed; TimedFeat timed_feat; *filename = '\0'; log("Load ascii char %s", name); @@ -1769,9 +1767,7 @@ int Player::load_char_ascii(const char *name, const int load_flags) { fbgetline(fl, line); sscanf(line, "%d %d", &num, &num2); if (num != 0) { - timed.skill = static_cast(num); - timed.time = num2; - ImposeTimedSkill(this, &timed); + this->timed_skill[static_cast(num)] = num2; } } while (num != 0); } else if (!strcmp(tag, "Spel")) { diff --git a/src/engine/ui/cmd/do_remort.cpp b/src/engine/ui/cmd/do_remort.cpp index 8201d7fda..cc7e7d8d4 100644 --- a/src/engine/ui/cmd/do_remort.cpp +++ b/src/engine/ui/cmd/do_remort.cpp @@ -92,13 +92,8 @@ void DoRemort(CharData *ch, char *argument, int/* cmd*/, int subcmd) { } } - while (ch->timed) { - ExpireTimedSkill(ch, ch->timed); - } - - while (ch->timed_feat) { - ExpireTimedFeat(ch, ch->timed_feat); - } + ch->timed_skill.clear(); + ch->timed_feat.clear(); for (const auto &feat : MUD::Feats()) { ch->UnsetFeat(feat.GetId()); } diff --git a/src/engine/ui/cmd_god/do_arena_restore.cpp b/src/engine/ui/cmd_god/do_arena_restore.cpp index e6d3d6b26..3d51f1ff0 100644 --- a/src/engine/ui/cmd_god/do_arena_restore.cpp +++ b/src/engine/ui/cmd_god/do_arena_restore.cpp @@ -26,12 +26,6 @@ void DoArenaRestore(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { } else { vict->mem_queue.stored = vict->mem_queue.total; } - if (vict->GetSkill(ESkill::kWarcry) > 0) { - struct TimedSkill wctimed; - wctimed.skill = ESkill::kWarcry; - wctimed.time = 0; - ImposeTimedSkill(vict, &wctimed); - } if (IS_GRGOD(ch) && IS_IMMORTAL(vict)) { vict->set_str(25); vict->set_int(25); @@ -46,10 +40,8 @@ void DoArenaRestore(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { RemoveAffectFromChar(vict, ESpell::kAbstinent); //сброс таймеров скиллов и фитов - while (vict->timed) - ExpireTimedSkill(vict, vict->timed); - while (vict->timed_feat) - ExpireTimedFeat(vict, vict->timed_feat); + ch->timed_skill.clear(); + ch->timed_feat.clear(); reset_affects(vict); for (int i = 0; i < EEquipPos::kNumEquipPos; i++) { if (GET_EQ(vict, i)) { diff --git a/src/engine/ui/cmd_god/do_restore.cpp b/src/engine/ui/cmd_god/do_restore.cpp index 7569d08e1..3c2b95dfd 100644 --- a/src/engine/ui/cmd_god/do_restore.cpp +++ b/src/engine/ui/cmd_god/do_restore.cpp @@ -36,12 +36,6 @@ void DoRestore(CharData *ch, char *argument, int/* cmd*/, int subcmd) { } else { vict->mem_queue.stored = vict->mem_queue.total; } - if (vict->GetSkill(ESkill::kWarcry) > 0) { - struct TimedSkill wctimed; - wctimed.skill = ESkill::kWarcry; - wctimed.time = 0; - ImposeTimedSkill(vict, &wctimed); - } if (IS_GRGOD(ch) && IS_IMMORTAL(vict)) { vict->set_str(25); vict->set_int(25); @@ -56,11 +50,8 @@ void DoRestore(CharData *ch, char *argument, int/* cmd*/, int subcmd) { RemoveAffectFromChar(vict, ESpell::kAbstinent); //сброс таймеров скиллов и фитов - while (vict->timed) - ExpireTimedSkill(vict, vict->timed); - while (vict->timed_feat) - ExpireTimedFeat(vict, vict->timed_feat); - + ch->timed_skill.clear(); + ch->timed_feat.clear(); if (subcmd == kScmdRestoreGod) { SendMsgToChar(OK, ch); act("Вы были полностью восстановлены $N4!", diff --git a/src/gameplay/abilities/feats.h b/src/gameplay/abilities/feats.h index d2d172328..547390c0f 100644 --- a/src/gameplay/abilities/feats.h +++ b/src/gameplay/abilities/feats.h @@ -24,7 +24,6 @@ struct TimedFeat { EFeat feat{EFeat::kUndefined}; // Used feature // ubyte time{0}; // Time for next using // - struct TimedFeat *next{nullptr}; }; int CalcMaxFeatSlotPerLvl(const CharData *ch); diff --git a/src/gameplay/affects/affect_data.cpp b/src/gameplay/affects/affect_data.cpp index e217bfba8..7fa1fef96 100644 --- a/src/gameplay/affects/affect_data.cpp +++ b/src/gameplay/affects/affect_data.cpp @@ -191,25 +191,22 @@ void player_timed_update() { for (auto d = descriptor_list; d; d = d->next) { if (d->state != EConState::kPlaying) continue; - const auto i = d->get_character(); - auto ch = i.get(); + const auto ch = d->get_character().get(); - decltype(ch->timed) timed_skill; - for (auto timed = ch->timed; timed; timed = timed_skill) { - timed_skill = timed->next; - if (timed->time >= 1) { - timed->time--; + for (auto timed = ch->timed_skill.begin(); timed != ch->timed_skill.end();) { + if (timed->second >= 1) { + timed->second--; + ++timed; } else { - ExpireTimedSkill(ch, timed); + timed = ch->timed_skill.erase(timed); } } - decltype(ch->timed_feat) timed_feat; - for (auto timed = ch->timed_feat; timed; timed = timed_feat) { - timed_feat = timed->next; - if (timed->time >= 1) { - timed->time--; + for (auto timed = ch->timed_feat.begin(); timed != ch->timed_feat.end();) { + if (timed->second >= 1) { + timed->second--; + ++timed; } else { - ExpireTimedFeat(ch, timed); + timed = ch->timed_feat.erase(timed); } } } @@ -448,22 +445,20 @@ void mobile_affect_update() { if (need_recalc) { affect_total(ch); } - decltype(ch->timed) timed_skill; - for (auto timed = ch->timed; timed; timed = timed_skill) { - timed_skill = timed->next; - if (timed->time >= 1) { - timed->time--; + for (auto timed = ch->timed_skill.begin(); timed != ch->timed_skill.end();) { + if (timed->second >= 1) { + timed->second--; + ++timed; } else { - ExpireTimedSkill(ch, timed); + timed = ch->timed_skill.erase(timed); } } - decltype(ch->timed_feat) timed_feat; - for (auto timed = ch->timed_feat; timed; timed = timed_feat) { - timed_feat = timed->next; - if (timed->time >= 1) { - timed->time--; + for (auto timed = ch->timed_feat.begin(); timed != ch->timed_feat.end();) { + if (timed->second >= 1) { + timed->second--; + ++timed; } else { - ExpireTimedFeat(ch, timed); + timed = ch->timed_feat.erase(timed); } } if (deathtrap::check_death_trap(ch)) {