-
-
Notifications
You must be signed in to change notification settings - Fork 852
proposal: extra attack ability #3983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -53153,6 +53153,15 @@ hands of its owner. Granted by TibiaRoyal.com"/> | |||||
| </item> | ||||||
| <item id="28478" article="an" name="umbral master bow TEST"> | ||||||
| <attribute key="primarytype" value="distance weapons"/> | ||||||
| <attribute key="slotType" value="two-handed" /> | ||||||
| <attribute key="ammotype" value="arrow" /> | ||||||
| <attribute key="hitchance" value="5" /> | ||||||
| <attribute key="range" value="7" /> | ||||||
| <attribute key="attack" value="6" /> | ||||||
| <attribute key="weight" value="4000" /> | ||||||
| <attribute key="extraattack" value="3" /> <!-- x3 rows as extra attacks --> | ||||||
| <attribute key="extraattackdelay" value="500" /> <!-- 5ms of delay between attacks --> | ||||||
| <attribute key="extraattackchance" value="500" /> <!-- 5% chance to trigger auto attacks --> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarify the percentage calculation basis in the comment. The comment states "5% chance" for a value of 500, which suggests the system uses a base of 10,000 for percentage calculations (500/10000 = 5%). While this is a common pattern in OT servers, the comment doesn't clarify this encoding, which could confuse developers trying to configure different chance values. 📝 Proposed fix- <attribute key="extraattackchance" value="500" /> <!-- 5% chance to trigger auto attacks -->
+ <attribute key="extraattackchance" value="500" /> <!-- 5% chance to trigger auto attacks (500/10000) -->📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| <attribute key="script" value="moveevent;weapon"> | ||||||
| <attribute key="weaponType" value="distance"/> | ||||||
| <attribute key="slot" value="hand"/> | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1574,6 +1574,157 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| g_game().sendSingleSoundEffect(target->getPosition(), params.soundCastEffect, caster); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (int32_t i = 1; i <= extraAttacks; ++i) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check failure on line 1578 in src/creatures/combat/combat.cpp
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto eventId = g_dispatcher().scheduleEvent( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| i * extraDelay, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check failure on line 1580 in src/creatures/combat/combat.cpp
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [caster, target, combatType, combatOrigin, distEffect, weaponRange]() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check failure on line 1581 in src/creatures/combat/combat.cpp
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1578
to
+1581
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Build failure: Missing variable declarations and setup block. The code uses Based on the feature requirements and past review suggestions, this block should:
🔧 Proposed fix: Add missing setup block before the loop+ // Extra attack scheduling - skip if this is already an extra attack to prevent recursion
+ if (damage.isExtraAttack) {
+ return;
+ }
+
+ const auto &player = caster ? caster->getPlayer() : nullptr;
+ if (!player) {
+ return;
+ }
+
+ const auto &weapon = player->getWeapon(true);
+ if (!weapon || weapon->getExtraAttack() <= 0) {
+ return;
+ }
+
+ const int32_t extraAttacks = std::clamp<int32_t>(weapon->getExtraAttack(), 0, 10);
+ const int32_t extraDelay = std::max<int32_t>(0, weapon->getExtraAttackDelay());
+ const int32_t extraAttackChance = std::clamp<int32_t>(weapon->getExtraAttackChance(), 0, 10000);
+
+ if (extraAttackChance > 0 && uniform_random(1, 10000) > extraAttackChance) {
+ return;
+ }
+
+ const CombatType_t combatType = params.combatType;
+ const CombatOrigin combatOrigin = params.origin;
+ const uint16_t distEffect = params.distanceEffect;
+ const uint8_t weaponRange = weapon->getShootRange() > 0 ? weapon->getShootRange() : Item::items[weapon->getID()].shootRange;
+
for (int32_t i = 1; i <= extraAttacks; ++i) {
auto eventId = g_dispatcher().scheduleEvent(
i * extraDelay,
- [caster, target, combatType, combatOrigin, distEffect, weaponRange]() {
+ [caster, target, combatType, combatOrigin, distEffect, weaponRange]() {🧰 Tools🪛 GitHub Check: Build - Linux / Compile (linux-debug)[failure] 1581-1581: [failure] 1581-1581: [failure] 1581-1581: [failure] 1581-1581: [failure] 1580-1580: [failure] 1578-1578: 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!caster || !target) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (caster->isRemoved() || !caster->isAlive()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (target->isRemoved() || !target->isAlive()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const auto &player = caster->getPlayer(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!player) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const Position currentCasterPos = caster->getPosition(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const Position targetPos = target->getPosition(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentCasterPos.z != targetPos.z) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const uint32_t currentDist = std::max<uint32_t>( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Position::getDistanceX(currentCasterPos, targetPos), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Position::getDistanceY(currentCasterPos, targetPos) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto currentTool = player->getWeapon(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!currentTool) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const auto ¤tBow = player->getWeapon(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentTool->getWeaponType() == WEAPON_AMMO && !currentBow) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uint8_t currentWeaponRange = weaponRange; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check failure on line 1621 in src/creatures/combat/combat.cpp
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentBow && currentBow->getShootRange() > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentWeaponRange = currentBow->getShootRange(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (currentBow) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentWeaponRange = Item::items[currentBow->getID()].shootRange; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentDist > currentWeaponRange) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!g_game().isSightClear(currentCasterPos, targetPos, true)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::shared_ptr<Item> currentAmmo = nullptr; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WeaponShared_ptr weaponToUse = nullptr; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::shared_ptr<Item> ammoToRemove = nullptr; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentTool->getWeaponType() == WEAPON_AMMO) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentAmmo = currentTool; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ammoToRemove = currentTool; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentAmmo->getItemCount() < 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentBow) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| weaponToUse = g_weapons().getWeapon(currentBow); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!weaponToUse) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| weaponToUse = g_weapons().getWeapon(currentTool); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| weaponToUse = g_weapons().getWeapon(currentTool); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!weaponToUse) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::shared_ptr<Item> damageTool = currentAmmo ? currentAmmo : currentTool; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!damageTool) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (damageTool->getID() == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uint16_t shootEffect = distEffect; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check failure on line 1674 in src/creatures/combat/combat.cpp
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (shootEffect == CONST_ANI_NONE) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ItemType &toolType = Item::items[damageTool->getID()]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shootEffect = toolType.shootType; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (shootEffect != CONST_ANI_NONE) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| g_game().addDistanceEffect(currentCasterPos, targetPos, shootEffect); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CombatParams extraParams; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraParams.combatType = combatType; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check failure on line 1685 in src/creatures/combat/combat.cpp
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraParams.origin = combatOrigin; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check failure on line 1686 in src/creatures/combat/combat.cpp
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraParams.blockedByArmor = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraParams.blockedByShield = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraParams.aggressive = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int32_t weaponDamage = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| weaponDamage = std::abs(weaponToUse->getWeaponDamage(player, target, damageTool, true)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (...) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1692
to
+1697
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Silent exception swallowing hides potential bugs. The catch block silently returns without logging. If 🛠️ Proposed fix: Add error logging try {
weaponDamage = std::abs(weaponToUse->getWeaponDamage(player, target, damageTool, true));
} catch (...) {
-
+ g_logger().error("[Combat::extraAttack] Exception in getWeaponDamage for player {}", player->getName());
return;
}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CombatDamage extraDamage; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraDamage.primary.type = combatType; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraDamage.primary.value = normal_random(0, static_cast<int32_t>(weaponDamage)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraDamage.secondary.type = weaponToUse->getElementType(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraDamage.secondary.value = weaponToUse->getElementDamage(player, target, damageTool); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraDamage.origin = combatOrigin; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extraDamage.isExtraAttack = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Combat::doCombatHealth(caster, target, currentCasterPos, extraDamage, extraParams); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (ammoToRemove && g_configManager().getBoolean(REMOVE_WEAPON_AMMO)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (ammoToRemove->getID() != 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const uint16_t ammoCount = ammoToRemove->getItemCount(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (ammoCount > 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto transformed = g_game().transformItem(ammoToRemove, ammoToRemove->getID(), ammoCount - 1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (void)transformed; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (ammoCount == 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto removed = g_game().internalRemoveItem(ammoToRemove); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (void)removed; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| player->updateSupplyTracker(ammoToRemove); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1709
to
+1722
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Supply tracker called after item may be invalid.
Consider calling the tracker before modification, or capturing the item ID/count beforehand. 🔧 Proposed fix: Track supply before modifying ammo if (ammoToRemove && g_configManager().getBoolean(REMOVE_WEAPON_AMMO)) {
-
if (ammoToRemove->getID() != 0) {
+ // Track supply before modifying the item
+ player->updateSupplyTracker(ammoToRemove);
+
const uint16_t ammoCount = ammoToRemove->getItemCount();
if (ammoCount > 1) {
auto transformed = g_game().transformItem(ammoToRemove, ammoToRemove->getID(), ammoCount - 1);
(void)transformed;
} else if (ammoCount == 1) {
auto removed = g_game().internalRemoveItem(ammoToRemove);
(void)removed;
}
- player->updateSupplyTracker(ammoToRemove);
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Combat::extraAttack" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (void)eventId; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void Combat::doCombatHealth(const std::shared_ptr<Creature> &caster, const Position &position, const std::unique_ptr<AreaCombat> &area, CombatDamage &damage, const CombatParams ¶ms) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,7 @@ void ItemParse::initParse(const std::string &stringValue, pugi::xml_node attribu | |
| ItemParse::parseDefense(stringValue, valueAttribute, itemType); | ||
| ItemParse::parseExtraDefense(stringValue, valueAttribute, itemType); | ||
| ItemParse::parseAttack(stringValue, valueAttribute, itemType); | ||
| ItemParse::parseExtraAttack(stringValue, valueAttribute, itemType); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function Please add the implementation of void ItemParse::parseExtraAttack(const std::string &stringValue, pugi::xml_attribute valueAttribute, ItemType &itemType) {
if (stringValue == "extraattack") {
itemType.extraAttack = pugi::cast<int32_t>(valueAttribute.value());
} else if (stringValue == "extraattackdelay") {
itemType.extraAttackDelay = pugi::cast<int32_t>(valueAttribute.value());
} else if (stringValue == "extraattackchance") {
itemType.extraAttackChance = pugi::cast<int32_t>(valueAttribute.value());
}
}Additionally, make sure to map these attributes in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
💡 Proposed fix+void ItemParse::parseExtraAttack(const std::string &stringValue, pugi::xml_attribute valueAttribute, ItemType &itemType) {
+ if (stringValue == "extraattack") {
+ itemType.extraAttack = std::max<int32_t>(0, pugi::cast<int32_t>(valueAttribute.value()));
+ } else if (stringValue == "extraattackdelay") {
+ itemType.extraAttackDelay = std::max<int32_t>(0, pugi::cast<int32_t>(valueAttribute.value()));
+ } else if (stringValue == "extraattackchance") {
+ itemType.extraAttackChance = std::clamp<int32_t>(pugi::cast<int32_t>(valueAttribute.value()), 0, 10000);
+ }
+}🤖 Prompt for AI Agents |
||
| ItemParse::parseMantra(stringValue, valueAttribute, itemType); | ||
| ItemParse::parseRotateTo(stringValue, valueAttribute, itemType); | ||
| ItemParse::parseWrapContainer(stringValue, valueAttribute, itemType); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the comment typo for delay timing.
The comment states "5ms of delay" but the value is 500. In OT servers, timing values are typically in milliseconds, so this should be "500ms of delay between attacks" not "5ms".
📝 Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents