|
![]() |
#1 |
Prophet
Join Date: Dec 2009
Posts: 8,198
![]() |
Pyrel dev log
A few weeks back I described an approach to handling the object model for a roguelike in this thread. I wasn't able to let it rest there, so I started implementing that object model, discovered it worked well, and moved on to adding actual features. So far I'm still at it.
I am legendarily bad at finishing big projects like this, but in the interests of keeping my motivation fresh I'm going to log my progress here. The ultimate goal is to rewrite Angband in Python -- a task several people have attempted in the past without success. I'm hoping that if I'm unable to complete it, I'm at least able to get it to the point that other people can start pitching in to help out. That in mind, eventually I should probably set up a GitHub repo for this project -- only problem is, I'm using Mercurial on my local machine (since I'm far, far more comfortable with it than with Git), and until there's an actual point in having GitHub up, I'd rather not disturb my workflow any more than necessary. Some high-level stuff: I'm working in Python 2.7, and so far the only external dependency is wxPython, which is doing my windowing, event handling, and display logic. In the interests of making it as simple as possible for new devs to get started, I'm going to try to keep it to just that one external dependency if I can manage it. Standalone applications for OSX and Windows can be made with py2app and py2exe respectively; Linux has apt-get and the like. I plan to have strong separation between the engine and display layers, so theoretically it should be possible to write e.g. a curses display mode so you can play over SSH or whatever. However, I'll leave that to others to work with. I'm only bothering to implement the "ASCII" display layer because I need it to be able to debug the code. ![]() The way communication between the engine and display layers work is that the display layers provide commands to the engine, the engine updates state, then it hands its state to the display layer to show. Some events will result in prompts to the user; in that case, the engine provides the prompt type, the relevant container of things being prompted for (e.g. items in inventory, monsters in LOS), and a prompt message. The display layer has a free hand in how to display those prompts. For example, the standard Angband UI is keyboard-driven via series of menus, but the display code could decide to show clickable buttons, or even pop up a dialog box instead. All the engine cares about is that a selection is made (or the prompt is cancelled). Last edited by Derakon; April 15, 2012 at 06:04. |
![]() |
![]() |
![]() |
#2 |
Prophet
Join Date: Dec 2009
Posts: 8,198
![]() |
My most recent work has been on loading monster records. I started out with the monster.txt and monster_base.txt files from v4, wrote a simple parser to load those into objects, and then serialized those objects using JSON. Then I removed the Angband files, replaced them with the JSON versions, and wrote a new (much simpler) loader to use them.
There's a number of reasons to do this, but the big two are: * The old format doesn't cleanly allow for optional values * The old format is rather inscrutable There's a third reason which is mostly just a bit of a pleasant bonus: JSON's much easier for programs to load than the Angband file format (you don't need to write your own parser), so writing tools that can make it easier for variant maintainers to add/edit creatures isn't out of the question. It should be fairly easy to integrate into wizard mode, frankly. I wanted optional values because I want to be able to simplify how display is handled. The idea is that each display mode (e.g. ASCII, small tile, Shockbolt tile, etc.) can attach its own display metadata to each monster record, which the corresponding display module will read out when it needs to draw that monster. That should be more pleasant to work with than having a big mapping of monster index numbers to image files / offsets, which is what I believe is currently being done. Incidentally, index numbers are completely irrelevant so far. Anyway, here's an example monster record: Code:
{"index": 24, "name": "Small kobold", "display": {"ascii": {"color": [255, 255, 0]}}, "templates": ["kobold"], "hitpoints": 8, "speed": 110, "visionRange": 20, "alertness": 70, "evasion": 0, "absorption": 0, "nativeDepth": 1, "rarity": 1, "experienceValue": 5, "blows": [["HIT", "HURT", "1d5"]], "flags": ["DROP_60"], "description": "It is a squat and ugly humanoid figure with a canine face."}, Code:
{"name": "kobold", "display": {"ascii": {"symbol": "k"}}, "category": "Kobold", "type": "kobold", "flags": ["EVIL", "OPEN_DOOR", "BASH_DOOR", "IM_POIS"]}, |
![]() |
![]() |
![]() |
#3 | |
Rookie
Join Date: Mar 2012
Posts: 13
![]() |
Quote:
|
|
![]() |
![]() |
![]() |
#4 |
Prophet
Join Date: Dec 2009
Posts: 8,198
![]() |
Hm, I'd been using JSON because a) I got it working quickly, and b) it had built-in support in Python via the json module (whereas YAML would require a third-party library). The lack of comments is a problem though. Thanks for pointing it out. We could just have a dummy field in the record that acts as a comment, but that strikes me as rather hackish.
On the flipside, if we assume that most modifications to these records will, in the future, be generated more often by editor programs instead of by hand, it's likely that comments that aren't embedded into the records as data would get blown away regularly anyway (insert comment by hand, someone else makes a change via editor -- boom, comment is gone). In which case, comments-as-data would be preferred, and YAML loses its major convenience. Incidentally, this morning I switched over object.txt to JSON. Objects and monsters were the roadblocks to implementing a bunch of stuff, so from here I should be clear to start working on inventory, a combat framework, level generation, etc. My plan here is to just sketch out rough details -- for example, for combat I'll be omitting hit chance, critical hits, maybe even multiple blows/round; the main thing is to be able to hit things and have them die. The details can be backfilled later. EDIT: ha! Writing a conversion from the old object file format to JSON does not equate to being able to create objects from those records! However, that is now working too, at least what I've tested of it -- I can load the records, tell the game to give me a stack of iron spikes, and get a random 6d7 spikes; I can also create daggers, potions, etc. Flavors haven't been implemented yet, and of course none of the items actually do anything, but it's progress. The codebase is currently 1768 lines long, of which 284 lines are comments and 310 are whitespace. That's a bit light on comments, but not unacceptably so; I've just been being uncharacteristically terse while banging out big structures, for the most part. Last edited by Derakon; April 16, 2012 at 06:26. |
![]() |
![]() |
![]() |
#5 |
Prophet
Join Date: Dec 2009
Posts: 8,198
![]() |
Objects can have object templates now, like creature templates. I spent a bunch of time manually creating a bunch of object templates, only to belatedly realize that Angband already had object templates in object_base.txt. They just aren't called out explicitly like the monster templates are. Oh well; I would have had to make adaptations anyway to handle templated display parameters and a few other things (like crowns always having a base AC of 0).
Example object record: Code:
{"index": 238, "subtype": "Devotion", "templates": ["amulet"], "mods": [{"bonus": "1+M3", "flags": ["WIS"]}, {"bonus": "d6", "flags": ["CHR"]}, {"bonus": "1", "flags": ["LIGHT"]}], "flags": ["SUST_WIS", "SUST_CHR", "", "RES_DARK", "RES_LIGHT", "RES_FIRE", "HOLD_LIFE", "GOOD"], "allocations": [{"commonness": 10, "minDepth": 70, "maxDepth": 100}]}, Code:
{"type": "amulet", "template_name": "amulet", "display": {"ascii": {"color": "flavor", "symbol": "\""}}, "weight": 0.3} 1824 lines, 408 are comments, 208 are whitespace. I'm...having trouble reconciling this count with my earlier count -- how did I manage to turn ~100 lines of whitespace into comments? The command I'm using, for what it's worth, is Code:
find . -name "*py" | grep -v data | xargs cat | grep -P "^\s*#" | grep -cv "#" |
![]() |
![]() |
![]() |
#6 |
Prophet
Join Date: Dec 2009
Posts: 8,198
![]() |
I'm in the middle of making items equippable. The basic plan here is:
I'm also thinking about how to handle the melee/missile stat split. Specifically, there's some weirdness right now with how Rings of Finesse/Prowess apply to missile combat, and you can't currently get off-launcher/ammo slays to apply to missile combat. What I'm thinking is this:
* Off-weapon combat bonuses are more obvious about what they affect * We have a few minor new items that we could create (c.f. anti-acid cloak) The cost of course is that the complexity of the mods system is increased. Currently mods implicitly affect either the item or the wielder; we can keep that implicit system and avoid having to specify weapon slots for 99% of existing mods. But the code will still need to handle it. Thoughts? Especially if you can think of other interesting things you could do with items that affect other items when equipped. Last edited by Derakon; April 19, 2012 at 21:15. |
![]() |
![]() |
![]() |
#7 | ||
Angband Devteam member
|
Quote:
Quote:
So I'd encourage you to code the mods framework in a way that is completely flexible: - any mod can affect any entity: @ or any monster(s) or any slot or item, including carried (not worn) items (combine your anti-acid cloak with Sangband's protection blankets), including not-self (dagger that boosts archery but not melee) - any mod's effect on its affected entities can be on-wield or on-carry (so an artifact rod in the backpack can provide a slowing aura which only affects demons) Just my 2p. Please keep up the good work. d_m and noz and I were discussing pyrel over a curry the other night and are all very excited about it.
__________________
"3.4 is much better than 3.1, 3.2 or 3.3. It still is easier than 3.0.9, but it is more convenient to play without being ridiculously easy, so it is my new favorite of the versions." - Timo Pietila |
||
![]() |
![]() |
![]() |
#8 | ||||
Prophet
Join Date: Dec 2009
Posts: 8,198
![]() |
Quote:
* Every trait of an equippable except for base AC, damage dice, weight, flavor, and of course its item category is considered a "mod" to the item. Some mods are binary (i.e. flags), some are parameterized (i.e. "pvals"). In the item record they're called "flags" and "mods" respectively. Yes, this means that +to-finesse and +to-prowess would be considered item mods. * Flags are transparently mapped to +1 mods on load. The item has a list of mods that it has -- I'll probably create a new ItemMod class for this. * Like ItemMods can be merged (e.g. a weapon with multiple Slaying affixes). * ItemMods can be known or unknown. Later on I/we can deal with affixes; they'll probably be approached as aggregates of Mods, and if every Mod in the aggregation is learned then the affix is learned too. Quote:
![]() Quote:
I spoke with d_m some about this yesterday evening; making mods targetable does significantly increase complexity even if we disallow second-order effects. I'm not certain I have a good idea for how to implement it cleanly yet; it'll bear some consideration. Quote:
![]() |
||||
![]() |
![]() |
![]() |
#9 | |||||
Angband Devteam member
|
Quote:
Quote:
Quote:
Quote:
I was thinking some more about this, and thinking that this is closely tied to how you implement effects (which in turn determines spell handling). Because although most item mods affect only attributes of something (usually @'s stats or resists), some of them affect the environment (OF_IMPACT, OF_TELEPATHY etc.). So it's probably worth thinking about effects at least a bit before making irrevocable conclusions about item mods. Quote:
If it helps, I'd happily volunteer to do Pyrel's item gen, if you want to outsource when you're happy with the mod framework. And I'm not sure if he told you this, but d_m wrote his dungeon gen code in python before porting it to V!
__________________
"3.4 is much better than 3.1, 3.2 or 3.3. It still is easier than 3.0.9, but it is more convenient to play without being ridiculously easy, so it is my new favorite of the versions." - Timo Pietila |
|||||
![]() |
![]() |
![]() |
#10 | |||||||
Prophet
Join Date: Dec 2009
Posts: 8,198
![]() |
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
* Item mods, and applying those mods to the player / other items / etc. * Simple level gen -- just making a small room with some level-appropriate items and monsters * Simple combat -- letting the player take a whack at monsters, letting monsters take a whack at the player (assuming their incredibly stupid AI lets them try, anyway). This is actually almost done; I just need to affect hitpoints. * Usable items -- make a potion that can be used to print a message, something like that. * Savefiles (which will probably be just a serialization of all extant objects, possibly gzipped) * Character birth and death That leaves a whole ton of stuff that's really important to gameplay but won't affect the basic engine. Proper AI, v4's combat model, all of the item effects, spells (including monster spells), etc...and honestly the last two items could probably wait until later, if only because we may well be changing the item and monster records and that would mean rewriting the (de)serialization code each time. |
|||||||
![]() |
![]() |
![]() |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Display Modes | |
|
|
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
Angband 3.5-dev | Magnate | Vanilla | 70 | July 2, 2012 16:47 |
JBand progress log. | PaulBlay | Development | 38 | June 27, 2009 09:19 |
Hackers triumph over pricing.log beast-file ... | Magnate | Vanilla | 3 | April 22, 2009 23:00 |
Angband/65 development log | PaulBlay | Development | 0 | April 16, 2009 18:55 |
Export entire message log to text file | PaulBlay | Vanilla | 2 | February 28, 2009 19:24 |