Angband.oook.cz
Angband.oook.cz
AboutVariantsLadderForumCompetitionComicScreenshotsFunniesLinks

Go Back   Angband Forums > Angband > Variants

Reply
 
Thread Tools Display Modes
Old November 11, 2012, 21:52   #1
Magnate
Angband Devteam member
 
Join Date: May 2007
Location: London, UK
Posts: 5,057
Magnate is on a distinguished road
Send a message via MSN to Magnate Send a message via Yahoo to Magnate
Pyrel dev log, part 4

Just sayin' ;-)
__________________
"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
Magnate is offline   Reply With Quote
Old November 13, 2012, 19:23   #2
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 8,917
Derakon is on a distinguished road
Yeah, yeah. Wimp.

Anyway, fizzix expressed some confusion about how the code is laid out, which is entirely reasonable for someone starting on a new project, so I went ahead and wrote up a high-level overview of the code. It's not very well-edited (but it's a wiki! Hint Hint!), but it should help people get oriented.

Also, an idea I had that I need to record somewhere: use the same system for displaying the character's status as for displaying monster memory. Obviously the character has some stats that monsters don't (currently) care about, like perception, stealth, and device use; monsters also have different spells. But the overall framework is similar, and I think it's a good idea to reinforce how Angband's systems work especially e.g. with regard to resistances.

The by-equipment breakdown page would be a follow-on page, of course.

Incidentally, it would totally be possible to write up monster memory now; monster stats are fully fleshed-out.
Derakon is offline   Reply With Quote
Old November 20, 2012, 19:57   #3
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 8,917
Derakon is on a distinguished road
Not to worry, things aren't dead! In fact, Pyrel has seen a lot of activity lately. Magnate's gotten a lot done on item affixes; Fizzix is laying the groundwork for level generation; Noz has been adding various wizard-mode commands. And for my part, I've mostly been approving pull requests.

The next thing I personally want to tackle is a refactoring of the proc/effect system. The original system has been extended and over-extended and is now more painful to work with than it really needs to be. Part of the problem is that every Proc is bundled into an Effect, which creates a lot of excess layers in the data files. For example, if you want to make a potion that cures 10% HP when drunk, you'd:

* Create a record in object.txt for the potion
* Create an Effect for the potion that triggers on item use and invokes the "healPlayer" Proc
* In the potion's record in object.txt, set the healing amount for the proc to 10%

This is a lot of bouncing back and forth between object records and effect records, and the code is kind of messy too. So here's my proposal for a new system:

* The datafiles get a new file: data/proc_template.txt. There is no data/proc.txt (but entries in proc_template can be "complete" procs if desired).
* Each individual proc has a name (referring to the code it will invoke), a trigger condition (determining when its code will be invoked), and any parameters it requires. Of course, some of these may be filled in by templates. However, the trigger condition is not specified either by the proc record or by its templates.
* When procs are referred to in other records, it is as a mapping of trigger conditions to lists of procs.

I think this covers the use cases we want. The important thing is that we want to be able to use the same in-game "effect" from multiple different triggers, without having to create separate proc records for each trigger. Under this regime, we'd have something like the follow:
Code:
proc_template.txt:
{
    "name": "modify hitpoints"
}

object.txt:
{
    "name": "Cure Light Wounds",
    "templates": ["potion"],
    "procs": {
        "on item use": [
            {"name": "modify hitpoints",
              "target": "user", 
              "power": "+10%"
            }, 
            "decrement quantity"
        ]
    }
}
Of course, we do have a lot of potions that heal the user by some amount, so we might want to have a separate "heal self" proc that in-lines the "target" parameter. And we could modify the "potion" object template so that "on item use" always invokes the "decrement quantity" proc. But the basic concept seems sound.

Thoughts?
Derakon is offline   Reply With Quote
Old November 28, 2012, 22:47   #4
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 8,917
Derakon is on a distinguished road
Therem Harth expressed some interest in working on spellcasting for Pyrel, so I guess I'd better write down my thoughts on that!

We can think of spells as having three main components: the effect of the spell when cast, the cost of casting the spell, and the chance of failing to successfully cast it. In Pyrel, each of these should be a Proc. How are these Procs handled? We can attach them to items -- call them spellscrolls.

And the items, of course, go into spellbooks, which in Pyrel will be containers. Of course in Vanilla proper you would be unable to put things into or take things out of spellbooks, since they'd be generated with all of their spells already set, but that's a detail that can be saved for later. In fact, spellbooks as a whole can be saved for later -- just implementing working spellscrolls will be enough to get us started.

So the player's holding some spellscrolls and they choose the "cast a spell" command. This command needs to do the following:

Gather this information:
* Which spell the player wants to cast (ItemListPrompt to select a spellscroll)
* How much it costs (examine the selected spellscroll)
* Whether the player really wants to cast it (YesNoPrompt), if the cost exceeds their current allowance
* Any relevant targeting information (TargetPrompt or ItemListPrompt as appropriate)

And then execute:
* Deduct the cost from the player's stats
* Determine if the player succeeds in casting the spell
* Cause the spell's effect to take place


Now we need to decide what the item record looks like. I suggest something like the following:
Code:
{
    "subtype": "&Resist Heat & Cold~",
    "templates": ["spellscroll"],
    "allocations": [{"commonness": 20, "minDepth": 10, "maxDepth": 60}]
    "procs": [{
        "triggerCondition": "cast spell", 
        "name": "temporary stat mod", "modAmount": 1, 
        "statNames": ["RES_FIRE", "RES_COLD"], 
        "duration": "10+d10M20",
        "targeting": "none"
    },
    {
        "triggerCondition": "spell failure rate",
        "name": "failure rate calculator", 
        "difficulty": 5,
        "spellType": "holy"
    },
    {
        "triggerCondition": "spell cost",
        "name": "stat calculator",
        "statName": "holy skill",
        "multiplier": -.5,
        "addend": 10
    }]
Let me explain some of this now. First off, the "spell cost" proc here is invoking an as-yet nonexistent proc that calculates a number based on the player's stats. Here we're saying that the spell's cost is 10 - half the player's holy skill stat. So we can go into the Priest class template and give them a holy skill of 10, say (spell cost is 5), and then the Paladin gets a holy skill of 5, so they pay 2.5 extra mana to cast the spell (spell cost is 7).

Then the spell failure rate proc is a specific proc only for dealing with spells. It too operates on the player's stats, and all it cares about is how hard the spell is to cast. Presumably it uses a formula such that the higher your skill and the higher your spellcasting stat, the easier the spell is to cast.

Finally the "cast spell" proc actually causes the spell to take effect, by giving the player a temporary bonus to their fire and cold resistance stats. These stats are actually binary on/off but codewise we treat them as if they stack. Actually we should use a separate stat name for temporary and permanent element resistances so that we can use Vanilla's..."unique"...approach to resistance stacking, but that's an unimportant detail.

Note that the "cast spell" proc has an extra "targeting" field. The proc code itself will not refer to this, but the command-execution logic needs to know how the spell is targeted so it can determine what information is needed to execute the spell. Valid targeting values would be "none", "item", and "aimed" -- that last one is for normal projectile targeting. Of course we need to modify the Proc code to provide access to this information; just add this function to the base Proc class:
Code:
def getParam(self, paramName):
    if paramName not in self.params:
        raise RuntimeError("Invalid parameter name [%s]" % paramName)
    return self.params[paramName]
Anyway, that should about do it. Thoughts? Requests for clarification? Thread-derailing tangents?
Derakon is offline   Reply With Quote
Old November 28, 2012, 23:33   #5
fizzix
Prophet
 
Join Date: Aug 2009
Location: Madison, Wisconsin, US
Posts: 3,002
fizzix is on a distinguished road
Quote:
Originally Posted by Derakon View Post
Let me explain some of this now. First off, the "spell cost" proc here is invoking an as-yet nonexistent proc that calculates a number based on the player's stats. Here we're saying that the spell's cost is 10 - half the player's holy skill stat. So we can go into the Priest class template and give them a holy skill of 10, say (spell cost is 5), and then the Paladin gets a holy skill of 5, so they pay 2.5 extra mana to cast the spell (spell cost is 7).
I don't like this. You want some classes to be better at certain spells than other classes independent of a holy or magic skill stat. For example, a rogue should be better at detecting magical objects and a mage, but a mage is better at creating magical light.

In other words, make sure we can support the V design where each class has a list of what spells it can cast and what they cost.
fizzix is offline   Reply With Quote
Old November 29, 2012, 00:06   #6
Patashu
Knight
 
Patashu's Avatar
 
Join Date: Jan 2008
Posts: 526
Patashu is on a distinguished road
What if I wanted, say, an amulet that could be used to cast a spell? Would the code that prompts me to choose a spell to cast also iterate over non spellscrolls to see if they have the trigger 'cast spell'?

If I wanted a spell that could only cast in certain situations, would I give it a novel proc under spell failure rate that makes the failure rate 100% when you're not allowed to cast it?
Would it be possible to combine procs that resolve to a numerical or boolean type via min/max/and/or/xor?
It would also be useful to have a generic expression syntax to sneak into places where a calculation is expected (for example, if modify hit points took current hp as x and max hp as y and could be set to 020, 2d12, y*0.1, -x*0.9 for poison, max(2d12+y*0.1), etc). Being able to do such a thing could save on lots of dummy procs that do the same as other procs but with a brief calculation first. I've written an expression evaluating calculator in C# once, took 2 days
__________________
My Chiptune music, made in Famitracker: http://soundcloud.com/patashu
Patashu is offline   Reply With Quote
Old November 29, 2012, 00:24   #7
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 8,917
Derakon is on a distinguished road
Quote:
Originally Posted by fizzix View Post
I don't like this. You want some classes to be better at certain spells than other classes independent of a holy or magic skill stat. For example, a rogue should be better at detecting magical objects and a mage, but a mage is better at creating magical light.

In other words, make sure we can support the V design where each class has a list of what spells it can cast and what they cost.
You have a fair point that some classes ought to be better at certain types of spells than other classes, but IMO we shouldn't do this by just enumerating the spells and classes and declaring a skill level for each one. Much better to come up with a set of rules that describe the system that we want, so that later when we add new spells we just insert them into the system and they automatically behave themselves nicely.

Thus what I'd suggest is to split the skill stats:
* healing: priests > paladins > rangers >> mages/rogues
* detection: rogues > mages > priests > paladins/rangers
* attack: mages > priests >> rangers > paladins >> rogues
* buffing: priests > mages > paladins? > rogues? > rangers
etc...

To make spells exclusive to certain classes, we can have a failure-rate proc that flat-out prevents casting the spell if your skill with that spell type is below some threshold level. Spells with 100% failure rates are unlearnable.

This leads into Patashu's question...
Quote:
Originally Posted by Patashu
What if I wanted, say, an amulet that could be used to cast a spell? Would the code that prompts me to choose a spell to cast also iterate over non spellscrolls to see if they have the trigger 'cast spell'?
Yes. When the item is created, it examines its procs; if it has procs with the "cast spell" triggerCondition then it puts itself into the CASTABLE container, which the "cast a spell" command will use to select possible spells to cast.

Put another way, any item that has a "cast spell" proc can be used to cast a spell.

If you have no "failure rate" procs, then the spell always succeeds; if you have no "spell cost" procs, then the spell is free to cast.

Quote:
If I wanted a spell that could only cast in certain situations, would I give it a novel proc under spell failure rate that makes the failure rate 100% when you're not allowed to cast it?
I didn't get into this in the original post because I didn't want to get bogged down, but my assumption is that if you have multiple procs with the same trigger condition, then they are attempted in sequence. So if you have multiple failure-rate procs, then if any of them fails the spell fails. Likewise you could have multiple spell-cost procs (say, to make a spell temporarily drain a stat in addition to costing mana) and they would all apply when the spell is cast. And of course the spell could have multiple effects when it is successfully cast.

Quote:
It would also be useful to have a generic expression syntax to sneak into places where a calculation is expected (for example, if modify hit points took current hp as x and max hp as y and could be set to 020, 2d12, y*0.1, -x*0.9 for poison, max(2d12+y*0.1), etc). Being able to do such a thing could save on lots of dummy procs that do the same as other procs but with a brief calculation first. I've written an expression evaluating calculator in C# once, took 2 days
I spoke with Magnate about creating a Proc that does multivariable polynomial evaluation without having to do any parsing -- the expression would be provided as a list of coefficients (e.g. "[60, 3, .5]" => "60 + 3x + .5x^2"). This is a bit clunky but does work. If we wanted to have proper expression parsing, and that might well be useful for making the data files easier to read if nothing else, then we can either try to implement our own in-house parser, or use a third-party library, of which there are plenty.

The only problem with third-party libraries is that they create extra dependencies that people have to install before they can start developing the game. Players wouldn't care as the game would be distributed as a standalone executable with all dependencies bundled in, but ideally devs should be able to get up and running with a minimum of fuss.

So hey, if you feel like rewriting your expression evaluator in Python, then I for one wouldn't say no.
Derakon is offline   Reply With Quote
Old November 29, 2012, 04:49   #8
fizzix
Prophet
 
Join Date: Aug 2009
Location: Madison, Wisconsin, US
Posts: 3,002
fizzix is on a distinguished road
Quote:
Originally Posted by Derakon View Post
You have a fair point that some classes ought to be better at certain types of spells than other classes, but IMO we shouldn't do this by just enumerating the spells and classes and declaring a skill level for each one. Much better to come up with a set of rules that describe the system that we want, so that later when we add new spells we just insert them into the system and they automatically behave themselves nicely.

Thus what I'd suggest is to split the skill stats:
* healing: priests > paladins > rangers >> mages/rogues
* detection: rogues > mages > priests > paladins/rangers
* attack: mages > priests >> rangers > paladins >> rogues
* buffing: priests > mages > paladins? > rogues? > rangers
etc...

To make spells exclusive to certain classes, we can have a failure-rate proc that flat-out prevents casting the spell if your skill with that spell type is below some threshold level. Spells with 100% failure rates are unlearnable.
I disagree pretty strongly with this. The number of different spell categories that most devs will want is going to be so large as to completely neuter its purpose and add an extra layer of complexity instead of providing simplification.

What we should be aiming for is that the creation of new spells (or items, monsters, level types etc) is simple to understand, not that it shouldn't require some thought or effort in the values. Requiring a person creating a new spell to specify what classes can cast it, what it costs for them, and what the failure rate is for each of them seems like a perfectly fair requirement and not overly burdensome in any way. Actually, to me it seems far easier than figuring out some complicated weighting scheme for different classes.

The only question to me is where the information goes. It could go in the spell or the class. It seems in the pyrel way, it should all go in the spell information, so each spell would have a list of class (or race?) flags that can cast it, what it costs, failure rate, and any other spell characteristics (like xp gain for first casting).
fizzix is offline   Reply With Quote
Old November 29, 2012, 06:35   #9
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 8,917
Derakon is on a distinguished road
Quote:
Originally Posted by fizzix View Post
I disagree pretty strongly with this. The number of different spell categories that most devs will want is going to be so large as to completely neuter its purpose and add an extra layer of complexity instead of providing simplification.
I don't personally think this statement can be supported, but frankly it doesn't matter because we aren't locked into a single system. If you want to have spells that use hardcoded variations depending on the player's class, then you can do that. Just make a different set of procs for determining failure rate / spell cost, and, yes, include the class-specific values in the procs' definitions.

I daresay most spells can simply use the skill-based system instead and only a few exceptions, if any, will need the more specific approach.
Derakon is offline   Reply With Quote
Old November 29, 2012, 06:55   #10
Patashu
Knight
 
Patashu's Avatar
 
Join Date: Jan 2008
Posts: 526
Patashu is on a distinguished road
Quote:
Originally Posted by Derakon View Post
So hey, if you feel like rewriting your expression evaluator in Python, then I for one wouldn't say no.
Ok, I copied how I did it from memory.

(REDACTED)

Probably still buggy, haven't had much chance to test yet. Will make sure everything works next time I sit down at a computer

Using python's eval() may be a possible alternative, btw.
__________________
My Chiptune music, made in Famitracker: http://soundcloud.com/patashu

Last edited by Patashu; November 29, 2012 at 12:13.
Patashu is offline   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Pyrel dungeon generation fizzix Variants 50 December 7, 2012 01:32
Pyrel dev log, part 3 Derakon Variants 108 November 12, 2012 23:30
Affixes in Pyrel Magnate Development 0 October 13, 2012 13:53
Pyrel dev log, part 2 Derakon Variants 126 September 11, 2012 23:03
Pyrel dev log Derakon Variants 64 June 8, 2012 11:58


All times are GMT +1. The time now is 20:58.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.