Add support to multiple towns#8535
Conversation
6f9cc02 to
53a3509
Compare
Have you explored the idea of extracting level setup to configuration first (basically making levels data-driven)? I think that would be a better general solution to this than making it a mod via Lua, personally. |
|
Don't we already have |
For one, the concept of which level is a "town" vs a "dungeon" should be softcoded so that I can define 5 town levels and 3 dungeon levels if I wanted to without needing to touch the source. That's more what I mean on this one: the capability of defining arbitrary level types per level shouldn't need to be a mod but a core configuration function, which then doesn't require Lua at all. Of course, that might come with the complication of also being able to define towners and quests in configuration (which I also believe would make 100% sense). |
|
Okay, so ignoring your specific gripe with doing anything via Lua, the crux of your argument is that the overarching structure of the game is not moddable enough. Coming back to your specific gripe with Lua, it should be noted that you do not need to touch the source code in order to write a Lua script. So unless you have a specific design in mind for something concrete, like a TSV file layout that you think is definitively better than a Lua API for some reason, then this PR should help to serve your needs as far as I can tell. |
Yeah, that's exactly what I am doing, I can reference tiles, dun files and sectors in this new town. It completely supports that case. |
|
@julealgon to be more specific, that's the lua script I was using for the "Tiny Town", I think it's data-driven enough (what did you have in mind?): -- Tiny Town MVP
-- A small subset of Tristram using only sector1 (the fountain area).
-- Talk to Farnham to travel between Tristram and Tiny Town.
local towns = require("devilutionx.towns")
local towners = require("devilutionx.towners")
local log = require("devilutionx.log")
-- Use only sector1 (bottom-right quadrant) which contains the fountain.
-- Sector1 is placed at (46,46) covering tiles 46-92 in both axes.
towns.register("tiny_town", {
name = "Tiny Town",
saveId = 1,
sectors = {
{ path = "levels\\towndata\\sector1s.dun", x = 46, y = 46 },
},
entries = {
{ type = "main", x = 62, y = 71 },
{ type = "townswitch", x = 62, y = 71 },
},
bounds = { min = { x = 48, y = 48 }, max = { x = 84, y = 84 } },
towners = {
{ name = "griswold", x = 56, y = 66 },
{ name = "pepin", x = 66, y = 66 },
{ name = "ogden", x = 56, y = 74 },
{ name = "cain", x = 66, y = 74 },
{ name = "farnham", x = 58, y = 70 },
{ name = "adria", x = 64, y = 70 },
{ name = "gillian", x = 60, y = 66 },
{ name = "wirt", x = 60, y = 76 },
},
})
-- Add a dialog option to Farnham's talk menu to travel between towns.
-- The label changes depending on which town the player is currently in.
towners.addDialogOption("farnham",
function()
local cur = towns.current()
if cur == "tristram" then
return "Go to Tiny Town"
elseif cur == "tiny_town" then
return "Go to Tristram"
end
return ""
end,
function()
local cur = towns.current()
if cur == "tristram" then
towns.travel("tiny_town")
else
towns.travel("tristram")
end
end
)
log.info("Tiny Town loaded — talk to Farnham to travel") |
I don't know where you got the impression that this is related to "a gripe with Lua". I have zero gripes with it even though I'm not familiar with it myself.
I don't think I've made that argument specifically? I just said that the type of a level should be a simple data field, is all.
Again, I don't know where you got the impression that I implied one would need to touch the source code to mod this via Lua? Instead of making this many assumptions, you can just ask if you have questions about my suggestion.
I don't have any specific concrete suggestions. I was just commenting to encourage a more data-driven view of the specific problem, as I think Lua would be better suited for custom behaviors and extension points compared to what seems more fit for a data field (the type of a level).
I don't have any needs myself here. Again, you are making so many assumptions from a single sentence. I do not intent to use this to make my own mods or anything. I'm commenting purely from an architecture perspective. |
|
@julealgon I'm not going to break down your response to show you how you said those very things that you think I am making assumptions about. I guess, let's just assume you said nothing at all. This PR is already data-driven. If you think this PR needs to change in some way, then why don't you actually review the code and comment on that instead of trying to start off-topic discussions about architectural approaches that you haven't even thought about yourself? |
|
I don't want to extend the discussion about assumptions but I am genuinely curious about how the architecture can be better @julealgon. It took me a few iterations to come up with this approach, AI wasn't very helpful in this case. C++ is not my main language so it's very likely I didn't choose the best approach, I tried to come up with a lua script that is simple enough to encourage mods but flexible enough for my needs. I took Diablo 2 as inspiration where you must talk to an NPC to travel to another city. I could potentially remove the logic to make the PR cleaner but eventually I would need this feature so I decided to keep it. For me, the current structure is simple enough (I really don't know how to make it better) I am open to suggestions: towns.register("tiny_town", {
name = "Tiny Town",
saveId = 1,
sectors = {
{ path = "levels\\towndata\\sector1s.dun", x = 46, y = 46 },
},
entries = {
{ type = "main", x = 62, y = 71 },
{ type = "townswitch", x = 62, y = 71 },
},
bounds = { min = { x = 48, y = 48 }, max = { x = 84, y = 84 } },
towners = {
{ name = "griswold", x = 56, y = 66 },
{ name = "pepin", x = 66, y = 66 },
{ name = "ogden", x = 56, y = 74 },
{ name = "cain", x = 66, y = 74 },
{ name = "farnham", x = 58, y = 70 },
{ name = "adria", x = 64, y = 70 },
{ name = "gillian", x = 60, y = 66 },
{ name = "wirt", x = 60, y = 76 },
},
}) |
Man... you guys are the most hostile open source group I've ever interacted with, by far. I'll leave it up to you and stop providing any suggestions moving forward. |
Every issue/pull request where you appear turns into a wall of text, how is that helpful? |
|
I think mods should be mostly Lua driven then config driven. It allows for more complex mod logic then what simple config does, we could see much more interesting mods that way. Making it largely config driven also means more complex config setups to support which can actually bloat things way more then if it was done though Lua bindings. We don't need bespoke formats for everything. Only data tables and a manifest should be bespoke. @julealgon maybe it would be better to start a discusion about architectural philosophy if it's something you feel should be taken in a different direction. I realize we don't have a clear document for this, and maybe it would be something that would be good to make and have a debate about. |
0132237 to
8c9d300
Compare
I really want to create a new mod where the player can explore a new town. Don't get me wrong I love Tristam but would be nice to expand Diablo 1.
This PR adds support to multiple towns extracting the hardcoded town initialization in a way that is possible to define it in lua.
I created a simple mod where the user can talk to Farnham and go to the "Tiny Town" a subset of Tristam with all NPCs grouped around the fountain.
The mod is not in this PR it was used for tests only (you can find in one of my comments).
Edit: I believe with those changes would be possible to enable the arena as a new town with the arena dungeons.
multi_city.mp4