Skip to content

Commit d4b86c7

Browse files
Add item selection helper class for Lua scripts and test spell
- Created itemSelector.lua library for initiating item selection from backpack in Lua - Added LuaWndBagListener Java class for all platforms to handle callbacks - Added luaCallByGlobalId method to GameLoop for calling Lua callbacks by ID - Updated RemixedDungeon classes on all platforms to expose luaCallByGlobalId - Added CurseItem test spell to demonstrate item selection functionality - Added SpellBook with CurseItem spell to initHeroesDebug.json - Updated modding documentation with item selection and SpellBook configuration info - Added example NPC script demonstrating item selection usage
1 parent ca5a41f commit d4b86c7

File tree

11 files changed

+323
-3
lines changed

11 files changed

+323
-3
lines changed

RemixedDungeon/src/android/java/com/nyrds/platform/game/RemixedDungeon.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,10 @@ public static void resetScene() {
229229
GameLoop.resetScene();
230230
}
231231

232+
// Method for handling Lua callbacks by ID for item selection
233+
@LuaInterface
234+
public static void luaCallByGlobalId(int callbackId, Object... params) {
235+
com.nyrds.pixeldungeon.game.GameLoop.callByGlobalId(callbackId, params);
236+
}
237+
232238
}

RemixedDungeon/src/main/assets/hero/initHeroesDebug.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@
1111
"kind": "Torch",
1212
"level": 1,
1313
"quantity": 100,
14-
"identetifyLevel": 2
14+
"identifyLevel": 2
1515
},
1616
{
1717
"kind": "ScrollHolder",
1818
"level": 1,
19-
"identetifyLevel": 2
19+
"identifyLevel": 2
2020
},
2121
{
2222
"kind": "test/TestItem",
2323
"level": 1,
24-
"identetifyLevel": 2
24+
"identifyLevel": 2
2525
},
2626
{
2727
"kind": "WandOfIcebolt",
@@ -31,6 +31,11 @@
3131
{
3232
"kind": "Gold",
3333
"quantity": 10
34+
},
35+
{
36+
"kind": "SpellBook",
37+
"identified": true,
38+
"spell": "CurseItem"
3439
}
3540
],
3641
"str": 20,

RemixedDungeon/src/main/assets/scripts/lib/commonClasses.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ local Objects = {
105105
WndOptionsLua = "com.nyrds.pixeldungeon.windows.WndOptionsLua",
106106
WndShopOptions = "com.nyrds.pixeldungeon.windows.WndShopOptions",
107107
WndChooseWay = "com.watabou.pixeldungeon.windows.WndChooseWay",
108+
WndBag = "com.watabou.pixeldungeon.windows.WndBag",
108109
Image = "com.watabou.noosa.Image",
109110
Banner = "com.watabou.pixeldungeon.ui.Banner"
110111
},
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
--
2+
-- User: mike
3+
-- Date: 18.09.2025
4+
-- Time: 12:00
5+
-- This file is part of Remixed Pixel Dungeon.
6+
--
7+
-- Item selector helper for initiating backpack item selection from Lua scripts
8+
--
9+
10+
local RPD = require "scripts/lib/commonClasses"
11+
12+
local itemSelector = {}
13+
14+
-- Function to select an item from the backpack
15+
-- Parameters:
16+
-- callback: function to call when an item is selected (receives item and selector as parameters)
17+
-- mode: selection mode (optional, defaults to ALL)
18+
-- title: window title (optional)
19+
-- selector: character that is selecting the item (optional, defaults to hero)
20+
function itemSelector.selectItem(callback, mode, title, selector)
21+
-- Validate callback
22+
if type(callback) ~= "function" then
23+
RPD.glog("Error: callback must be a function")
24+
return
25+
end
26+
27+
-- Set defaults
28+
mode = mode or RPD.BackpackMode.ALL
29+
title = title or "Select an item"
30+
selector = selector or RPD.Dungeon.hero
31+
32+
-- Store the callback in a way that can be accessed from Java
33+
-- We'll use a global table to store callbacks
34+
if not _G.ItemSelectionCallbacks then
35+
_G.ItemSelectionCallbacks = {}
36+
end
37+
38+
-- Generate a unique ID for this callback
39+
local callbackId = #_G.ItemSelectionCallbacks + 1
40+
_G.ItemSelectionCallbacks[callbackId] = callback
41+
42+
-- Create a listener using a custom Java class that can call back to Lua
43+
local listener = luajava.newInstance("com.nyrds.pixeldungeon.windows.LuaWndBagListener", callbackId)
44+
45+
-- Show the backpack window
46+
local wndBag = luajava.newInstance("com.watabou.pixeldungeon.windows.WndBag",
47+
selector:getBelongings(),
48+
nil, -- bag (nil for default)
49+
listener,
50+
mode,
51+
title)
52+
RPD.GameScene:show(wndBag)
53+
end
54+
55+
-- Convenience functions for common selection modes
56+
function itemSelector.selectAnyItem(callback, title, selector)
57+
itemSelector.selectItem(callback, RPD.BackpackMode.ALL, title, selector)
58+
end
59+
60+
function itemSelector.selectUnidentifiedItem(callback, title, selector)
61+
itemSelector.selectItem(callback, RPD.BackpackMode.UNIDENTIFED, title, selector)
62+
end
63+
64+
function itemSelector.selectUpgradeableItem(callback, title, selector)
65+
itemSelector.selectItem(callback, RPD.BackpackMode.UPGRADEABLE, title, selector)
66+
end
67+
68+
function itemSelector.selectWeapon(callback, title, selector)
69+
itemSelector.selectItem(callback, RPD.BackpackMode.WEAPON, title, selector)
70+
end
71+
72+
function itemSelector.selectArmor(callback, title, selector)
73+
itemSelector.selectItem(callback, RPD.BackpackMode.ARMOR, title, selector)
74+
end
75+
76+
function itemSelector.selectWand(callback, title, selector)
77+
itemSelector.selectItem(callback, RPD.BackpackMode.WAND, title, selector)
78+
end
79+
80+
function itemSelector.selectSeed(callback, title, selector)
81+
itemSelector.selectItem(callback, RPD.BackpackMode.SEED, title, selector)
82+
end
83+
84+
function itemSelector.selectArrow(callback, title, selector)
85+
itemSelector.selectItem(callback, RPD.BackpackMode.ARROWS, title, selector)
86+
end
87+
88+
return itemSelector
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--
2+
-- Example script demonstrating how to use the itemSelector library
3+
-- This script creates an NPC that allows the player to select an item from their backpack
4+
--
5+
6+
local RPD = require "scripts/lib/commonClasses"
7+
local itemSelector = require "scripts/lib/itemSelector"
8+
local mob = require "scripts/lib/mob"
9+
10+
return mob.init({
11+
spawn = function(self, level)
12+
-- Set the NPC's AI state
13+
RPD.setAi(self, "NpcDefault")
14+
end,
15+
16+
interact = function(self, chr)
17+
-- Show a message to the player
18+
RPD.glog("Hello! I can help you select an item from your backpack.")
19+
20+
-- Show item selection window
21+
itemSelector.selectItem(function(item, selector)
22+
if item then
23+
RPD.glog("You selected: " .. item:name())
24+
-- Do something with the selected item
25+
-- For example, identify it
26+
if not item:isIdentified() then
27+
item:identify()
28+
RPD.glog("I've identified your " .. item:name() .. "!")
29+
else
30+
RPD.glog("That item is already identified.")
31+
end
32+
else
33+
RPD.glog("You didn't select any item.")
34+
end
35+
end, RPD.BackpackMode.ALL, "Select an item for me to examine")
36+
end
37+
})
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--
2+
-- Test spell to demonstrate item selection functionality
3+
-- This spell allows the player to select an item from their backpack and curse it
4+
--
5+
6+
local RPD = require "scripts/lib/commonClasses"
7+
local itemSelector = require "scripts/lib/itemSelector"
8+
local spell = require "scripts/lib/spell"
9+
10+
return spell.init{
11+
desc = function()
12+
return {
13+
image = 0, -- Using a generic spell icon
14+
imageFile = "spellsIcons/necromancy.png",
15+
name = "Curse Item",
16+
info = "Select an item from your backpack to curse it.",
17+
magicAffinity = "Necromancy",
18+
targetingType = "self",
19+
level = 1,
20+
castTime = 0,
21+
spellCost = 3,
22+
cooldown = 5
23+
}
24+
end,
25+
26+
cast = function(self, spell, chr)
27+
-- Show item selection window
28+
itemSelector.selectItem(function(item, selector)
29+
if item then
30+
-- Check if the item is already cursed
31+
if item:isCursed() then
32+
RPD.glog("That item is already cursed!")
33+
else
34+
-- Curse the selected item
35+
item:curse()
36+
RPD.glog("You have cursed your " .. item:name() .. "!")
37+
38+
-- Apply a visual effect
39+
RPD.zapEffect(chr:getPos(), chr:getPos(), "ShadowParticle")
40+
41+
-- Play a sound effect
42+
RPD.playSound("snd_cursed.mp3")
43+
end
44+
else
45+
RPD.glog("You decided not to curse anything.")
46+
end
47+
end, RPD.BackpackMode.ALL, "Select an item to curse")
48+
49+
return true
50+
end
51+
}

RemixedDungeon/src/main/java/com/nyrds/pixeldungeon/game/GameLoop.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import android.view.KeyEvent;
44

55
import com.nyrds.LuaInterface;
6+
import com.nyrds.lua.LuaEngine;
67
import com.nyrds.platform.ConcurrencyProvider;
78
import com.nyrds.platform.EventCollector;
89
import com.nyrds.platform.PlatformAtomicInteger;
@@ -27,6 +28,8 @@
2728
import com.watabou.utils.SystemTime;
2829

2930
import org.luaj.vm2.LuaError;
31+
import org.luaj.vm2.LuaValue;
32+
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
3033

3134
import java.util.Queue;
3235
import java.util.concurrent.Future;
@@ -285,4 +288,28 @@ private void switchScene(Scene requestedScene) {
285288
public static void setDifficulty(int difficulty) {
286289
GameLoop.difficulty = difficulty;
287290
}
291+
292+
@LuaInterface
293+
public static void callByGlobalId(int callbackId, Object... params) {
294+
// Get the global callbacks table from Lua
295+
LuaValue callbacks = LuaEngine.call("getfenv").get("ItemSelectionCallbacks");
296+
297+
// If the callbacks table exists and has the callback ID
298+
if (callbacks != null && callbacks.istable()) {
299+
LuaValue callback = callbacks.get(callbackId);
300+
if (callback != null && callback.isfunction()) {
301+
// Convert Java objects to Lua values
302+
LuaValue[] luaParams = new LuaValue[params.length];
303+
for (int i = 0; i < params.length; i++) {
304+
luaParams[i] = CoerceJavaToLua.coerce(params[i]);
305+
}
306+
307+
// Call the Lua callback function
308+
callback.invoke(luaParams);
309+
310+
// Remove the callback from the table to prevent memory leaks
311+
callbacks.set(callbackId, LuaValue.NIL);
312+
}
313+
}
314+
}
288315
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.nyrds.pixeldungeon.windows;
2+
3+
import com.watabou.pixeldungeon.windows.WndBag;
4+
import com.watabou.pixeldungeon.items.Item;
5+
import com.watabou.pixeldungeon.actors.Char;
6+
import com.nyrds.platform.game.RemixedDungeon;
7+
8+
public class LuaWndBagListener implements WndBag.Listener {
9+
private int callbackId;
10+
11+
public LuaWndBagListener(int callbackId) {
12+
this.callbackId = callbackId;
13+
}
14+
15+
@Override
16+
public void onSelect(Item item, Char selector) {
17+
// Call the Lua callback function with the item and selector
18+
RemixedDungeon.luaCallByGlobalId(callbackId, item, selector);
19+
}
20+
}

RemixedDungeonDesktop/src/libgdx/java/com/nyrds/platform/game/RemixedDungeon.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ public static void resetScene() {
5252
GameLoop.resetScene();
5353
}
5454

55+
// Method for handling Lua callbacks by ID for item selection
56+
@LuaInterface
57+
public static void luaCallByGlobalId(int callbackId, Object... params) {
58+
GameLoop.callByGlobalId(callbackId, params);
59+
}
60+
5561

5662
public static void switchNoFade(Class<? extends PixelScene> c) {
5763
PixelScene.noFade = true;

RemixedDungeonHtml/src/html/java/com/nyrds/platform/game/RemixedDungeon.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ public static void resetScene() {
5252
GameLoop.resetScene();
5353
}
5454

55+
// Method for handling Lua callbacks by ID for item selection
56+
@LuaInterface
57+
public static void luaCallByGlobalId(int callbackId, Object... params) {
58+
GameLoop.callByGlobalId(callbackId, params);
59+
}
60+
5561

5662
public static void switchNoFade(Class<? extends PixelScene> c) {
5763
PixelScene.noFade = true;

0 commit comments

Comments
 (0)