From fd587da229b3f140cb00a11b28973924b216a3a7 Mon Sep 17 00:00:00 2001 From: thokkat Date: Tue, 16 Jul 2024 19:41:43 +0200 Subject: [PATCH 1/9] set non-zero damage type --- game/world/objects/npc.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/game/world/objects/npc.cpp b/game/world/objects/npc.cpp index bd6f93eac..ca78ce2e8 100644 --- a/game/world/objects/npc.cpp +++ b/game/world/objects/npc.cpp @@ -168,6 +168,10 @@ Npc::Npc(World &owner, size_t instance, std::string_view waypoint) owner.script().initializeInstanceNpc(hnpc, instance); hnpc->wp = std::string(waypoint); + + // vanilla forces non-zero damage type + if(hnpc->damage_type==0) + hnpc->damage_type = 2; } Npc::~Npc(){ From 865e7af06e532b460fe7e5bb2fd41608aeabbac1 Mon Sep 17 00:00:00 2001 From: thokkat Date: Tue, 16 Jul 2024 19:41:43 +0200 Subject: [PATCH 2/9] remove leftover of special handling for 1hp npcs --- game/world/objects/npc.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/game/world/objects/npc.cpp b/game/world/objects/npc.cpp index ca78ce2e8..9b2703c2f 100644 --- a/game/world/objects/npc.cpp +++ b/game/world/objects/npc.cpp @@ -436,15 +436,12 @@ float Npc::angleDir(float x, float z) { } bool Npc::resetPositionToTA() { - const bool g2 = owner.version().game==2; - const bool isDead = this->isDead(); + const bool g2 = owner.version().game==2; + const bool isDragon = (g2 && guild()==GIL_DRAGON); + const bool isDead = this->isDead(); - if(isDead && !invent.hasMissionItems()) { - const bool isDragon = (g2 && guild()==GIL_DRAGON); - const bool isBackgroundBody = (hnpc->attribute[ATR_HITPOINTSMAX]==1); - if(!isBackgroundBody && !isDragon) - return false; - } + if(isDead && !invent.hasMissionItems() && !isDragon) + return false; invent.clearSlot(*this,"",currentInteract!=nullptr); if(!isPlayer()) From d9f91eb295fa3766842c0b6949fbca2d16771ed9 Mon Sep 17 00:00:00 2001 From: thokkat Date: Tue, 16 Jul 2024 19:41:43 +0200 Subject: [PATCH 3/9] call script function B_RefreshAtInsert if npc is reset --- game/game/gamescript.cpp | 8 ++++++++ game/game/gamescript.h | 1 + game/world/objects/npc.cpp | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/game/game/gamescript.cpp b/game/game/gamescript.cpp index 609227104..dadd1c7bb 100644 --- a/game/game/gamescript.cpp +++ b/game/game/gamescript.cpp @@ -1128,6 +1128,14 @@ void GameScript::invokePickLock(Npc& npc, int bSuccess, int bBrokenOpen) { vm.call_function(fn, bSuccess, bBrokenOpen); } +void GameScript::invokeRefreshAtInsert(Npc& npc) { + auto fn = vm.find_symbol_by_name("B_RefreshAtInsert"); + if(fn==nullptr) + return; + ScopeVar self(*vm.global_self(), npc.handlePtr()); + vm.call_function(fn); + } + CollideMask GameScript::canNpcCollideWithSpell(Npc& npc, Npc* shooter, int32_t spellId) { auto fn = vm.find_symbol_by_name("C_CanNpcCollideWithSpell"); if(fn==nullptr) diff --git a/game/game/gamescript.h b/game/game/gamescript.h index 358d6ed71..33c363faa 100644 --- a/game/game/gamescript.h +++ b/game/game/gamescript.h @@ -137,6 +137,7 @@ class GameScript final { void invokeSpell(Npc& npc, Npc *target, Item& fn); int invokeCond (Npc& npc, std::string_view func); void invokePickLock(Npc& npc, int bSuccess, int bBrokenOpen); + void invokeRefreshAtInsert(Npc& npc); auto canNpcCollideWithSpell(Npc& npc, Npc* shooter, int32_t spellId) -> CollideMask; int playerHotKeyScreenMap(Npc& pl); diff --git a/game/world/objects/npc.cpp b/game/world/objects/npc.cpp index 9b2703c2f..15ff5381b 100644 --- a/game/world/objects/npc.cpp +++ b/game/world/objects/npc.cpp @@ -474,6 +474,10 @@ bool Npc::resetPositionToTA() { if(!isDead) attachToPoint(at); + + if(g2) + owner.script().invokeRefreshAtInsert(*this); + return true; } From 8713c6b74a388b5fa34e1e10f56242916e44d76e Mon Sep 17 00:00:00 2001 From: thokkat Date: Tue, 16 Jul 2024 19:41:43 +0200 Subject: [PATCH 4/9] autoequip melee weapons if npc is reset --- game/game/inventory.cpp | 6 +----- game/game/inventory.h | 2 +- game/world/objects/npc.cpp | 5 ++++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/game/game/inventory.cpp b/game/game/inventory.cpp index d38e07ea4..c2aee5867 100644 --- a/game/game/inventory.cpp +++ b/game/game/inventory.cpp @@ -905,13 +905,9 @@ void Inventory::invalidateCond(Item *&slot, Npc &owner) { } } -void Inventory::autoEquip(Npc &owner) { - sortItems(); - - auto a = bestArmour (owner); +void Inventory::autoEquipWeapons(Npc &owner) { auto m = bestMeleeWeapon(owner); auto r = bestRangeWeapon(owner); - setSlot(armour,a,owner,false); setSlot(melee ,m,owner,false); setSlot(range ,r,owner,false); } diff --git a/game/game/inventory.h b/game/game/inventory.h index 691b401ff..3c48a8a99 100644 --- a/game/game/inventory.h +++ b/game/game/inventory.h @@ -77,7 +77,7 @@ class Inventory final { void unequip(Item* cls, Npc &owner); void invalidateCond(Npc &owner); bool isChanged() const { return !sorted; } - void autoEquip(Npc &owner); + void autoEquipWeapons(Npc &owner); void equipArmour (int32_t cls, Npc &owner); void equipBestArmour (Npc &owner); void equipBestMeleeWeapon(Npc &owner); diff --git a/game/world/objects/npc.cpp b/game/world/objects/npc.cpp index 15ff5381b..7291c5013 100644 --- a/game/world/objects/npc.cpp +++ b/game/world/objects/npc.cpp @@ -472,8 +472,11 @@ bool Npc::resetPositionToTA() { setDirection(at->dirX,at->dirY,at->dirZ); owner.script().fixNpcPosition(*this,0,0); - if(!isDead) + if(!isDead) { attachToPoint(at); + if(!isMonster()) + invent.autoEquipWeapons(*this); + } if(g2) owner.script().invokeRefreshAtInsert(*this); From e972797e2c49f85f233b782a831726e5f3bb38fe Mon Sep 17 00:00:00 2001 From: thokkat Date: Tue, 16 Jul 2024 19:41:43 +0200 Subject: [PATCH 5/9] add munition availability as check for best weapon search --- game/game/inventory.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/game/game/inventory.cpp b/game/game/inventory.cpp index c2aee5867..5ba80c22b 100644 --- a/game/game/inventory.cpp +++ b/game/game/inventory.cpp @@ -946,6 +946,8 @@ Item* Inventory::bestItem(Npc &owner, ItmFlags f) { continue; if(!i->checkCond(owner)) continue; + if(itData.munition>0 && findByClass(size_t(itData.munition))==nullptr) + continue; if(itData.value>g){ ret=i.get(); From 36dde5ec5ecf7bed69b4aceddb66b750f6556300 Mon Sep 17 00:00:00 2001 From: thokkat Date: Mon, 22 Jul 2024 14:10:05 +0200 Subject: [PATCH 6/9] cache symbol B_RefreshAtInsert --- game/game/gamescript.cpp | 9 +++++---- game/game/gamescript.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/game/game/gamescript.cpp b/game/game/gamescript.cpp index dadd1c7bb..bb70b6216 100644 --- a/game/game/gamescript.cpp +++ b/game/game/gamescript.cpp @@ -339,9 +339,11 @@ void GameScript::initCommon() { auto* vtime = vm.find_symbol_by_name("VIEW_TIME_PER_CHAR"); viewTimePerChar = vtime != nullptr ? vtime->get_float() : 550.f; - ItKE_lockpick = vm.find_symbol_by_name("ItKE_lockpick"); if(viewTimePerChar<=0.f) viewTimePerChar = 550.f; + + ItKE_lockpick = vm.find_symbol_by_name("ItKE_lockpick"); + B_RefreshAtInsert = vm.find_symbol_by_name("B_RefreshAtInsert"); } else { itMi_Gold = vm.find_symbol_by_name("ItMiNugget"); if(itMi_Gold!=nullptr) { // FIXME @@ -1129,11 +1131,10 @@ void GameScript::invokePickLock(Npc& npc, int bSuccess, int bBrokenOpen) { } void GameScript::invokeRefreshAtInsert(Npc& npc) { - auto fn = vm.find_symbol_by_name("B_RefreshAtInsert"); - if(fn==nullptr) + if(B_RefreshAtInsert==nullptr) return; ScopeVar self(*vm.global_self(), npc.handlePtr()); - vm.call_function(fn); + vm.call_function(B_RefreshAtInsert); } CollideMask GameScript::canNpcCollideWithSpell(Npc& npc, Npc* shooter, int32_t spellId) { diff --git a/game/game/gamescript.h b/game/game/gamescript.h index 33c363faa..3350b3049 100644 --- a/game/game/gamescript.h +++ b/game/game/gamescript.h @@ -461,6 +461,7 @@ class GameScript final { QuestLog quests; zenkit::DaedalusSymbol* itMi_Gold = nullptr; zenkit::DaedalusSymbol* ItKE_lockpick = nullptr; + zenkit::DaedalusSymbol* B_RefreshAtInsert = nullptr; float tradeValMult = 0.3f; zenkit::DaedalusSymbol* spellFxInstanceNames = nullptr; zenkit::DaedalusSymbol* spellFxAniLetters = nullptr; From ad24481f276ac862ba5da35434741cc4be7bbc80 Mon Sep 17 00:00:00 2001 From: thokkat Date: Tue, 23 Jul 2024 18:13:21 +0200 Subject: [PATCH 7/9] equip best weapons when npc is created --- game/world/objects/npc.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/game/world/objects/npc.cpp b/game/world/objects/npc.cpp index 7291c5013..65d3e50f9 100644 --- a/game/world/objects/npc.cpp +++ b/game/world/objects/npc.cpp @@ -169,7 +169,9 @@ Npc::Npc(World &owner, size_t instance, std::string_view waypoint) owner.script().initializeInstanceNpc(hnpc, instance); hnpc->wp = std::string(waypoint); - // vanilla forces non-zero damage type + // vanilla behavior: equip best weapon and set non-zero damage type + if(!isMonster() && !isPlayer()) + invent.autoEquipWeapons(*this); if(hnpc->damage_type==0) hnpc->damage_type = 2; } From 597c82b6dcf8c32d5d74dbe245abfc6aa7ba97b0 Mon Sep 17 00:00:00 2001 From: Try Date: Wed, 24 Jul 2024 22:44:19 +0200 Subject: [PATCH 8/9] change search of bestItem t match vanilla --- game/game/inventory.cpp | 14 +++++++++----- game/world/objects/npc.cpp | 5 ++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/game/game/inventory.cpp b/game/game/inventory.cpp index 5ba80c22b..b41c9133d 100644 --- a/game/game/inventory.cpp +++ b/game/game/inventory.cpp @@ -906,6 +906,8 @@ void Inventory::invalidateCond(Item *&slot, Npc &owner) { } void Inventory::autoEquipWeapons(Npc &owner) { + if(owner.isMonster()) + return; auto m = bestMeleeWeapon(owner); auto r = bestRangeWeapon(owner); setSlot(melee ,m,owner,false); @@ -937,8 +939,9 @@ Item *Inventory::findByClass(size_t cls) { } Item* Inventory::bestItem(Npc &owner, ItmFlags f) { - Item* ret=nullptr; - int g =-1; + Item* ret = nullptr; + int32_t value = std::numeric_limits::min(); + int32_t damage = std::numeric_limits::min(); for(auto& i:items) { auto& itData = i->handle(); auto flag = ItmFlags(itData.main_flag); @@ -949,9 +952,10 @@ Item* Inventory::bestItem(Npc &owner, ItmFlags f) { if(itData.munition>0 && findByClass(size_t(itData.munition))==nullptr) continue; - if(itData.value>g){ - ret=i.get(); - g = itData.value; + if(std::make_tuple(itData.damage_total, itData.value)>std::make_tuple(damage, value)){ + ret = i.get(); + damage = itData.damage_total; + value = itData.value; } } return ret; diff --git a/game/world/objects/npc.cpp b/game/world/objects/npc.cpp index 65d3e50f9..bcad61ca8 100644 --- a/game/world/objects/npc.cpp +++ b/game/world/objects/npc.cpp @@ -170,7 +170,7 @@ Npc::Npc(World &owner, size_t instance, std::string_view waypoint) hnpc->wp = std::string(waypoint); // vanilla behavior: equip best weapon and set non-zero damage type - if(!isMonster() && !isPlayer()) + if(!isPlayer()) invent.autoEquipWeapons(*this); if(hnpc->damage_type==0) hnpc->damage_type = 2; @@ -476,8 +476,7 @@ bool Npc::resetPositionToTA() { if(!isDead) { attachToPoint(at); - if(!isMonster()) - invent.autoEquipWeapons(*this); + invent.autoEquipWeapons(*this); } if(g2) From d17a61031e2f1463b8d1e60c7804b0fd390e1db2 Mon Sep 17 00:00:00 2001 From: Try Date: Wed, 24 Jul 2024 22:45:01 +0200 Subject: [PATCH 9/9] set 'true guild' at npc-creation --- game/world/objects/npc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/game/world/objects/npc.cpp b/game/world/objects/npc.cpp index bcad61ca8..0cea2f6d5 100644 --- a/game/world/objects/npc.cpp +++ b/game/world/objects/npc.cpp @@ -174,6 +174,7 @@ Npc::Npc(World &owner, size_t instance, std::string_view waypoint) invent.autoEquipWeapons(*this); if(hnpc->damage_type==0) hnpc->damage_type = 2; + setTrueGuild(hnpc->guild); // https://worldofplayers.ru/threads/12446/post-878087 } Npc::~Npc(){