Skip to content

fix: fishing#3981

Open
Paco161315 wants to merge 1 commit into
opentibiabr:mainfrom
Paco161315:update-fishing
Open

fix: fishing#3981
Paco161315 wants to merge 1 commit into
opentibiabr:mainfrom
Paco161315:update-fishing

Conversation

@Paco161315

@Paco161315 Paco161315 commented May 26, 2026

Copy link
Copy Markdown
Contributor

Fishing fixed just like real Tibia, including the mechanical fishing for the Isle of Evil Quest and the game achievements.
You can merge this PR already, but keep on mind you need to change every water tiles in the map as shown in the image.
Else, wait until Majesty upload the map update I sent to him and everything will work just fine.

Everything has been debuged and tested at https://tibiatales.com/

image

Fishing fixed just like real Tibia, including the mechanical fishing for the Isle of Evil Quest and the game achievements.

You can merge this PR already, but keep on mind you need to change every water tiles in the map as shown in the image.

Else, wait until Majesty upload the map update I sent to him and everything will work just fine.

Everything has been debuged and tested at https://tibiatales.com using canary/tfs crystal server distribution.
@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR refactors the fishing system by introducing water-type classifications (fishable, non-fishable, dirty), transformation mappings, and specialized handlers. Both regular and mechanical fishing actions now delegate dirty-water and desert outcomes to dedicated functions, perform target transformations with decay, and apply shimmer-based cooldown logic. Yalahar Sewers nail-based fishing and elemental loot rolls are integrated into mechanical fishing. Item definitions for water and dirt items are expanded with explicit attributes, duration, and decay targets.

Changes

Fishing Mechanics System

Layer / File(s) Summary
Water classification and item definitions
data-otservbr-global/scripts/actions/other/fishing.lua (lines 1–71), data-otservbr-global/scripts/actions/other/mechanical_fishing.lua (lines 1–190), data/items/items.xml (lines 13977–14023, 14058–14104, 30470–30497, 31964–31974, 42331–42349)
Water IDs extended and split into fishable/non-fishable/dirty categories; transformation mappings, shimmer storage constants, and loot-table variants introduced; water and dirt items redefined with explicit per-ID entries adding type, duration, and new decayTo sequences.
Dirty-water and desert fishing handlers
data-otservbr-global/scripts/actions/other/fishing.lua (lines 92–176)
handleDirtyWaterFishing and handleDesertFishing encapsulate specialized outcomes: magic effects, conditional skill-tries, worm consumption, item transformation/decay, shimmer cooldown checks via storage, random loot/achievement/text, and early returns controlling main action flow.
Mechanical fishing main flow with Yalahar integration
data-otservbr-global/scripts/actions/other/mechanical_fishing.lua (lines 199–351)
Yalahar Sewers routing when player holds nails performs success/failure chance, nail consumption, target transformation with optional decay, and mechanical fish reward; delegates dirty-water/desert targets to helpers; adds elemental loot roll with transformation and "rubbish" early return; introduces quest-conditional worm logic for specific target; updates Ice Hole handling with delayed refreezing and achievement-bearing loot selection.
Regular fishing main flow refinement
data-otservbr-global/scripts/actions/other/fishing.lua (lines 185–308)
Early decision logic routes dirty-water spent/non-fishable targets with magic effect returns; delegates dirty-water fishable and desert targets to handlers; worm-success branch removes previous 13988 special case, applies transformToNonFishable mappings with optional decay, and resumes standard reward and achievement progression for Ice Hole (7236) and transformed targets.

Sequence Diagram(s)

sequenceDiagram
    participant Player
    participant FishingAction
    participant WaterCheck
    participant DirtyWaterHandler
    participant DesertHandler
    participant TransformLogic
    participant LootSelection
    participant Storage as Storage (Shimmer Cooldown)
    
    Player->>FishingAction: Use fishing item on water target
    FishingAction->>WaterCheck: Check target water type
    alt Dirty Water Spent
        WaterCheck->>FishingAction: Return (magic effect)
    else Dirty Water Fishable
        WaterCheck->>DirtyWaterHandler: Delegate to handler
        DirtyWaterHandler->>Storage: Check shimmer cooldown
        DirtyWaterHandler->>TransformLogic: Transform if mapped
        DirtyWaterHandler->>LootSelection: Award loot/achievement
        DirtyWaterHandler->>FishingAction: Return (flow control)
    else Desert Water
        WaterCheck->>DesertHandler: Delegate to handler
        DesertHandler->>TransformLogic: Transform and decay target
        DesertHandler->>LootSelection: Award rare loot/progress
        DesertHandler->>FishingAction: Return (flow control)
    else Non-Fishable Water
        WaterCheck->>FishingAction: Return (magic effect)
    else Fishable Water
        WaterCheck->>FishingAction: Continue to fishing attempt
        FishingAction->>FishingAction: Check worm, compute success
        alt Success with Worm
            FishingAction->>TransformLogic: Apply transformToNonFishable[targetId]
            TransformLogic->>LootSelection: Award transformed target reward
            LootSelection->>Player: Deliver item, progress achievement
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 In waters deep where fishers cast their line,
New maps divide what's fishable from shine,
Dirty pools and deserts get their way,
Transform and shimmer cool—a better day!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'fix: fishing' is vague and generic. While it references fishing, it does not convey what specific aspect of fishing is being fixed or what the main change entails. Provide a more descriptive title that clarifies the specific fishing-related changes, such as 'refactor: improve fishing mechanics and water-type handling' or 'feat: add mechanical fishing for Isle of Evil quest'.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the fishing and mechanical fishing scripts to support new mechanics, including dirty water fishing (for Shimmer Swimmers), desert fishing, and updated water ID classifications. The review feedback highlights several critical issues in mechanical_fishing.lua where the logic was copied from fishing.lua but incorrectly references worms (item ID 3492 or "worm") instead of nails (NAIL_ID) for bait checks and consumption. Additionally, a logical bug was identified in the elemental loot loop where the chance check is misplaced and the function fails to return early upon successfully finding an item, which would cause the script to continue executing regular fishing logic.

Comment on lines +111 to +113
if player:getItemCount(3492) > 0 then
player:addSkillTries(SKILL_FISHING, 1, true)
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The mechanical fishing rod uses nails as bait instead of worms. Therefore, the skill tries check should verify if the player has nails (NAIL_ID) in their inventory, rather than worms (3492).

	if player:getItemCount(NAIL_ID) > 0 then
		player:addSkillTries(SKILL_FISHING, 1, true)
	end

Comment on lines +120 to +122
if useWorms and not player:removeItem("worm", 1) then
return true
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The mechanical fishing rod uses nails as bait instead of worms. This function should remove a nail (NAIL_ID) instead of a worm.

	if useWorms and not player:removeItem(NAIL_ID, 1) then
		return true
	end

Comment on lines +165 to +167
if player:getItemCount(3492) > 0 then
player:addSkillTries(SKILL_FISHING, 1, true)
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The mechanical fishing rod uses nails as bait instead of worms. The skill tries check should verify if the player has nails (NAIL_ID) in their inventory, rather than worms (3492).

	if player:getItemCount(NAIL_ID) > 0 then
		player:addSkillTries(SKILL_FISHING, 1, true)
	end

Comment on lines +174 to +176
if useWorms and not player:removeItem("worm", 1) then
return true
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The mechanical fishing rod uses nails as bait instead of worms. This function should remove a nail (NAIL_ID) instead of a worm.

	if useWorms and not player:removeItem(NAIL_ID, 1) then
		return true
	end

Comment on lines +262 to +272
local chance = math.random(10000)
for i = 1, #elementals.chances do
local randomItem = elementals.chances[i]
if chance >= randomItem.from and chance <= randomItem.to then
player:addItem(randomItem.itemId, 1)
end
if chance > 1115 then
player:say("There was just rubbish in it.", TALKTYPE_MONSTER_SAY)
return true
end
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are two issues here:

  1. The check chance > 1115 is placed inside the loop, which is inefficient and logically misplaced since it executes on the first iteration and returns immediately if true.
  2. If a player successfully fishes an elemental item (chance <= 1115), the loop adds the item but does not return true. This causes the script to continue executing the rest of the regular fishing logic, which is a bug.

Moving the chance > 1115 check outside the loop and returning true immediately upon finding an item resolves both issues.

		local chance = math.random(10000)
		if chance > 1115 then
			player:say("There was just rubbish in it.", TALKTYPE_MONSTER_SAY)
			return true
		end

		for i = 1, #elementals.chances do
			local randomItem = elementals.chances[i]
			if chance >= randomItem.from and chance <= randomItem.to then
				player:addItem(randomItem.itemId, 1)
				return true
			end
		end

Comment on lines +311 to +313
if player:getItemCount(3492) > 0 and table.contains(fishableWaterIds, targetId) then
player:addSkillTries(SKILL_FISHING, 1, true)
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The mechanical fishing rod uses nails as bait instead of worms. The skill tries check should verify if the player has nails (NAIL_ID) in their inventory, rather than worms (3492).

	if player:getItemCount(NAIL_ID) > 0 and table.contains(fishableWaterIds, targetId) then
		player:addSkillTries(SKILL_FISHING, 1, true)
	end

Comment on lines +316 to +318
if useWorms and not player:removeItem("worm", 1) then
return true
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The mechanical fishing rod uses nails as bait instead of worms. This should remove a nail (NAIL_ID) instead of a worm.

		if useWorms and not player:removeItem(NAIL_ID, 1) then
			return true
		end

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@data-otservbr-global/scripts/actions/other/fishing.lua`:
- Line 44: The table dirtyWaterSpent currently contains 12560 which triggers the
early-return when targetId is in dirtyWaterSpent and prevents the later targetId
== 12560 loot branch (lootVeryRare1/lootRare1/lootCommon1) from ever running;
fix by either removing 12560 from dirtyWaterSpent or by changing the
early-return condition that checks targetId so it excludes 12560 (i.e., allow
targetId == 12560 to fall through to the loot branch), and ensure the same
change is applied consistently where similar early-return checks occur around
the other targetId handling blocks.
- Line 1: The top-level waterIds table is missing IDs produced by
transformToNonFishable, causing later checks in the fishing flow (see function
transformToNonFishable and the main fishing handler that returns false instead
of taking the non-fishable-water path) to fail; update the waterIds list (and
the equivalent ID lists around the other waterId declarations noted) to include
4809–4814 and 21314 so transformed tiles are recognized as water/non-fishable
and the code follows the correct branch (ensure all occurrences of the initial
waterIds arrays at the other mentioned blocks are updated accordingly).

In `@data-otservbr-global/scripts/actions/other/mechanical_fishing.lua`:
- Line 1: The waterIds table is missing transformed water tile IDs so
transformed non-fishable states are rejected; update the waterIds list (used in
the mechanical fishing action) to include the IDs produced by
transformToNonFishable (4809–4814 and 21314) and likewise add those IDs to the
other similar waterId checks present in the file (the blocks referenced at lines
roughly 27-41 and 56-70) so transformed sewer/water tiles follow the
non-fishable handling path.
- Line 44: The dirtyWaterSpent table includes 12560 which causes the generic
return path to fire before the specific loot branch for targetId == 12560,
making the new dirty-water loot table unreachable; fix by removing 12560 from
dirtyWaterSpent (or by moving the targetId == 12560 conditional to execute
before the generic dirtyWaterSpent return) so the specific loot branch in
mechanical_fishing.lua runs — update references to dirtyWaterSpent and the
targetId == 12560 check accordingly (also adjust the same pattern where similar
returns appear later in the file).
- Around line 259-273: The elemental loot branch can fall through to the generic
fishing flow; after awarding the elemental item inside the loop (where
player:addItem(randomItem.itemId, 1) is called) immediately return true to stop
further processing so the worm/fish/achievement flow is not executed; also
ensure the rubbish check (chance > 1115) is not placed so it executes after
successful elemental resolution (i.e., move or evaluate that check outside/after
the elementals.chances loop) so it only triggers when no elemental was granted.

In `@data/items/items.xml`:
- Around line 31964-31970: Add the missing type="trashholder" attribute to the
shallow water item with id="13988": locate the <item id="13988" name="shallow
water"> block and add an attribute entry with key/type equal to "type" and value
"trashholder" so its definition matches other fishable/transitional
shallow-water tiles and keeps fishing behavior consistent with fishing.lua.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 013235ef-ac4a-441e-8bfb-2964a92e99bf

📥 Commits

Reviewing files that changed from the base of the PR and between dd1a95c and b82ad97.

📒 Files selected for processing (3)
  • data-otservbr-global/scripts/actions/other/fishing.lua
  • data-otservbr-global/scripts/actions/other/mechanical_fishing.lua
  • data/items/items.xml

@@ -1,4 +1,5 @@
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 13988, 13989, 12560, 21414 }
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 12560, 12561, 12562, 12563, 12558, 12559, 13988, 13989, 21414, 21312 }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the transformed water states to waterIds.

transformToNonFishable can turn tiles into 4809-4814 and 21314, but those IDs are not in the top-level waterIds gate. After the first successful catch, later uses hit return false at Line 181 instead of the non-fishable-water path.

Also applies to: 27-41, 56-70

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@data-otservbr-global/scripts/actions/other/fishing.lua` at line 1, The
top-level waterIds table is missing IDs produced by transformToNonFishable,
causing later checks in the fishing flow (see function transformToNonFishable
and the main fishing handler that returns false instead of taking the
non-fishable-water path) to fail; update the waterIds list (and the equivalent
ID lists around the other waterId declarations noted) to include 4809–4814 and
21314 so transformed tiles are recognized as water/non-fishable and the code
follows the correct branch (ensure all occurrences of the initial waterIds
arrays at the other mentioned blocks are updated accordingly).

}

local dirtyWaterFishable = { 12561, 12562, 12563 }
local dirtyWaterSpent = { 12558, 12559, 12560 }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

12560 is blocked before its loot branch can run.

Because dirtyWaterSpent includes 12560, the early return at Line 186 makes the later targetId == 12560 block unreachable. That leaves the new lootVeryRare1/lootRare1/lootCommon1 path dead.

Possible fix
-local dirtyWaterSpent = { 12558, 12559, 12560 }
+local dirtyWaterSpent = { 12558, 12559 }

Also applies to: 186-189, 232-245

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@data-otservbr-global/scripts/actions/other/fishing.lua` at line 44, The table
dirtyWaterSpent currently contains 12560 which triggers the early-return when
targetId is in dirtyWaterSpent and prevents the later targetId == 12560 loot
branch (lootVeryRare1/lootRare1/lootCommon1) from ever running; fix by either
removing 12560 from dirtyWaterSpent or by changing the early-return condition
that checks targetId so it excludes 12560 (i.e., allow targetId == 12560 to fall
through to the loot branch), and ensure the same change is applied consistently
where similar early-return checks occur around the other targetId handling
blocks.

@@ -1,10 +1,193 @@
local waterIds = { 622, 4597, 4598, 4599, 4600, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 13988, 13989 }
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 12560, 12561, 12562, 12563, 12558, 12559, 13988, 13989, 21414, 21312 }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the transformed water states to waterIds.

transformToNonFishable produces 4809-4814 and 21314, but the initial waterIds check still rejects them. That means transformed sewer/water tiles stop going through the non-fishable handling and just fall out of the action.

Also applies to: 27-41, 56-70

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@data-otservbr-global/scripts/actions/other/mechanical_fishing.lua` at line 1,
The waterIds table is missing transformed water tile IDs so transformed
non-fishable states are rejected; update the waterIds list (used in the
mechanical fishing action) to include the IDs produced by transformToNonFishable
(4809–4814 and 21314) and likewise add those IDs to the other similar waterId
checks present in the file (the blocks referenced at lines roughly 27-41 and
56-70) so transformed sewer/water tiles follow the non-fishable handling path.

}

local dirtyWaterFishable = { 12561, 12562, 12563 }
local dirtyWaterSpent = { 12558, 12559, 12560 }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

12560 is unreachable here too.

The generic dirtyWaterSpent return at Line 229 fires before the later targetId == 12560 loot branch, so the new dirty-water loot table can never execute in mechanical fishing either.

Possible fix
-local dirtyWaterSpent = { 12558, 12559, 12560 }
+local dirtyWaterSpent = { 12558, 12559 }

Also applies to: 229-232, 275-288

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@data-otservbr-global/scripts/actions/other/mechanical_fishing.lua` at line
44, The dirtyWaterSpent table includes 12560 which causes the generic return
path to fire before the specific loot branch for targetId == 12560, making the
new dirty-water loot table unreachable; fix by removing 12560 from
dirtyWaterSpent (or by moving the targetId == 12560 conditional to execute
before the generic dirtyWaterSpent return) so the specific loot branch in
mechanical_fishing.lua runs — update references to dirtyWaterSpent and the
targetId == 12560 check accordingly (also adjust the same pattern where similar
returns appear later in the file).

Comment on lines 259 to +273
toPosition:sendMagicEffect(CONST_ME_WATERSPLASH)
target:remove()
target:transform(target.itemid + 1)

local chance = math.random(10000)
for i = 1, #elementals.chances do
local randomItem = elementals.chances[i]
if chance >= randomItem.from and chance <= randomItem.to then
player:addItem(randomItem.itemId, 1)
end
if chance > 1115 then
player:say("There was just rubbish in it.", TALKTYPE_MONSTER_SAY)
return true
end
end
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Return after resolving the 9582 loot roll.

When the corpse roll awards an elemental item, this branch falls through into the generic fishing flow because only the rubbish case returns. That can still consume a worm and also grant the default fish/achievement afterward.

Possible fix
 		for i = 1, `#elementals.chances` do
 			local randomItem = elementals.chances[i]
 			if chance >= randomItem.from and chance <= randomItem.to then
 				player:addItem(randomItem.itemId, 1)
 			end
 			if chance > 1115 then
 				player:say("There was just rubbish in it.", TALKTYPE_MONSTER_SAY)
 				return true
 			end
 		end
+		return true
 	end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
toPosition:sendMagicEffect(CONST_ME_WATERSPLASH)
target:remove()
target:transform(target.itemid + 1)
local chance = math.random(10000)
for i = 1, #elementals.chances do
local randomItem = elementals.chances[i]
if chance >= randomItem.from and chance <= randomItem.to then
player:addItem(randomItem.itemId, 1)
end
if chance > 1115 then
player:say("There was just rubbish in it.", TALKTYPE_MONSTER_SAY)
return true
end
end
end
toPosition:sendMagicEffect(CONST_ME_WATERSPLASH)
target:transform(target.itemid + 1)
local chance = math.random(10000)
for i = 1, `#elementals.chances` do
local randomItem = elementals.chances[i]
if chance >= randomItem.from and chance <= randomItem.to then
player:addItem(randomItem.itemId, 1)
end
if chance > 1115 then
player:say("There was just rubbish in it.", TALKTYPE_MONSTER_SAY)
return true
end
end
return true
end
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@data-otservbr-global/scripts/actions/other/mechanical_fishing.lua` around
lines 259 - 273, The elemental loot branch can fall through to the generic
fishing flow; after awarding the elemental item inside the loop (where
player:addItem(randomItem.itemId, 1) is called) immediately return true to stop
further processing so the worm/fish/achievement flow is not executed; also
ensure the rubbish check (chance > 1115) is not placed so it executes after
successful elemental resolution (i.e., move or evaluate that check outside/after
the elementals.chances loop) so it only triggers when no elemental was granted.

Comment thread data/items/items.xml
Comment on lines +31964 to +31970
<item id="13988" name="shallow water">
<attribute key="primarytype" value="natural tiles" />
<attribute key="fluidsource" value="water" />
<attribute key="effect" value="bluebubble" />
<attribute key="duration" value="1200" />
<attribute key="decayTo" value="13989" />
</item>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add type="trashholder" to item 13988 to keep fishing behavior consistent.

13988 is defined as a fishable/transitional shallow-water tile (duration + decayTo) but misses type="trashholder", which is present on equivalent fishable shallow-water entries in this PR. This can create inconsistent fishing outcomes for this tile family (see downstream water target usage in data-canary/scripts/actions/tools/fishing.lua, Line 1).

Suggested patch
 	<item id="13988" name="shallow water">
 		<attribute key="primarytype" value="natural tiles" />
 		<attribute key="fluidsource" value="water" />
+		<attribute key="type" value="trashholder" />
 		<attribute key="effect" value="bluebubble" />
 		<attribute key="duration" value="1200" />
 		<attribute key="decayTo" value="13989" />
 	</item>	
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<item id="13988" name="shallow water">
<attribute key="primarytype" value="natural tiles" />
<attribute key="fluidsource" value="water" />
<attribute key="effect" value="bluebubble" />
<attribute key="duration" value="1200" />
<attribute key="decayTo" value="13989" />
</item>
<item id="13988" name="shallow water">
<attribute key="primarytype" value="natural tiles" />
<attribute key="fluidsource" value="water" />
<attribute key="type" value="trashholder" />
<attribute key="effect" value="bluebubble" />
<attribute key="duration" value="1200" />
<attribute key="decayTo" value="13989" />
</item>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@data/items/items.xml` around lines 31964 - 31970, Add the missing
type="trashholder" attribute to the shallow water item with id="13988": locate
the <item id="13988" name="shallow water"> block and add an attribute entry with
key/type equal to "type" and value "trashholder" so its definition matches other
fishable/transitional shallow-water tiles and keeps fishing behavior consistent
with fishing.lua.

@dudantas dudantas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for your contribution. I left the concrete fixes inline.

One behavior worth re-checking: the mechanical fishing rod now has worm-based fallback paths outside the Yalahar sewer branch. If this rod is meant to stay tied to the Isle of Evil mechanical-fish flow, those paths should either stay nail/mechanical-fish based or return early instead of behaving like regular fishing.

@@ -1,4 +1,5 @@
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 13988, 13989, 12560, 21414 }
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 12560, 12561, 12562, 12563, 12558, 12559, 13988, 13989, 21414, 21312 }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transformToNonFishable can turn fishable tiles into 4809-4814 and 21314, but this top-level gate rejects those ids before the action reaches nonFishableWaterIds. After the first successful catch on those source tiles, a later use returns false instead of taking the non-fishable-water path.

Suggested change
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 12560, 12561, 12562, 12563, 12558, 12559, 13988, 13989, 21414, 21312 }
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 4809, 4810, 4811, 4812, 4813, 4814, 629, 630, 631, 632, 633, 634, 7236, 9582, 12560, 12561, 12562, 12563, 12558, 12559, 13988, 13989, 21414, 21312, 21314 }

}

local dirtyWaterFishable = { 12561, 12562, 12563 }
local dirtyWaterSpent = { 12558, 12559, 12560 }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping 12560 in the generic spent-water list makes the dedicated targetId == 12560 loot branch below unreachable, because the action returns at the early spent-water check first.

Suggested change
local dirtyWaterSpent = { 12558, 12559, 12560 }
local dirtyWaterSpent = { 12558, 12559 }

@@ -1,10 +1,193 @@
local waterIds = { 622, 4597, 4598, 4599, 4600, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 13988, 13989 }
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 12560, 12561, 12562, 12563, 12558, 12559, 13988, 13989, 21414, 21312 }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transformToNonFishable can produce 4809-4814 and 21314, but this top-level waterIds check runs before nonFishableWaterIds. Transformed water tiles will be rejected by the action instead of showing the expected non-fishable-water effect.

Suggested change
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 629, 630, 631, 632, 633, 634, 7236, 9582, 12560, 12561, 12562, 12563, 12558, 12559, 13988, 13989, 21414, 21312 }
local waterIds = { 622, 4597, 4598, 4599, 4600, 12561, 12563, 4601, 4602, 4609, 4610, 4611, 4612, 4613, 4614, 4809, 4810, 4811, 4812, 4813, 4814, 629, 630, 631, 632, 633, 634, 7236, 9582, 12560, 12561, 12562, 12563, 12558, 12559, 13988, 13989, 21414, 21312, 21314 }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you test it? Works fine for me as it is.

}

local dirtyWaterFishable = { 12561, 12562, 12563 }
local dirtyWaterSpent = { 12558, 12559, 12560 }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

12560 is handled by the generic spent-water return before it can reach the dedicated targetId == 12560 loot branch, so that branch cannot run.

Suggested change
local dirtyWaterSpent = { 12558, 12559, 12560 }
local dirtyWaterSpent = { 12558, 12559 }

Comment on lines +262 to +273
local chance = math.random(10000)
for i = 1, #elementals.chances do
local randomItem = elementals.chances[i]
if chance >= randomItem.from and chance <= randomItem.to then
player:addItem(randomItem.itemId, 1)
end
if chance > 1115 then
player:say("There was just rubbish in it.", TALKTYPE_MONSTER_SAY)
return true
end
end
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the elemental roll awards an item, the function continues into the generic fishing flow because only the rubbish path returns. That can consume normal bait and grant the default fishing reward after the corpse roll has already been resolved.

Suggested change
local chance = math.random(10000)
for i = 1, #elementals.chances do
local randomItem = elementals.chances[i]
if chance >= randomItem.from and chance <= randomItem.to then
player:addItem(randomItem.itemId, 1)
end
if chance > 1115 then
player:say("There was just rubbish in it.", TALKTYPE_MONSTER_SAY)
return true
end
end
end
local chance = math.random(10000)
if chance > 1115 then
player:say("There was just rubbish in it.", TALKTYPE_MONSTER_SAY)
return true
end
for i = 1, #elementals.chances do
local randomItem = elementals.chances[i]
if chance >= randomItem.from and chance <= randomItem.to then
player:addItem(randomItem.itemId, 1)
return true
end
end
return true
end

Comment thread data/items/items.xml
Comment on lines +31964 to +31970
<item id="13988" name="shallow water">
<attribute key="primarytype" value="natural tiles" />
<attribute key="fluidsource" value="water" />
<attribute key="effect" value="bluebubble" />
<attribute key="duration" value="1200" />
<attribute key="decayTo" value="13989" />
</item>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

13988 is now a transitional shallow-water tile with duration and decayTo, but it is missing the trashholder type that the equivalent shallow-water entries in this diff have. Adding it keeps this tile family consistent.

Suggested change
<item id="13988" name="shallow water">
<attribute key="primarytype" value="natural tiles" />
<attribute key="fluidsource" value="water" />
<attribute key="effect" value="bluebubble" />
<attribute key="duration" value="1200" />
<attribute key="decayTo" value="13989" />
</item>
<item id="13988" name="shallow water">
<attribute key="primarytype" value="natural tiles" />
<attribute key="fluidsource" value="water" />
<attribute key="type" value="trashholder" />
<attribute key="effect" value="bluebubble" />
<attribute key="duration" value="1200" />
<attribute key="decayTo" value="13989" />
</item>

@Paco161315

Paco161315 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Hi, thanks for your contribution. I left the concrete fixes inline.

One behavior worth re-checking: the mechanical fishing rod now has worm-based fallback paths outside the Yalahar sewer branch. If this rod is meant to stay tied to the Isle of Evil mechanical-fish flow, those paths should either stay nail/mechanical-fish based or return early instead of behaving like regular fishing.

I think mechanical fishing rod shouldn't be added yet. In real tibia you can't use it for regular fishing, only for the mechanical fish.
However I gave extra-usage here because in canary, it's an unonbtainable item because quest isn't coded yet.
I think you should merge as it is, the position for mechanical fish is checked by zone not by IDs that's why is overriden by the worms and all that. ...
But, if it doesn't feels right to you I can just delete it. Repo already has a wrong mechanical fishing rod script that can't be obtained in game anyway.

@vllsystems

Copy link
Copy Markdown
Contributor

Hi Paco. Could you please provide me with a list of all the IDs that need to be changed? It would really help me if it could be in the format below:

id 4609 -> 4597
id X -> id Y

I will create a Lua script to perform this function. Thanks!

@Paco161315

Copy link
Copy Markdown
Contributor Author

Hi Paco. Could you please provide me with a list of all the IDs that need to be changed? It would really help me if it could be in the format below:

id 4609 -> 4597 id X -> id Y

I will create a Lua script to perform this function. Thanks!

Hello, sure!
This is the ones you need to transfrom in your map:
local nonFishableWaterIds = {
4609, 4610, 4611, 4612, 4613, 4614,
4809, 4810, 4811, 4812, 4813, 4814, 21314,
}
local dirtyWaterSpent = { 12558, 12559, 12560 }

Into these:
local fishableWaterIds = {
4597, 4598, 4599, 4600, 4601, 4602,
629, 630, 631, 632, 633, 634, 21312,
}
local dirtyWaterFishable = { 12561, 12562, 12563 }

Hope it helps! :D Good Luck doing that, please don't fell into desperation, it may take you a while to update all tiles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants