From 9376f54628ebbcc581c21182581e7f8884d6d8ff Mon Sep 17 00:00:00 2001 From: Bylins Date: Thu, 26 Feb 2026 18:38:35 +0300 Subject: [PATCH 1/2] =?UTF-8?q?timed=20skill=20=D1=81=D0=BC=20#2918?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/core/handler.cpp | 36 ++++++---------------- src/engine/core/handler.h | 4 +-- src/engine/core/iosystem.cpp | 6 ++-- src/engine/entities/char_data.cpp | 6 +--- src/engine/entities/char_data.h | 2 +- src/engine/entities/char_player.cpp | 10 ++---- src/engine/ui/cmd/do_camouflage.cpp | 2 +- src/engine/ui/cmd/do_courage.cpp | 2 +- src/engine/ui/cmd/do_drunkoff.cpp | 2 +- src/engine/ui/cmd/do_pray.cpp | 2 +- src/engine/ui/cmd/do_remort.cpp | 5 +-- src/engine/ui/cmd_god/do_arena_restore.cpp | 9 +----- src/engine/ui/cmd_god/do_restore.cpp | 9 +----- src/gameplay/affects/affect_data.cpp | 25 +++++++-------- src/gameplay/ai/mob_memory.cpp | 2 +- src/gameplay/skills/firstaid.cpp | 2 +- src/gameplay/skills/identify.cpp | 2 +- src/gameplay/skills/manadrain.cpp | 2 +- src/gameplay/skills/repair.cpp | 2 +- src/gameplay/skills/skills.h | 1 - src/gameplay/skills/stun.cpp | 2 +- src/gameplay/skills/townportal.cpp | 2 +- src/gameplay/skills/turnundead.cpp | 2 +- src/gameplay/skills/warcry.cpp | 2 +- 24 files changed, 47 insertions(+), 92 deletions(-) diff --git a/src/engine/core/handler.cpp b/src/engine/core/handler.cpp index 543547890..0530e172d 100644 --- a/src/engine/core/handler.cpp +++ b/src/engine/core/handler.cpp @@ -191,42 +191,26 @@ 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; +void ImposeTimedSkill(CharData *ch, struct TimedSkill timed) { + 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..6cf751e23 100644 --- a/src/engine/core/handler.h +++ b/src/engine/core/handler.h @@ -44,8 +44,8 @@ void CheckLight(CharData *ch, int was_equip, int was_single, int was_holylight, void ImposeTimedFeat(CharData *ch, TimedFeat *timed); void ExpireTimedFeat(CharData *ch, TimedFeat *timed); int IsTimedByFeat(CharData *ch, EFeat feat); -void ImposeTimedSkill(CharData *ch, struct TimedSkill *timed); -void ExpireTimedSkill(CharData *ch, struct TimedSkill *timed); +void ImposeTimedSkill(CharData *ch, struct 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..72c0b7464 100644 --- a/src/engine/entities/char_data.cpp +++ b/src/engine/entities/char_data.cpp @@ -338,7 +338,6 @@ void CharData::zero_init() { punctual_wait = 0; last_comm.clear(); player_specials = nullptr; - timed = nullptr; timed_feat = nullptr; carrying = nullptr; desc = nullptr; @@ -430,10 +429,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..a0871f142 100644 --- a/src/engine/entities/char_data.h +++ b/src/engine/entities/char_data.h @@ -775,7 +775,7 @@ 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 + std::unordered_map timed_skill; // use which timed skill/spells struct TimedFeat *timed_feat; // use which timed feats ObjData *equipment[EEquipPos::kNumEquipPos]; // Equipment array diff --git a/src/engine/entities/char_player.cpp b/src/engine/entities/char_player.cpp index 9bb89a464..978ffdb16 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; @@ -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\n", to_underlying(skj.first), skj.second); } 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_camouflage.cpp b/src/engine/ui/cmd/do_camouflage.cpp index 39c81d73c..040987459 100644 --- a/src/engine/ui/cmd/do_camouflage.cpp +++ b/src/engine/ui/cmd/do_camouflage.cpp @@ -66,7 +66,7 @@ void do_camouflage(CharData *ch, char * /*argument*/, int/* cmd*/, int/* subcmd* if (!IS_IMMORTAL(ch)) { timed.skill = ESkill::kDisguise; timed.time = 2; - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); } } diff --git a/src/engine/ui/cmd/do_courage.cpp b/src/engine/ui/cmd/do_courage.cpp index cd0c73fee..e985708d9 100644 --- a/src/engine/ui/cmd/do_courage.cpp +++ b/src/engine/ui/cmd/do_courage.cpp @@ -28,7 +28,7 @@ void do_courage(CharData *ch, char * /*argument*/, int/* cmd*/, int/* subcmd*/) struct TimedSkill timed; timed.skill = ESkill::kCourage; timed.time = 6; - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); auto prob = CalcCurrentSkill(ch, ESkill::kCourage, nullptr) / 20; auto dur = 1 + std::min(5, ch->GetSkill(ESkill::kCourage) / 40); Affect af[4]; diff --git a/src/engine/ui/cmd/do_drunkoff.cpp b/src/engine/ui/cmd/do_drunkoff.cpp index 0ffda2825..d5abc66fc 100644 --- a/src/engine/ui/cmd/do_drunkoff.cpp +++ b/src/engine/ui/cmd/do_drunkoff.cpp @@ -101,7 +101,7 @@ void do_drunkoff(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { timed.skill = ESkill::kHangovering; timed.time = 12; - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); percent = number(1, MUD::Skill(ESkill::kHangovering).difficulty); prob = CalcCurrentSkill(ch, ESkill::kHangovering, nullptr); diff --git a/src/engine/ui/cmd/do_pray.cpp b/src/engine/ui/cmd/do_pray.cpp index 4dc05a266..8b91a5a87 100644 --- a/src/engine/ui/cmd/do_pray.cpp +++ b/src/engine/ui/cmd/do_pray.cpp @@ -99,7 +99,7 @@ void do_pray(CharData *ch, char *argument, int/* cmd*/, int subcmd) { timed.skill = ESkill::kReligion; timed.time = 12; - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); for (const auto &i : pray_affect) { if (i.metter == metter) { diff --git a/src/engine/ui/cmd/do_remort.cpp b/src/engine/ui/cmd/do_remort.cpp index 8201d7fda..9a4287fb3 100644 --- a/src/engine/ui/cmd/do_remort.cpp +++ b/src/engine/ui/cmd/do_remort.cpp @@ -92,10 +92,7 @@ void DoRemort(CharData *ch, char *argument, int/* cmd*/, int subcmd) { } } - while (ch->timed) { - ExpireTimedSkill(ch, ch->timed); - } - + ch->timed_skill.clear(); while (ch->timed_feat) { ExpireTimedFeat(ch, ch->timed_feat); } diff --git a/src/engine/ui/cmd_god/do_arena_restore.cpp b/src/engine/ui/cmd_god/do_arena_restore.cpp index e6d3d6b26..6ba054507 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,8 +40,7 @@ void DoArenaRestore(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { RemoveAffectFromChar(vict, ESpell::kAbstinent); //сброс таймеров скиллов и фитов - while (vict->timed) - ExpireTimedSkill(vict, vict->timed); + vict->timed_skill.clear(); while (vict->timed_feat) ExpireTimedFeat(vict, vict->timed_feat); reset_affects(vict); diff --git a/src/engine/ui/cmd_god/do_restore.cpp b/src/engine/ui/cmd_god/do_restore.cpp index 7569d08e1..d8c34fb2e 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,8 +50,7 @@ void DoRestore(CharData *ch, char *argument, int/* cmd*/, int subcmd) { RemoveAffectFromChar(vict, ESpell::kAbstinent); //сброс таймеров скиллов и фитов - while (vict->timed) - ExpireTimedSkill(vict, vict->timed); + vict->timed_skill.clear(); while (vict->timed_feat) ExpireTimedFeat(vict, vict->timed_feat); diff --git a/src/gameplay/affects/affect_data.cpp b/src/gameplay/affects/affect_data.cpp index e217bfba8..b1270d170 100644 --- a/src/gameplay/affects/affect_data.cpp +++ b/src/gameplay/affects/affect_data.cpp @@ -191,16 +191,14 @@ 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; @@ -448,13 +446,12 @@ 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; diff --git a/src/gameplay/ai/mob_memory.cpp b/src/gameplay/ai/mob_memory.cpp index a51d0161b..7f13e7d40 100644 --- a/src/gameplay/ai/mob_memory.cpp +++ b/src/gameplay/ai/mob_memory.cpp @@ -49,7 +49,7 @@ void mobRemember(CharData *ch, CharData *victim) { if (!IsTimedBySkill(victim, ESkill::kHideTrack) && victim->GetSkill(ESkill::kHideTrack)) { timed.skill = ESkill::kHideTrack; timed.time = ch->GetSkill(ESkill::kTrack) ? 6 : 3; - ImposeTimedSkill(victim, &timed); + ImposeTimedSkill(victim, timed); } } diff --git a/src/gameplay/skills/firstaid.cpp b/src/gameplay/skills/firstaid.cpp index 65e2d6a0d..e8116cc80 100644 --- a/src/gameplay/skills/firstaid.cpp +++ b/src/gameplay/skills/firstaid.cpp @@ -79,7 +79,7 @@ void DoFirstaid(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { if (CanUseFeat(ch, EFeat::kPhysicians)) time /=2; timed.time = time; - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); ImproveSkill(ch, ESkill::kFirstAid, success, nullptr); if (vict != ch) { if (success) { diff --git a/src/gameplay/skills/identify.cpp b/src/gameplay/skills/identify.cpp index 67e93b98b..b395a72e5 100644 --- a/src/gameplay/skills/identify.cpp +++ b/src/gameplay/skills/identify.cpp @@ -32,7 +32,7 @@ void do_identify(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { auto time = 12; time = std::max(1, time); timed.time = std::max(time - ((ch->GetSkill(ESkill::kIdentify) - 25) / 25), 1); //12..5 or 8..1 - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); } MANUAL_SPELL(SkillIdentify) } diff --git a/src/gameplay/skills/manadrain.cpp b/src/gameplay/skills/manadrain.cpp index 3b2bb159f..ddff19493 100644 --- a/src/gameplay/skills/manadrain.cpp +++ b/src/gameplay/skills/manadrain.cpp @@ -85,6 +85,6 @@ void do_manadrain(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { timed.time = 1; else timed.time = 6 - std::min(4, (ch->GetSkill(ESkill::kJinx) + 30) / 50); - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); } } diff --git a/src/gameplay/skills/repair.cpp b/src/gameplay/skills/repair.cpp index b4867940b..c900a3fbd 100644 --- a/src/gameplay/skills/repair.cpp +++ b/src/gameplay/skills/repair.cpp @@ -71,7 +71,7 @@ void DoRepair(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { timed.skill = ESkill::kRepair; auto modif = ch->GetSkill(ESkill::kRepair) / 7 + number(1, 5); timed.time = std::max(1, 25 - modif); - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); obj->set_current_durability(std::min(obj->get_maximum_durability(), obj->get_current_durability() * percent / prob + 1)); SendMsgToChar(ch, "Теперь %s выгляд%s лучше.\r\n", obj->get_PName(ECase::kNom).c_str(), GET_OBJ_POLY_1(ch, obj)); diff --git a/src/gameplay/skills/skills.h b/src/gameplay/skills/skills.h index 4538c4330..09b08f1c1 100644 --- a/src/gameplay/skills/skills.h +++ b/src/gameplay/skills/skills.h @@ -165,7 +165,6 @@ struct SkillRollResult { struct TimedSkill { ESkill skill{ESkill::kUndefined}; // Used skill // ubyte time{0}; // Time for next using // - TimedSkill *next{nullptr}; }; int SendSkillMessages(int dam, CharData *ch, CharData *vict, int attacktype, std::string add = ""); diff --git a/src/gameplay/skills/stun.cpp b/src/gameplay/skills/stun.cpp index 0689c7e09..49db26442 100644 --- a/src/gameplay/skills/stun.cpp +++ b/src/gameplay/skills/stun.cpp @@ -56,7 +56,7 @@ void go_stun(CharData *ch, CharData *vict) { timed.skill = ESkill::kStun; timed.time = std::clamp(7 - (ch->GetSkill(ESkill::kStun) - (MUD::Skill(ESkill::kStun).cap / 4 * 3)) / 10, 2, 7); - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); int percent = number(1, MUD::Skill(ESkill::kStun).difficulty); int prob = CalcCurrentSkill(ch, ESkill::kStun, vict); diff --git a/src/gameplay/skills/townportal.cpp b/src/gameplay/skills/townportal.cpp index 49e5344f2..580ec6b60 100644 --- a/src/gameplay/skills/townportal.cpp +++ b/src/gameplay/skills/townportal.cpp @@ -123,7 +123,7 @@ void SetSkillTownportalTimer(CharData *ch) { // timed.time - это unsigned char, поэтому при уходе в минус будет вынос на 255 и ниже int modif = ch->GetSkill(ESkill::kTownportal) / 7 + number(1, 5); timed.time = MAX(1, 25 - modif); - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); } } diff --git a/src/gameplay/skills/turnundead.cpp b/src/gameplay/skills/turnundead.cpp index 9b5a5abfe..e922aeb04 100644 --- a/src/gameplay/skills/turnundead.cpp +++ b/src/gameplay/skills/turnundead.cpp @@ -36,7 +36,7 @@ void do_turn_undead(CharData *ch, char * /*argument*/, int/* cmd*/, int/* subcmd SendMsgToChar("Вам пока не по силам изгонять нежить, нужно отдохнуть.\r\n", ch); return; } - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); SendMsgToChar(ch, "Вы свели руки в магическом жесте и отовсюду хлынули яркие лучи света.\r\n"); act("$n свел$g руки в магическом жесте и отовсюду хлынули яркие лучи света.\r\n", diff --git a/src/gameplay/skills/warcry.cpp b/src/gameplay/skills/warcry.cpp index 6862f388f..19eebafc2 100644 --- a/src/gameplay/skills/warcry.cpp +++ b/src/gameplay/skills/warcry.cpp @@ -94,7 +94,7 @@ void do_warcry(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { if (ch->get_wait() <= 0) { SetWaitState(ch, kBattleRound); } - ImposeTimedSkill(ch, &timed); + ImposeTimedSkill(ch, timed); ch->set_move(ch->get_move() - MUD::Spell(spell_id).GetMaxMana()); } TrainSkill(ch, ESkill::kWarcry, true, nullptr); From 36123c01c83df20f650ead7fb705a978908620a1 Mon Sep 17 00:00:00 2001 From: Bylins Date: Thu, 26 Feb 2026 19:42:06 +0300 Subject: [PATCH 2/2] =?UTF-8?q?timed=20skill=20and=20feat=20=D1=80=D0=B5?= =?UTF-8?q?=D1=84=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D1=81?= =?UTF-8?q?=D0=BC=20#2918?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/core/handler.cpp | 53 +++++++--------------- src/engine/core/handler.h | 4 +- src/engine/entities/char_data.cpp | 1 - src/engine/entities/char_data.h | 2 +- src/engine/entities/char_player.cpp | 6 +-- src/engine/ui/cmd/do_camouflage.cpp | 2 +- src/engine/ui/cmd/do_courage.cpp | 2 +- src/engine/ui/cmd/do_drunkoff.cpp | 2 +- src/engine/ui/cmd/do_pray.cpp | 2 +- src/engine/ui/cmd/do_remort.cpp | 4 +- src/engine/ui/cmd_god/do_arena_restore.cpp | 5 +- src/engine/ui/cmd_god/do_restore.cpp | 6 +-- src/gameplay/abilities/feats.h | 1 - src/gameplay/affects/affect_data.cpp | 22 ++++----- src/gameplay/ai/mob_memory.cpp | 2 +- src/gameplay/skills/firstaid.cpp | 2 +- src/gameplay/skills/identify.cpp | 2 +- src/gameplay/skills/manadrain.cpp | 2 +- src/gameplay/skills/repair.cpp | 2 +- src/gameplay/skills/skills.h | 1 + src/gameplay/skills/stun.cpp | 2 +- src/gameplay/skills/townportal.cpp | 2 +- src/gameplay/skills/turnundead.cpp | 2 +- src/gameplay/skills/warcry.cpp | 2 +- 24 files changed, 52 insertions(+), 79 deletions(-) diff --git a/src/engine/core/handler.cpp b/src/engine/core/handler.cpp index 0530e172d..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,48 +149,31 @@ 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); } /** * Insert an TimedSkill in a char_data structure */ -void ImposeTimedSkill(CharData *ch, struct TimedSkill timed) { - ch->timed_skill[timed.skill] = std::max(1, timed.time + GetTalentTimerMod(ch, timed.skill)); +void ImposeTimedSkill(CharData *ch, struct TimedSkill *timed) { + ch->timed_skill[timed->skill] = std::max(1, timed->time + GetTalentTimerMod(ch, timed->skill)); } void ExpireTimedSkill(CharData *ch, ESkill skill) { diff --git a/src/engine/core/handler.h b/src/engine/core/handler.h index 6cf751e23..c20a91108 100644 --- a/src/engine/core/handler.h +++ b/src/engine/core/handler.h @@ -42,9 +42,9 @@ 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 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/entities/char_data.cpp b/src/engine/entities/char_data.cpp index 72c0b7464..3c6a84cff 100644 --- a/src/engine/entities/char_data.cpp +++ b/src/engine/entities/char_data.cpp @@ -338,7 +338,6 @@ void CharData::zero_init() { punctual_wait = 0; last_comm.clear(); player_specials = nullptr; - timed_feat = nullptr; carrying = nullptr; desc = nullptr; followers = nullptr; diff --git a/src/engine/entities/char_data.h b/src/engine/entities/char_data.h index a0871f142..25699fe4a 100644 --- a/src/engine/entities/char_data.h +++ b/src/engine/entities/char_data.h @@ -776,7 +776,7 @@ class CharData : public ProtectedCharData { char_affects_list_t affected; // affected by what spells std::unordered_map timed_skill; // use which timed skill/spells - struct TimedFeat *timed_feat; // use which timed feats + 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 978ffdb16..4823dc5d9 100644 --- a/src/engine/entities/char_player.cpp +++ b/src/engine/entities/char_player.cpp @@ -538,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,7 +566,7 @@ void Player::save_char() { if (GetRealLevel(this) < kLvlImmortal) { fprintf(saved, "SkTm:\n"); for (auto skj : this->timed_skill) { - fprintf(saved, "%d %d\n", to_underlying(skj.first), skj.second); + fprintf(saved, "%d %d %s\n", to_underlying(skj.first), skj.second, MUD::Skill(skj.first).GetName()); } fprintf(saved, "0 0\n"); } diff --git a/src/engine/ui/cmd/do_camouflage.cpp b/src/engine/ui/cmd/do_camouflage.cpp index 040987459..39c81d73c 100644 --- a/src/engine/ui/cmd/do_camouflage.cpp +++ b/src/engine/ui/cmd/do_camouflage.cpp @@ -66,7 +66,7 @@ void do_camouflage(CharData *ch, char * /*argument*/, int/* cmd*/, int/* subcmd* if (!IS_IMMORTAL(ch)) { timed.skill = ESkill::kDisguise; timed.time = 2; - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); } } diff --git a/src/engine/ui/cmd/do_courage.cpp b/src/engine/ui/cmd/do_courage.cpp index e985708d9..cd0c73fee 100644 --- a/src/engine/ui/cmd/do_courage.cpp +++ b/src/engine/ui/cmd/do_courage.cpp @@ -28,7 +28,7 @@ void do_courage(CharData *ch, char * /*argument*/, int/* cmd*/, int/* subcmd*/) struct TimedSkill timed; timed.skill = ESkill::kCourage; timed.time = 6; - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); auto prob = CalcCurrentSkill(ch, ESkill::kCourage, nullptr) / 20; auto dur = 1 + std::min(5, ch->GetSkill(ESkill::kCourage) / 40); Affect af[4]; diff --git a/src/engine/ui/cmd/do_drunkoff.cpp b/src/engine/ui/cmd/do_drunkoff.cpp index d5abc66fc..0ffda2825 100644 --- a/src/engine/ui/cmd/do_drunkoff.cpp +++ b/src/engine/ui/cmd/do_drunkoff.cpp @@ -101,7 +101,7 @@ void do_drunkoff(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { timed.skill = ESkill::kHangovering; timed.time = 12; - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); percent = number(1, MUD::Skill(ESkill::kHangovering).difficulty); prob = CalcCurrentSkill(ch, ESkill::kHangovering, nullptr); diff --git a/src/engine/ui/cmd/do_pray.cpp b/src/engine/ui/cmd/do_pray.cpp index 8b91a5a87..4dc05a266 100644 --- a/src/engine/ui/cmd/do_pray.cpp +++ b/src/engine/ui/cmd/do_pray.cpp @@ -99,7 +99,7 @@ void do_pray(CharData *ch, char *argument, int/* cmd*/, int subcmd) { timed.skill = ESkill::kReligion; timed.time = 12; - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); for (const auto &i : pray_affect) { if (i.metter == metter) { diff --git a/src/engine/ui/cmd/do_remort.cpp b/src/engine/ui/cmd/do_remort.cpp index 9a4287fb3..cc7e7d8d4 100644 --- a/src/engine/ui/cmd/do_remort.cpp +++ b/src/engine/ui/cmd/do_remort.cpp @@ -93,9 +93,7 @@ void DoRemort(CharData *ch, char *argument, int/* cmd*/, int subcmd) { } ch->timed_skill.clear(); - while (ch->timed_feat) { - ExpireTimedFeat(ch, ch->timed_feat); - } + 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 6ba054507..3d51f1ff0 100644 --- a/src/engine/ui/cmd_god/do_arena_restore.cpp +++ b/src/engine/ui/cmd_god/do_arena_restore.cpp @@ -40,9 +40,8 @@ void DoArenaRestore(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { RemoveAffectFromChar(vict, ESpell::kAbstinent); //сброс таймеров скиллов и фитов - vict->timed_skill.clear(); - 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 d8c34fb2e..3c2b95dfd 100644 --- a/src/engine/ui/cmd_god/do_restore.cpp +++ b/src/engine/ui/cmd_god/do_restore.cpp @@ -50,10 +50,8 @@ void DoRestore(CharData *ch, char *argument, int/* cmd*/, int subcmd) { RemoveAffectFromChar(vict, ESpell::kAbstinent); //сброс таймеров скиллов и фитов - vict->timed_skill.clear(); - 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 b1270d170..7fa1fef96 100644 --- a/src/gameplay/affects/affect_data.cpp +++ b/src/gameplay/affects/affect_data.cpp @@ -201,13 +201,12 @@ void player_timed_update() { 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); } } } @@ -454,13 +453,12 @@ void mobile_affect_update() { 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)) { diff --git a/src/gameplay/ai/mob_memory.cpp b/src/gameplay/ai/mob_memory.cpp index 7f13e7d40..a51d0161b 100644 --- a/src/gameplay/ai/mob_memory.cpp +++ b/src/gameplay/ai/mob_memory.cpp @@ -49,7 +49,7 @@ void mobRemember(CharData *ch, CharData *victim) { if (!IsTimedBySkill(victim, ESkill::kHideTrack) && victim->GetSkill(ESkill::kHideTrack)) { timed.skill = ESkill::kHideTrack; timed.time = ch->GetSkill(ESkill::kTrack) ? 6 : 3; - ImposeTimedSkill(victim, timed); + ImposeTimedSkill(victim, &timed); } } diff --git a/src/gameplay/skills/firstaid.cpp b/src/gameplay/skills/firstaid.cpp index e8116cc80..65e2d6a0d 100644 --- a/src/gameplay/skills/firstaid.cpp +++ b/src/gameplay/skills/firstaid.cpp @@ -79,7 +79,7 @@ void DoFirstaid(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { if (CanUseFeat(ch, EFeat::kPhysicians)) time /=2; timed.time = time; - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); ImproveSkill(ch, ESkill::kFirstAid, success, nullptr); if (vict != ch) { if (success) { diff --git a/src/gameplay/skills/identify.cpp b/src/gameplay/skills/identify.cpp index b395a72e5..67e93b98b 100644 --- a/src/gameplay/skills/identify.cpp +++ b/src/gameplay/skills/identify.cpp @@ -32,7 +32,7 @@ void do_identify(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { auto time = 12; time = std::max(1, time); timed.time = std::max(time - ((ch->GetSkill(ESkill::kIdentify) - 25) / 25), 1); //12..5 or 8..1 - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); } MANUAL_SPELL(SkillIdentify) } diff --git a/src/gameplay/skills/manadrain.cpp b/src/gameplay/skills/manadrain.cpp index ddff19493..3b2bb159f 100644 --- a/src/gameplay/skills/manadrain.cpp +++ b/src/gameplay/skills/manadrain.cpp @@ -85,6 +85,6 @@ void do_manadrain(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { timed.time = 1; else timed.time = 6 - std::min(4, (ch->GetSkill(ESkill::kJinx) + 30) / 50); - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); } } diff --git a/src/gameplay/skills/repair.cpp b/src/gameplay/skills/repair.cpp index c900a3fbd..b4867940b 100644 --- a/src/gameplay/skills/repair.cpp +++ b/src/gameplay/skills/repair.cpp @@ -71,7 +71,7 @@ void DoRepair(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { timed.skill = ESkill::kRepair; auto modif = ch->GetSkill(ESkill::kRepair) / 7 + number(1, 5); timed.time = std::max(1, 25 - modif); - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); obj->set_current_durability(std::min(obj->get_maximum_durability(), obj->get_current_durability() * percent / prob + 1)); SendMsgToChar(ch, "Теперь %s выгляд%s лучше.\r\n", obj->get_PName(ECase::kNom).c_str(), GET_OBJ_POLY_1(ch, obj)); diff --git a/src/gameplay/skills/skills.h b/src/gameplay/skills/skills.h index 09b08f1c1..4538c4330 100644 --- a/src/gameplay/skills/skills.h +++ b/src/gameplay/skills/skills.h @@ -165,6 +165,7 @@ struct SkillRollResult { struct TimedSkill { ESkill skill{ESkill::kUndefined}; // Used skill // ubyte time{0}; // Time for next using // + TimedSkill *next{nullptr}; }; int SendSkillMessages(int dam, CharData *ch, CharData *vict, int attacktype, std::string add = ""); diff --git a/src/gameplay/skills/stun.cpp b/src/gameplay/skills/stun.cpp index 49db26442..0689c7e09 100644 --- a/src/gameplay/skills/stun.cpp +++ b/src/gameplay/skills/stun.cpp @@ -56,7 +56,7 @@ void go_stun(CharData *ch, CharData *vict) { timed.skill = ESkill::kStun; timed.time = std::clamp(7 - (ch->GetSkill(ESkill::kStun) - (MUD::Skill(ESkill::kStun).cap / 4 * 3)) / 10, 2, 7); - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); int percent = number(1, MUD::Skill(ESkill::kStun).difficulty); int prob = CalcCurrentSkill(ch, ESkill::kStun, vict); diff --git a/src/gameplay/skills/townportal.cpp b/src/gameplay/skills/townportal.cpp index 580ec6b60..49e5344f2 100644 --- a/src/gameplay/skills/townportal.cpp +++ b/src/gameplay/skills/townportal.cpp @@ -123,7 +123,7 @@ void SetSkillTownportalTimer(CharData *ch) { // timed.time - это unsigned char, поэтому при уходе в минус будет вынос на 255 и ниже int modif = ch->GetSkill(ESkill::kTownportal) / 7 + number(1, 5); timed.time = MAX(1, 25 - modif); - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); } } diff --git a/src/gameplay/skills/turnundead.cpp b/src/gameplay/skills/turnundead.cpp index e922aeb04..9b5a5abfe 100644 --- a/src/gameplay/skills/turnundead.cpp +++ b/src/gameplay/skills/turnundead.cpp @@ -36,7 +36,7 @@ void do_turn_undead(CharData *ch, char * /*argument*/, int/* cmd*/, int/* subcmd SendMsgToChar("Вам пока не по силам изгонять нежить, нужно отдохнуть.\r\n", ch); return; } - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); SendMsgToChar(ch, "Вы свели руки в магическом жесте и отовсюду хлынули яркие лучи света.\r\n"); act("$n свел$g руки в магическом жесте и отовсюду хлынули яркие лучи света.\r\n", diff --git a/src/gameplay/skills/warcry.cpp b/src/gameplay/skills/warcry.cpp index 19eebafc2..6862f388f 100644 --- a/src/gameplay/skills/warcry.cpp +++ b/src/gameplay/skills/warcry.cpp @@ -94,7 +94,7 @@ void do_warcry(CharData *ch, char *argument, int/* cmd*/, int/* subcmd*/) { if (ch->get_wait() <= 0) { SetWaitState(ch, kBattleRound); } - ImposeTimedSkill(ch, timed); + ImposeTimedSkill(ch, &timed); ch->set_move(ch->get_move() - MUD::Spell(spell_id).GetMaxMana()); } TrainSkill(ch, ESkill::kWarcry, true, nullptr);