Thursday, 20 September 2012

Various proposed changes

I have some ideas for a few relatively far-reaching changes.  The big question is whether they are radical enough that they warrant a fork (of V or v4) or whether inclusion in v4 is reasonable.  To begin with I want to motivate the problems I'm trying to solve.

1) The length of the second half of the dungeon is too long, and gameplay tends to be monotonous.  This is only countered by the enjoyment of being in the deep dungeon assuming you are unfamiliar with it.  (This is the standard operating assumption of Angband, it is not true for me.)

2) Unique monsters are too strong.  They can rarely be handled at depth.

2a) There is not enough incentive from dealing with uniques, particularly late game uniques. 

2b) On the other hand there is incentive to wait to kill uniques until deeper in the dungeon for better drops.  This is the standard gameplay strategy.

3) Monsters come in groups that are too large (and tedious to deal with).  Group monsters are also too ubiquitous in the dungeon.

3a) Later game escorts are absurd.  20 pit fiends or greater balrogs are not an interesting challenge.  They are an impossible challenge.

3b) Z monsters are too powerful.  Always awake + breathe for way too much damage make these groups uninteresting and not fun.

4) Monster summoning is too powerful.  If two Great Wyrms of Balance are too much for one player to fight at once, one should not be able to create another.

5) Teleport other, destruction and banishment are too strong.   4 and 5 are interrelated.  You can't weaken the players counters to summons without weakening summons.

So here's what I would like to do -mapped to the above issues.

1) Reduce the dungeon to 50 levels.  This may involve removing some unique monsters, but that's not entirely necessary.

1a) The mapping would proceed something like this.
     Current Angband                          Smaller version
    1-10                                               1-10
    11-50                                             11-30
    51-100                                           31-50

1b) This step is probably the final step I would take, and the most likely to require a personal variant, especially if it involves removing monsters.

1c) Sauron lives at 50, killing Sauron causes Morgoth to spawn on the level.

2) Lower the strength of uniques.  This would mainly be accomplished by reducing hit points.  An increase in the incentive to kill uniques is discussed in 4).

2a) Make uniques guaranteed to appear on their rated level.  A player that wants to systematically kill all uniques will be able to.

3) The main goal is to provide more customization for how large groups are.  This is likely to be the least controversial, so it's probably what I'll start with.  (It's also the hardest for me to implement)

3a) Allow specification of what monsters appear with given monsters.  The clearest example would be to have the three trolls Tom, Bert and Bill appear with each other.  But also Gothmog appears with Lungorthin and a couple other Balrogs.  (If Lungorthin is dead, Gothmog is that much easier to handle)

3b) Allow different magnitudes of how many friends should appear.  Novices can come in smaller packs, but orcs can still come in larger ones.  Size should be dependent both on danger and how annoying it is to deal with a large pack.  'Z's are annoying, 'o's are not.  The argument is that large packs of 'Z's are bad for game enjoyment but large packs of 'o's are ok.

3c) No spawned group monsters.

4) Major changes to summons and player abilities are called for.  First for summons.

4a) Monsters that tend to 'summon' other monsters instead appear with one as an escort.  Enchantresses are accompanied by a dragon, Mystics come with spiders.  Rangers get some dogs.

4b) Most summons get replaced with 'calls.'  A call brings a monster somewhere else on the level to the summoner to assist in the battle.  A called monster must not have LoS to the summoner (or maybe the player because that's easier).

 - I've considered having a called monster gain HP back at the expense of the caller if it was injured, but I'm not sure whether this is a good idea or a pointless one.

- Calls should be a preferred attack if no other monsters are in LoS of a call-capable monster.  The goal would be to first kill the escort, then the summoner.

- Failed calls should not be repeated.

4c) If no monsters are available to be called (all dragons on the level are dead) nothing is summoned.  The call goes unheeded.

4d) Monsters can still summon (read: create) a monster but at some penalty to themselves.  I was thinking a HP penalty related to the level of the summoned monster.  Monsters will not use this summon attack if their HP are below some threshold.  Very few monsters have this ability (Qs and some Uniques).

4e) Summon Uniques is unchanged.  Only Sauron and Morgoth have this spell.  The uniques come at no penalty.  Other non-unique summons arrive with the same penalty for Sauron and Morgoth.  If all uniques are dead, Summon_Uniques brings nothing.

5) The major nerfs of summons are accompanied by major reductions to the ways for the player to dismiss monsters it doesn't want to fight.

5a) Monsters get a save against teleport other.  The save maxes at 50% for Morgoth.

5b) Destruction does not remove monsters from the level.  Monster can save and be teleported elsewhere on the level, or just outside the destruction zone.  Destruction zones are smaller (radius 10 instead of 15).  Destruction will not work on level 50 until Sauron and Morgoth are dead.

- Destruction spell is only available to mages and priests.

5c) Banishment disappears entirely.  Mass banishment works as a mass-teleport other of everything within N squares without a saving through.  N must be larger than max-sight (uniques excluded)

Some more miscellaneous changes.

Monsters can forget about the player and fall asleep.  (I'd like to implement wandering monsters, but that might be beyond my ability.)  Spawned monsters can appear asleep, or maybe eliminate spawned monsters altogether?

Increase the divisor of many breaths.  Time, Gravity and Plasma top this list, but I would also consider Nether, Shards, Chaos and Inertia.  A pack of 6 time hounds that only breathe for 30 damage are still something you avoid.

I have a far goal of implementing permanent levels, but I know I don't have the skills for this right now. 

Allow probabilistic drops.  Sauron gets a 2% chance of dropping the One Ring.  Gothmog has a 50% chance of dropping his whip, etc.  This also includes normal drops like spellcasters dropping books, molds dropping mushrooms and so on.

Wednesday, 11 April 2012

Thoughts on the current state of 3.4 gameplay

The following are my thoughts on the current state of 3.4 gameplay. Overall the game is good. There have been many quiet improvements in this version and there aren't really any showstoppers. I think a release candidate at the end of May is certainly possible. I'll outline the rest of the post as follows:

  1. What gameplay improvements have been made
  2. Changes that still need to be made
  3. Current bad things about gameplay and where we might want to direct attention in the future.

1. The current improvements/changes in 3.4.

If you haven't had a chance to play 3.4 lately, the game is significantly different from 3.3, and mostly in a better way. Shockbolt's tiles are amazing. While I prefer ASCII, and still do, they may help in bringing new people into the game. The addition of new pits is another big improvement to gameplay. Summoning changes have made fights with summoners less tedious and more interesting (summon_hounds went from the least interesting summon to the most interesting). And lastly, the game is significantly more stingy with artifacts and good weapons. This successfully prevents the "runaway" effect that existed in 3.3 and previous where I personally found that below a certain dungeon level my character improved faster than I could descend. Currently I've found that many items and weapons that I would never use previously have a useful niche. And artifact production is way down, which means that other egos have longer lives. Lastly, in the endgame I'm spendting more time hunting for equipment than for consumables which is much more interesting (in fact I have excess consumables to be used for uniques). It's not perfect yet, but it's certainly better.

There are other changes, but these seem to be the most salient.

2. Changes that still need to be made.

From my gameplay, there is only really one change that absolutely needs to be made for 3.4 to be released, and this is:

A) remove_curse is currently useless.
Right now there are no longer any cursed jewelery, and no cursed weapons or armor that you can find (stats collection picked up 0 cursed non-artifacts). The only cursed items are the cursed artifacts, and the ones you create yourself with the curse scrolls. These are all heavy_curses which remove_curse does nothing for. The removal of light_curse on objects is probably a positive step until curses are made more interesting, but it puts us currently in an odd position because we have some useless items and spells in the game.

The simple solution is to remove all remove_curse scrolls (even *remove_curse*). We also need to get rid of the remove_curse priest spell as well. Enchant scrolls should have the curse breaking property in their text. the priest spell of dispel_curse could stay since it does have a niche use, however it's redundant because of the priest enchant spells, so it should probably be chucked also. Then we can look at curses in more detail when they've been overhauled (4.0?).

The other changes are not necessary but probably should be fixed.

B) MAX_RANGE option for large tiles/small screens.

Playing where I could only see about half of MAX_RANGE on my monitor is actually completely playable, provided you keep a sharp eye on the monster list. However, it's not ideal, and may not even be practical for phone screens (don't know if they support subwindows, probably not). The solution is to make a birth option to lower the MAX_RANGE, probably to around 10 or so. We need a couple lines of code to cap archery and throwing at MAX_RANGE, but all the devices and spells should be fine on their own. Unfortunately, this is a change that I'm not capable of coding myself. Changing MAX_RANGE requires some esoteric additions to some hardcoded values in cave.c that I don't understand. I also have no idea how this would work with an option, since these values are checked at game init. If someone wants to pick this up for 3.4, great. Otherwise it will probably need to be punted.

C) Early dungeon emptiness

I've talked about this a bit on irc, and d_m tepidly agrees that the early dungeon is too empty. In fact, it seems like it is suffering from TLJ (too little junk). Later in the game, where dragon pits and vaults spew crap all over the floor, TMJ exists, but that won't be fixed for 3.4 and I'll mention it a bit in the next section. My solution is to increase the floor drops, at least to 3.0.6 levels. This is an increase to 12 items per level instead of 9. I'd actually prefer it go up further to 15 or so, but there's some pushback to even raising it back to 12. Increasing floor drops mainly increases early game availability of items, since later in the game, you get more items from monster drops than the floor. If you oppose this, please play the first 10 levels or so of the current angband (preferably ironman style) and see how the dungeon feels to you. It's possible that we can wait until the RC is out and get player feedback, but player feedback can be notoriously skewed depending on who actually is playing it.

That's it for gameplay issues that are problematic. There's one must-fix, one easy-to-fix that we just need to reach a consensus on, and one fix that is hard, but won't prevent a release if no one wants to take it on.

3. Current problem areas

There are several longstanding annoyances with gameplay (or at least with how I play it), that we should be thinking of solutions for, preferably by poaching ideas from v4 and variants. In fact many of these problems have been focused on in v4, so we might be able to nip some of the mature ones for future vanilla development.

A) Traps are boring. CunningGabe's changes in v4 will certainly help. Although having traps being semi- or non-relevant is ok for quality of gameplay. Just because traps are boring doesn't mean I'm not enjoying the game.

B) TMJ from pits/vaults. I hate sorting through the tremendous amount of junk from pits and vaults. It's ok when you come across the lone item on the floor that's junk, but when you have 100 junk items to ID or test-wield (or even test-pickup) it gets tedious. Some solutions like auto-id on sight, or a LoS ID spell should be on the table. This is not a commonly test-played area of the game, since most test-playing doesn't simulate player-dungeon interaction at high levels. However, this is probably the least satisfying part of gameplay for me.

C) Dungeon interest wanes/game drags in the 2nd half. The game proceeds with much improved pacing between dlevels 1 and 50. Getting to dlevel 50 is a fun goal, and more enjoyable for me than killing Morgoth. There are lots of reasons for this, and no real good solutions, but it should be something to think about. This is a long-standing problem and has actually been improved relative to 3.3 with things like Ainu pits and lower artifact drop rates.

C2) There are too many uniques. Unique drops are still weak compared to the effort it takes to kill them. Uniques without a drop have no reason to be killed, besides personal pride (and the vague goal of preventing Morgoth from summoning them). This hasn't been touched in v4, except for the redistribution of monsters, which has made uniques even more out of whack with their level distributions. I don't have anything resembling a solution to this issue.

D) Caverns are still a problem. They are too dangerous, too common, and have no rewards. I may push for 3.4 to have a decrease in monster density in caverns and a increase in drop-quality (as exists in labyrinths). On the other hand, labyrinths, which I thought were fun because of the good drops are now so rare to be irrelevant.

E) I talked about curses earlier. There is potential for something interesting here, but there's a lot of inertia and a lot of resistance (and a lot of difficult coding). One improvement was recently pushed to v4 where curse scrolls either blast a weapon or make it sticky. I think this should have immediate consideration for inclusion in 3.4. However, I'm not a good judge here. Because of gameplay style, in all the games I've played, I've never once cursed a weapon or armor with a scroll...

F) Dungeon levels are too predictable. Nomad's extra rooms would be great if we could include them in 3.4. I doubt there's much opposition to this. Everyone seems to like new rooms. In the future, adjustable pit sizes, and multiple pits per level could be helpful.

Saturday, 5 November 2011

Core-UI split: user input

A lump of slate
Here are my current thoughts on how to move forward with the Core-UI split.  At the moment there aren't really layers - it's more like a lump of slate that's starting to crack in two but isn't quite there yet.  The biggest single issue that I see right now in moving towards that goal is user interaction, and that's what this post covers.  This post was written while I was working out the issues, so I hope it makes sense to other people!

At the moment, there is a game command layer which is the intermediary between the UI and the core.  Roughly speaking, the core runs in a loop on a queue of commands.  If the queue is empty, it passes control to the UI and asks it to get a command.  The UI then gets some input, works out what game command that corresponds to, and pushes that command onto the game stack.  When the queue isn't empty, the game just runs through it, executing every command it finds until it runs out of commands to process.

This picture is complicated a bit by the presence of macros.  At the moment, macros are implemented at the UI level as a queue of keypresses.  So there are two queues operating at once - one command queue and one keypress queue (actually, there are three queues - the terminal code keeps another keypress queue).  To illustrate, say we have a macro P:

P = p1bt

And let's start with an empty command queue.  This is the flow inside the game:

Core: Queue is empty -> ask UI for keypress
UI: Player presses P -> put p1b*t into the keypress queue
UI: Process 'p' -> UI command calls prayer book selection code
UI: '1' selects book inscribed @p1 -> select prayer menu
UI: 'b' selects prayer b -> put "pray book:1 spell:b" into the command queue, return control to core
Core: Checks over command to make sure it's got all the data
Core: Calls associated command function - do_cmd_pray(1, b)
Core: 'b' requires a target so it prompts for one
UI: 't' popped from keypress queue, ends prompt
Core: execute prayer

The problem here is that the game core isn't given enough information up-front to execute the prayer without user input.  So the question is: what do we have to do to get the command layer running without user input?

First off, there is a problem at the moment in that the game command queue handling code sometimes fills in the paramaters given to the functions that execute those commands.  So, for example, when the game core comes to execute an 'open door' command, but no direction is provided, it will check to see how many doors can be opened around @.  If more than 1, it will prompt.  This is bad layering, and the way to fix it is to make the game command code refuse to run incomplete commands, and put that logic in a level a bit higher up.

The bigger problem, though, is the one in the prayer example.  Different commands require different input, but not based on their command type (aim, read, pray, etc) but on what the effect the object they are used with will invoke.  It doesn't matter whether you're making a fireball from a want, spell or rod - they all need a direction.  Enchant Weapon requires an item regardless of whether you're reading from a scroll or a spellbook.

To make this work, we evidently need close tie-in between the command and effects code.  Effects basically need to be specified in such a way that their input requirements and implementation are coded up separately. How to do this in C is quite beyond me at present - while many effects only need a target, some portion want to select an object, which requires a prompt, a filter function and an error message if the effect can't be invoked because there is no appropriate object.  All this needs to be specified in some declarative way so that the UI, game core, and effect code can all access and use it.

Any help appreciated!

After sorting out this (very sticky) point, I think we're pretty close to a proper UI-Core input split.  One useful way of enforcing the constant that the core layer doesn't ask for input would be to add assert()ions in inkey() when a "in the core now" flag is set, and that would help find the remaining instances pretty quickly.  Of course, there's still some output issues - I'm sure some of the core code writes to the screen directly - but they could hopefully be sorted out pretty quickly.


The ambition, after making all game commands run without user input, is to rid ourselves of the second key queue inside the UI layer, and we can do this by rewriting macros to be a string of game commands sent to the core in one bunch.  So instead of:


Your macro would look like:

cast "Enchant Weapon" item:floor:1
cast "Enchant Weapon" item:floor:1
cast "Enchant Weapon" item:floor:1
cast "Enchant Weapon" item:floor:1

Monday, 19 September 2011

So what exactly is an "ego" item anyway?

I think the concept of the "ego item" in gaming can be credited to Gary Gygax, back in 1E AD&D if not before. Literally, he meant an object with an ego, with its own personality. In gaming terms, these were powerful items whose egos meant they were not to be trifled with, expressed their views and could in extremis refuse to obey the wielder.

As ever with Angband the original intent of the designers is unclear, but over the years the term has come to mean "an item with one or more properties which its base item type doesn't have, excluding plusses to-hit/dam (on weapons) or to AC (on armour pieces)". The original concept of powerful arcane items with their own personalities is closer to what we think of as artifacts, and indeed some roguelikes actually express the personality of some artifacts quite explicitly (e.g. the Singing Sword in Crawl).

Having collected the stats from 25million dungeon levels in 3.3.0 we're working towards a fairly significant overhaul of item generation, to try and rebalance the prevalence of weapons and armour which has crept up on us over the last few years. As many people have observed, there are some deficiencies in the current system - two main ones being the distinction between "special" and other artifacts, and the granularity of the alloc_prob variable. There are also obvious problems with distribution: the vast majority of stuff is findable in the first half of the dungeon, making the second half less interesting and making potentially interesting items obsolete too quickly.

It seems to me that the current system of templates for ego items is quite limiting - you need a new template for every variation of an ego, such as if you want it to be quite common on boots and quite rare on armour, or permit a higher pval in one slot than another. The potential for random variation is currently limited to a single random sustain, random high resist or random ability, and even these are implemented in a spectacularly hackish way. There's also no reliable way of providing a smooth power curve from {average} through {good} to low-end ego to high-end ego. Although you ought to be more likely to find Slay Troll than Holy Avenger on dl20 and the reverse on dl80, that isn't noticeably true.

I've had item affixes in the corner of my mind for a couple of years now. EyAngband introduced a number of useful innovations, this one clearly inspired by the prefix/suffix system used in many modern CRPGs (Diablo, Dungeon Siege, Titan Quest et al.). While EyAngband used them as a bolt-on to the existing framework, it would seem eminently plausible to replace Angband's template system with an affix-driven system for magical and ego items. What follows are my initial thoughts on how this could work and why it would be an improvement - feedback would be most welcome.

First, let's distinguish between craftsmanship and magic. A set of affixes like sharp/keen/brutal of piercing/slashing/bludgeoning could refer to additional damage-dealing properties of weapons which result from superior craftsmanship rather than magic (e.g. +dam, or chance of 2x dam, or whatever). Similarly, affixes like superior or of deflection could imply similarly-derived properties for armour (e.g. increased AC, reduced weight). As an aside, this opens up interesting possibilities for making detection slightly less dominant if these items did not show up as magic.

Next, you have all the magical affixes, which should be divided into groups. These would include slays, brands, resists, stat boosts, protections, movement effects (speed, stealth, FA, lower weight, etc.) and so on. I envisage a one-to-one mapping of affixes to object flags, so that any code for picking affixes can provide any individual flag. (Note to self: get the OFT_ types right in list-object-flags.h and this grouping is already done.)

That gives you the basic framework for creating the equivalent of {good} items and low-end egos. What we now think of as {good} would be those with a non-magical affix (occasionally two) which purely boosted offence or defence, while those with one magical affix would be the equivalent of today's single-slay weapons and other one-trick egos.

Where it gets interesting is combining multiple affixes. You can combine a prefix and a suffix to get items ranging from mildly exciting to endgame (anyone remember Godly Plate of the Whale?). You can combine more than one of each to re-create the current high-end egos, with hundreds of other possibilities. You can combine craftsmanship and magical affixes to get even more permutations (sure, Gondolin weapons are special, but some of the smiths were better than others). The key thing about this is that it provides a route to a smoother power curve - the number of affixes would be a function of depth, with shallow items rarely getting more than one or two and really deep items rarely getting fewer than four or five.

Not all properties are equal so it would be sensible if there was some way of telling the generator that "of Dragonbane" is a more useful affix than "of Troll-slaying". I know that some people intensely dislike numerical power ratings, so I remain open to alternative ways of achieving this. In the meantime, list-object-flags.h already provides a rating for each flag, and a multiplier for each slot, which could be used as a starting point.

To avoid a total mish-mash of random permutations, we could tell the generator to recognise certain combinations and steer its later choices. This would enable us to retain the flavour of existing ego types without their limitations - we could specify the likelihood of each affix on a per-slot basis, and limit the later choices as much or as little as we wanted. (Hmmm, this item has one more affix to go, and it's already got SLAY_ORC and SLAY_TROLL - looks like a weak Westernesse weapon to me, so let's give it STR or DEX ... oooh we rolled a 1_in_6, let's bung in a sustain for free ...) It would also go hand-in-hand with naming items with multiple affixes - so for example anything with two of SLAY_EVIL, SLAY_UNDEAD and SLAY_DEMON gets the prefix "holy".

This proposal will mean rethinking the concept of randarts. With more randomness in non-artifact items, it becomes less important in artifacts. I think there is still a place for randarts, but how to distinguish them from these new ego items is a topic for another day. (My initial instinct is to randomise only *some* of the properties of each artifact ...)

So how are we going to balance this to make sure it doesn't flood the dungeon with egos (er ...) or, even worse, leave people struggling with a +0 whip until 2000'. That's what the stats module is for - rather than agonise over balance before writing it we can write it, run some stats, adjust it and iterate. It's non-trivial (the code for picking names is going to be tricky - fortunately there's a handy precedent in Sangband's class titles), but I think it's possible.

What do you think?

Wednesday, 17 August 2011

Some thoughts on the Angband economy

I have just been reading a book called Debt by the anthropologist David Graeber - it's a fascinating book, examining in some depth the forms that states, markets, money, credit and debt have existed in. This has prompted me to ask some questions of Angband's economy, some of which I am sure are entirely superfluous and others which might prompt some useful, gameplay-improving answers.

So, first: Angband's economy is based entirely in gold coins and the convertibility of precious metals and minerals directly into gold coins. Note that the game itself never says that you have any gold coins: just so much stuff that is equivalent to so many gold coins.

Where is the adventurer finding enough space to carry (at the beginning of the game) enough chunks of copper to the value of 213 gold pieces or (at the end of the game) enough chunks of precious minerals to the value of tens of thousands of gold pieces? That much stuff would weigh you down. I think an intelligent player would try to maintain a certain amount of tradeable currency, but not pick up everything they found.

Also, the amount of gold that successive adventurers would bring up from the dungeon would surely cause massive inflationary problems...

And why does everyone in the dungeon seem to be carrying around so many precious stones all the time? Their needs as troops (food, water, weapons, armour) will surely be met in some semi-centralised way, since Morgoth needs an army that can fight, that is well-nourished and the like. So in everyday usage, soldiers would make no use of money or precious stones. Why are they carrying them?

Also, how does the town even exist? It is a weird place, atop a massive dungeon full of murderous individuals, all looking to profit from looting and pillaging. The town is nevertheless full of other people, none of whom seem to be particularly interesting or adventurous, all of whom must survive somehow but clearly do not possess the survival skills to fight even a moderately well-equipped player. These people must all eat and sleep somehow. They must also be occupied one way or another. Who is paying them to laze around in a position of extreme danger?

The player has an unguarded, unprotected home in which they can place whatever they like and be sure that it is there even though the building is unoccupied 99% of the time. How does it not get broken into?

Also, why is is cheaper to buy arrows than food? Why are cloaks cheaper than food? Food is essential for life. The idea that a ration of food should cost four gold pieces makes the real-world inflation of food prices look seem tiny by comparison. And why is food handled in-game but drink not?

Why does the player not simply demand what they want from the shopkeepers and threaten to kill them otherwise? There is a total lack of authority or protection to keep this from happening. There is no reason for the shopkeepers not to kill the player, either.

I think a lot of the weirdness of the Angband economy comes down to this: we are all very used to exchanging money for other things we want or need in shops, in line with the rule of law. However, the situation that lets us do this (state authority, police, judicial systems) is pretty much entirely dissimilar to the situation in Angband.

Actually, the entire system of tradeable commodities that Angband has is completely unfitting to the place the game is set. The idea that you can have seventeen identical longswords is somewhat ridiculous, or twenty pieces of plate mail - these things historically would not have been available for trade. You would, at best, be paying someone to make them for you, to your specification. Smiths would not have created massive surpluses because there would have been no reason for them to do so.

That's all very well, but...

So what might happen if we try and provide more reasonable answers to these questions? What happens if we try to re-balance the game's economy? I think that some gameplay issues might start to disappear, mostly those around gold availability, buying, and selling.

From the list above, I would start off with:

1. Make currency weigh the player down. Allow them to drop it, pick it up, etc.

2. Reduce the amount of money that monsters in the dungeon carry, significantly. Some monsters should hoard lots of money (but should maybe not be carrying it - think dragons) but most will have none. The current scaling of amount of GP / drop with dungeon level will need to be rethought.

Pair this up with a reduction in the amount of money required to purchase items. EyAngband started doing this quite well.

3. The home should either be a general item-deposit place that holds your items securely for an access fee, or it should be a home that requires you to pay a retainer to guard it.

After this, what? I think food and drink need to be reconsidered - either they need to become serious elements of the game or they need to disappear. The shops need a plausible back-story; are they all merchants, bringing wares to flog to needy adventurers, or is there a permanent weaponsmith, potionbrewer, etc in residence all the time? How do they survive?

These questions affect the gameplay decisions around them. If the weaponsmith's is actually a weaponsmith's, then maybe you can ask them to make you a new weapon for a given price, but they are unlikely to keep hundreds of weapons in their store. But if they are a merchant, they will surely want to bring some impressive swords along with some cheaper ones - but maybe they will only part with them for a large sum. They certainly wouldn't bring 18 whips and 18 daggers.

Maybe, also, the player could leave a deposit on a particularly handsome item and come back for it later with more money. Combined with a reduction in the availability of gold, this turns into less of a scum-fest and more of something with the potential to be an interesting minigame.

Merchants would also be unlikely to buy unimpressive weapons or items - their job is to turn up with wares, flog them and get lots of precious stones and metals to take back away with them. Unimpressive weapons are worth less to the merchant than the equivalent in gold pieces, because the entire point of the trading is to exchange weapons for more liquid assets. There would have to be regular trips away from the area in order to get more stock and deposit money with a bank, out of danger - this provides a nice explanation for shopkeeper rotation.

And why the hell would there be a temple above Angband? On this thought, I'll leave you.

Thursday, 24 March 2011

So many flags, so little time ...

So I finally managed to refactor monster spells into a data table (or
three, in fact). It taught me a lot. As takkaria notes in the first post, the thinking in the original code is not always easy to divine, as layer upon layer of change over the years either obscures it or undermines it (if it was there in the first place).

What we had was half the spells being resolved in monster2.c (the non-projectable ones), and the other half being resolved by the projection code in spells1.c. We now have a separate mon-spell.c which will handle all spells and their side effects, calling out to project() where necessary.

Monster spells, by the way, means anything that isn't a melee attack - so all breaths, balls and bolts as well as the non-damaging spells like teleportation, confusion, summoning etc. Anything that's on an S: line in monster.txt and has an RSF_ flag in the code.

This work led me to two conclusions: the first is that data tables and nice flavourful text output don't mix well. It was hard enough doing all the different verbs for slay_table, but I think it's worth moving to an edit file for the spell text. If I understand takkaria correctly the list-foo.h data tables are a stepping stone towards some sort of scriptable edit file setup anyway, and elly's brilliant parser API makes writing a new parser possible for the syntactically challenged. This way we can keep (and even enhance) the flavour of the different in-game messages without cluttering the list-* files.

The second conclusion is that we ought to go back to first principles and have a think about object flags before we make too many more decisions which are constrained by the existing setup. Object flags are fundamental to the game, because they are used by p_ptr->state to determine resistances and other abilities granted to @ by objects. (Perhaps really going back to first principles would challenge this way of tracking @'s state, but that's a separate essay - for now I'll start from here.)

At the moment object flags are all lumped together in a single group, and we use a load of #defines to create "masks" for particular flag types (slays, brands, obvious flags, etc.). We recently expanded OF_SIZE because we went beyond the limit of 96 flags when the new HATES_FOO flags were introduced in object_base.txt. We can now have up to 255 object flags before we need to change savefiles again. (takkaria has written a new block-based savefile format, which should mean much better savefile compat in future.)

But there are already two different types of flags, and should probably be more. There are binary flags (you either have fire immunity or you don't), and there are pval flags (you have an object which affects your STR, but the precise effect is determined by a pval).

Before I added multiple pvals, there was no structural governance of which flags were connected with an object's pval and which weren't - it was all done by hard-coded rules. Now we have a set of o_ptr->pval_flags for each pval, which simply indexes each flag which is related to that pval. This may seem memory-inefficient at 32 bytes for each pval, but it allows object flag operations to use a single flagset instead of searching over N pval flagsets (+1 for the non-pval flags). It also allows a binary flag to become a pval flag with a minimum of hackery.

As I was acquainting myself with the ID code last year, I was gratified to learn that o_ptr->known_flags is exactly what you expect it to be: a bitflag which tells you which object flags @ knows to be present on the object. I assumed that o_ptr->flags was the actual flags present on the object - and it is in a way, but it's almost never used directly.

Instead a function will create a bitflag f[OF_SIZE] and call object_flags(f). This copies into f the flags of the base object type, those of the object kind, then flags from any ego type or artifact. Instead of being done once at object creation, this is done repeatedly throughout the code. If there was ever a reason for this I can't find it - the object list is global, so the memory for all the o_ptr->flags of all the objects is already in use at any point.

Of course, the object list isn't a single list. There's o_list, which has all the items on the current dungeon level, including those carried by monsters. There's p_ptr->inventory, which is everything @ is carrying and wearing. There's st_ptr->stock, which is all the objects in a store. But they're all global.

In fact, the only flags which *aren't* copied over every time object_flags is called are the curse flags - so when you remove a curse from an object, it stays removed. Now, why doesn't this apply to every other flag too? That way all sorts of spells and effects in the game could add or remove flags from objects, opening up all sorts of possibilities (forging, anyone?) - including the long-gestated new curses. Recent discussion on Oook came down against allowing effects to remove flags from objects, but dispelling timed buffs was considered tolerable.

So we come to the issue of timed flags. The TMD_ flag set is quite recent (2008) and the MON_TMD_ group are even more so. We will have to be careful to keep these separate from object flags, and test for both timed and object flags if necessary. In calc_bonuses we copy TMD_OPP_CONF to p_ptr->state, and likewise with TMD_AFRAID. We should soon be able to do without this, as the new check_for_resist function returns nonzero if either is present. But at the moment it only works for effects whose temporary and permanent effects are linked in gf_table, so something needs redesigning if it is to be more broadly useful.

My suggestions so far:

1) Make o_ptr->flags the definitive source of an object's flags (call object_flags at creation, but not subsequently). This would allow us to do lots of interesting things to add flags before upsetting people by taking any away (but some of the additions could be curses ...)

2) Synchronise OF_FOO and TMD_FOO so that they are linked pairs. This should enable a single check for any flag in the player's state, regardless of whether it comes from an object or a temporary spell effect.

3) Add o_ptr->timed_flags[OF_MAX] so that each object flag can be added or removed temporarily as well as permanently. This would add about 600k to the memory footprint (256x u16b per object, or more if we want timers over 2^16), but should still leave us about two orders of magnitude short of memory-limiting an average smartphone.

4) Create of_table[OF_MAX] to replace all the #defines for OF_FOO_MASK. This would also allow the encoding of other info about a particular flag (e.g. whether it could be found as a random ego power, or on a randart).

None of this directly changes gameplay, but it opens up possibilities that the current code cannot offer. Even if we don't want to use them, variant maintainers might.