rpd:modding_custom_items
Differences
This shows you the differences between two versions of the page.
| rpd:modding_custom_items [2025/12/25 21:04] – list fix Mikhael | rpd:modding_custom_items [2025/12/25 21:25] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Creating Custom Items with JSON and Lua ====== | ||
| + | This guide shows how to create completely new items in Remixed Dungeon without any Java coding. You'll learn to use JSON configuration and Lua scripting to define new weapons, armor, potions, scrolls, and special items. | ||
| + | |||
| + | ===== Item Basics ===== | ||
| + | |||
| + | Every item in Remixed Dungeon is defined by: | ||
| + | * A JSON file that describes its properties | ||
| + | * Optional Lua scripts that define special behaviors | ||
| + | * An image file for its sprite | ||
| + | |||
| + | ===== Simple Item: Custom Weapon ===== | ||
| + | |||
| + | ==== Step 1: Create the Item JSON ==== | ||
| + | Create '' | ||
| + | |||
| + | <code json> | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Step 2: Create the Lua Script ==== | ||
| + | Create '' | ||
| + | |||
| + | <code lua> | ||
| + | local RPD = require " | ||
| + | local item = require " | ||
| + | |||
| + | return item.init{ | ||
| + | desc = function() | ||
| + | return { | ||
| + | image = 15, | ||
| + | imageFile | ||
| + | name = " | ||
| + | info = "This sword crackles with electrical energy that jumps to nearby enemies.", | ||
| + | stackable | ||
| + | upgradable | ||
| + | isFlies | ||
| + | defaultAction = " | ||
| + | } | ||
| + | end, | ||
| + | |||
| + | -- Called when the weapon hits an enemy | ||
| + | attackProc = function(self, | ||
| + | -- Find nearby enemies (within 2 tiles) using level mobs | ||
| + | local mobs = RPD.Dungeon.level(): | ||
| + | for i = 0, mobs: | ||
| + | local mob = mobs:get(i) | ||
| + | if mob ~= enemy and RPD.Dungeon.level(): | ||
| + | local lightningDamage = math.random(1, | ||
| + | mob: | ||
| + | RPD.glog(" | ||
| + | end | ||
| + | end | ||
| + | |||
| + | -- Show visual effect (using available effect) | ||
| + | RPD.topEffect(enemy: | ||
| + | return damage | ||
| + | end, | ||
| + | |||
| + | activate = function(self, | ||
| + | -- Called when item is equipped | ||
| + | RPD.glog(" | ||
| + | end, | ||
| + | |||
| + | deactivate = function(self, | ||
| + | -- Called when item is unequipped | ||
| + | RPD.glog(" | ||
| + | end | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Step 3: Add the Sprite ==== | ||
| + | Add your custom sword sprite to '' | ||
| + | |||
| + | ===== Custom Potion Example ===== | ||
| + | |||
| + | ==== JSON Definition ==== | ||
| + | Create '' | ||
| + | |||
| + | <code json> | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Lua Script ==== | ||
| + | Create '' | ||
| + | |||
| + | <code lua> | ||
| + | local RPD = require " | ||
| + | local item = require " | ||
| + | |||
| + | return item.init{ | ||
| + | desc = function() | ||
| + | return { | ||
| + | image = 22, | ||
| + | imageFile | ||
| + | name = " | ||
| + | info = " | ||
| + | stackable | ||
| + | upgradable | ||
| + | isFlies | ||
| + | defaultAction = " | ||
| + | } | ||
| + | end, | ||
| + | |||
| + | actions = function() | ||
| + | return {RPD.Actions.DRINK} | ||
| + | end, | ||
| + | |||
| + | execute = function(self, | ||
| + | if action == RPD.Actions.DRINK then | ||
| + | RPD.glog(" | ||
| + | |||
| + | -- Apply phase buff for 10 turns using RPD API | ||
| + | RPD.affectBuff(hero, | ||
| + | |||
| + | -- Show visual effect (using available effect) | ||
| + | RPD.topEffect(hero: | ||
| + | end | ||
| + | end | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Buff Definition ==== | ||
| + | Create the buff that enables phasing in '' | ||
| + | |||
| + | <code json> | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | And the Lua script '' | ||
| + | |||
| + | <code lua> | ||
| + | local RPD = require " | ||
| + | local buff = require " | ||
| + | |||
| + | return buff.init{ | ||
| + | desc = function() | ||
| + | return { | ||
| + | icon = 25, | ||
| + | name = " | ||
| + | info = "You can move through walls and enemies.\\nDuration: | ||
| + | } | ||
| + | end, | ||
| + | |||
| + | attach = function(self, | ||
| + | -- Called when buff is applied | ||
| + | self.target = target | ||
| + | RPD.glog(" | ||
| + | return true | ||
| + | end, | ||
| + | |||
| + | act = function(self) | ||
| + | -- Called each turn while active | ||
| + | -- Visual effect each step | ||
| + | RPD.topEffect(self.target: | ||
| + | -- Continue for another turn | ||
| + | return true | ||
| + | end, | ||
| + | |||
| + | detach = function(self) | ||
| + | -- Called when buff is removed | ||
| + | RPD.glog(" | ||
| + | end | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Custom Scroll Example ===== | ||
| + | |||
| + | ==== JSON Definition ==== | ||
| + | Create '' | ||
| + | |||
| + | <code json> | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Lua Script ==== | ||
| + | Create '' | ||
| + | |||
| + | <code lua> | ||
| + | local RPD = require " | ||
| + | local item = require " | ||
| + | |||
| + | return item.init{ | ||
| + | desc = function() | ||
| + | return { | ||
| + | image = 12, | ||
| + | imageFile | ||
| + | name = " | ||
| + | info = " | ||
| + | stackable | ||
| + | upgradable | ||
| + | isFlies | ||
| + | defaultAction = " | ||
| + | } | ||
| + | end, | ||
| + | |||
| + | actions = function() | ||
| + | return {RPD.Actions.READ} | ||
| + | end, | ||
| + | |||
| + | execute = function(self, | ||
| + | if action == RPD.Actions.READ then | ||
| + | RPD.glog(" | ||
| + | |||
| + | -- Apply telepathy buff for 20 turns | ||
| + | RPD.affectBuff(hero, | ||
| + | |||
| + | -- Show visual effect | ||
| + | RPD.topEffect(hero: | ||
| + | end | ||
| + | end | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Telepathy Buff ==== | ||
| + | Create '' | ||
| + | |||
| + | <code json> | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | And '' | ||
| + | |||
| + | <code lua> | ||
| + | local RPD = require " | ||
| + | local M = {} | ||
| + | |||
| + | function M.startTelepathy(buff, | ||
| + | RPD.glog(" | ||
| + | end | ||
| + | |||
| + | function M.endTelepathy(buff, | ||
| + | RPD.glog(" | ||
| + | end | ||
| + | |||
| + | function M.updateTelepathy(buff, | ||
| + | -- Reveal all creatures on the level every few turns | ||
| + | -- Note: This effect would depend on specific game mechanics - this is conceptual | ||
| + | local level = RPD.Dungeon.level() | ||
| + | local mobs = level: | ||
| + | for i = 0, mobs: | ||
| + | local mob = mobs:get(i) | ||
| + | -- Reveal 1 tile around mob (conceptual implementation) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | return M | ||
| + | </ | ||
| + | |||
| + | ===== Custom Armor Example ===== | ||
| + | |||
| + | ==== JSON Definition ==== | ||
| + | Create '' | ||
| + | |||
| + | <code json> | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Lua Script ==== | ||
| + | Create '' | ||
| + | |||
| + | <code lua> | ||
| + | local RPD = require " | ||
| + | local item = require " | ||
| + | |||
| + | return item.init{ | ||
| + | desc = function() | ||
| + | return { | ||
| + | image = 8, | ||
| + | imageFile | ||
| + | name = " | ||
| + | info = "This armor glows with a protective field that sometimes blocks attacks completely.", | ||
| + | stackable | ||
| + | upgradable | ||
| + | isFlies | ||
| + | defaultAction = " | ||
| + | } | ||
| + | end, | ||
| + | |||
| + | defenceProc = function(self, | ||
| + | -- 25% chance to completely block the attack | ||
| + | if math.random() < 0.25 then -- 25% chance | ||
| + | RPD.glog(" | ||
| + | RPD.topEffect(self: | ||
| + | return 0 -- Reduce damage to 0 | ||
| + | end | ||
| + | return damage -- Return original damage if not blocked | ||
| + | end, | ||
| + | |||
| + | activate = function(self, | ||
| + | RPD.glog(" | ||
| + | end | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Advanced Item Techniques ===== | ||
| + | |||
| + | ==== Item Sets ==== | ||
| + | Create items that work together: | ||
| + | |||
| + | <code json> | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Conditional Behavior ==== | ||
| + | Use Lua to create context-sensitive items: | ||
| + | |||
| + | <code lua> | ||
| + | local RPD = require " | ||
| + | local item = require " | ||
| + | |||
| + | return item.init{ | ||
| + | desc = function() | ||
| + | return { | ||
| + | image = 0, | ||
| + | imageFile | ||
| + | name = " | ||
| + | info = "An item with context-sensitive effects.", | ||
| + | stackable | ||
| + | upgradable | ||
| + | isFlies | ||
| + | defaultAction = " | ||
| + | } | ||
| + | end, | ||
| + | |||
| + | actions = function() | ||
| + | return {RPD.Actions.USE} | ||
| + | end, | ||
| + | |||
| + | execute = function(self, | ||
| + | if action == RPD.Actions.USE then | ||
| + | local level = RPD.Dungeon.level() | ||
| + | local heroHP = hero: | ||
| + | local heroMaxHP = hero: | ||
| + | |||
| + | if level: | ||
| + | -- Stronger effect on early levels | ||
| + | hero: | ||
| + | RPD.glog(" | ||
| + | elseif heroHP < heroMaxHP * 0.3 then | ||
| + | -- Emergency healing when low on health | ||
| + | hero: | ||
| + | RPD.glog(" | ||
| + | else | ||
| + | -- Normal effect | ||
| + | hero: | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Complex Interactions ==== | ||
| + | Create items that interact with the environment: | ||
| + | |||
| + | <code lua> | ||
| + | local RPD = require " | ||
| + | local item = require " | ||
| + | |||
| + | return item.init{ | ||
| + | desc = function() | ||
| + | return { | ||
| + | image = 0, | ||
| + | imageFile | ||
| + | name = " | ||
| + | info = "An item that interacts with the environment.", | ||
| + | stackable | ||
| + | upgradable | ||
| + | isFlies | ||
| + | defaultAction = " | ||
| + | } | ||
| + | end, | ||
| + | |||
| + | onThrow = function(self, | ||
| + | local level = RPD.Dungeon.level() | ||
| + | local terrainType = level: | ||
| + | |||
| + | if terrainType == RPD.Terrain.WATER then | ||
| + | -- Create a temporary bridge | ||
| + | level: | ||
| + | RPD.glog(" | ||
| + | elseif terrainType == RPD.Terrain.CHASM then | ||
| + | -- Fill the chasm | ||
| + | level: | ||
| + | RPD.glog(" | ||
| + | end | ||
| + | end | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Testing Your Items ===== | ||
| + | |||
| + | ==== Common Testing Steps ==== | ||
| + | * Enable your mod in-game | ||
| + | * Start a new game (not a saved game) to see new items | ||
| + | * Verify that sprites appear correctly | ||
| + | * Test all item functions and Lua scripts | ||
| + | * Check that item descriptions are properly localized | ||
| + | * Confirm that item balancing is appropriate | ||
| + | |||
| + | ==== Debugging Tips ==== | ||
| + | * Check the game log for Lua errors | ||
| + | * Verify file paths match the expected directory structure | ||
| + | * Ensure JSON syntax is valid | ||
| + | * Make sure image indices correspond to actual sprite locations | ||
| + | |||
| + | ===== Testing Your Items ===== | ||
| + | |||
| + | ==== Common Testing Steps ==== | ||
| + | * Enable your mod in-game | ||
| + | * Start a new game (not a saved game) to see new items | ||
| + | * Verify that sprites appear correctly | ||
| + | * Test all item functions and Lua scripts | ||
| + | * Check that item descriptions are properly localized | ||
| + | * Confirm that item balancing is appropriate | ||
| + | |||
| + | ==== Debugging Tips ==== | ||
| + | * Check the game log for Lua errors | ||
| + | * Verify file paths match the expected directory structure | ||
| + | * Ensure the '' | ||
| + | * Make sure image indices correspond to actual sprite locations | ||
| + | |||
| + | ===== Code References ===== | ||
| + | |||
| + | ==== Core Implementation ==== | ||
| + | - **Java Class**: '' | ||
| + | - **Lua Library**: '' | ||
| + | - **Lua Examples**: '' | ||
| + | |||
| + | ==== Key Methods in CustomItem.java ==== | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | |||
| + | ==== Key Methods in item.lua ==== | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | |||
| + | Creating custom items without Java is quite powerful in Remixed Dungeon. With Lua scripting, you can create complex interactions, | ||
rpd/modding_custom_items.txt · Last modified: by 127.0.0.1
