Feature - Implemented Include variable/scaling monsters in monster stat functions

Veracity

Developer
Staff member
That's exactly right. I recall not being completely satisfied with ... something. I need to look at it again and incorporate it in a way that satisfies me, but that will take more time than I can afford to devote to it before the upcoming new release.
 

Theraze

Active member
Possibly that I decided not to break current monster files. As they currently stand, a space is considered the delineator between sections. Modifiers uses a comma as its delineator between the modifier effects, I believe. I seem to recall most examples that people posted of how scaling monsters could work involved spaces, though that could just be my head lying to me. It's early yet, and I have no caffeine.

The other bit was that you had requested brackets for evaluation. Because we already have the entire segment delineated by the spaces, additional delineators (the brackets) weren't needed to find what was being evaluated. Since the value is either a pure number or something we'll need to evaluate, I ran it through the isNumeric function to decide which to do (save or evaluate). Brackets could still be added, though they'd be there purely for show (because space is the delineator, unless it's changed, as noted above), and would be removed by the evaluative system when it actually processes.

But I think the bracket issue was the main one remaining, mentioned by both you and Jason, but which would take reworking this from MonsterDatabase...
Code:
  StringTokenizer tokens = new StringTokenizer( s, " " );
Since that breaks each of the parameters (hp, attack, defence, etc) using spaces, if the goal is not to break up bracketted statements that involve them, the tokenizer or data files will need some reworking...

Not saying that was the only issue, but that's the only part I'm aware of that's still divergent. Haven't had dev feedback since Jason checked on the original patch back Dec 15th.
 

jasonharper

Developer
Modifier expressions can contain spaces (as part of the parameter to a text function). How are you imagining that spaces are going to be sufficient to delimit expressions here?

Monster poison levels in monsters.txt already contain spaces, the existing tokenizer isn't the problem.
 

Theraze

Active member
Ah... it uses "<text>" as its current bracketting for monster poison. Hmm... let me try to see if I can rework that. value.startsWith("[") for beginning the evaluation sequence, temp.endsWith("]") to end it... anything else to be aware of, or should it be that simple?

Edit: Will try this for HP loading.
Code:
    if ( option.equals( "HP:" ) )
    {
     if ( tokens.hasMoreTokens() )
     {
      value = tokens.nextToken();
      if ( value.startsWith( "[" ) )
      {
       StringBuffer temp = new StringBuffer( value );
       while ( !value.endsWith( "]" ) && tokens.hasMoreTokens() )
       {
        value = tokens.nextToken();
        temp.append( ' ' );
        temp.append( value );
       }
       value = temp.toString();
      }
      if (StringUtilities.isNumeric(value)) health = StringUtilities.parseInt( value );
      else evaluatehealth = value;
      continue;
     }
    }

Well, it sort of works... the current issue is that the evaluator isn't scrapping the brackets. After code change, before bracket addition:
> ash monster_attack(to_monster("ratswor"))
Returned: 164
After:
> ash monster_attack(to_monster("ratswor"))
Evaluator syntax error: can't understand [MOX+min(3+A,12)]
Returned: 0

Edit2: Tweaked the temp to value code, so it strips leading/trailing characters, which are just the [ and ]. By doing that, the evaluated text should work fine, but you can use the brackets if needed. Returned this:
> ash monster_attack(to_monster("ratswor"))

Returned: 164
by changing
Code:
       value = temp.toString();
to
Code:
       value = temp.toString().substring(1, (temp.toString().length() - 1));
Potential issue if you have spaces... the actual Evaluator fails to process it properly, if it's not one of the text items that's supposed to have spaces.
> ash monster_attack(to_monster("ratswor"))

Expression syntax error for '': expected end, found + min(3+A,12)
Returned: 154
Guessing that's working as it should though, since it did save the whole strong properly as the evaluative text.

Edit3: Guess I could spin another patch if anyone cares, or if not I'll just wait until after the next main version gets spun and devs have more time. Thanks for the pointings today. Brackets are a go. :) Now I just need to apply it to all of the randomly scattered monsters using my hex editor... meh.
 
Last edited:

Theraze

Active member
Okay, monster files should be updated (on my system).

Here's the structure update. Guessing there won't be too many more huge changes to this structure, so I'll post this and let people poke around until someone with time evaluates it again. :)

After the structure and datafile update actually happen, we'll have to try to figure out that stuff on monster quantity drops to clean up the CRIMBCO monsters... they still exist through faxes, right? So people can still scrip-farm, though they can't turn them in anymore? Anyways... currently, they have 5-30 scrips at n100 drop rate. Having these be a single drop with (q5) or something like that would definitely be simpler. And easier to read.
 

Attachments

  • ScalingMonstersStructure.patch
    13.4 KB · Views: 24

Theraze

Active member
Dunno... I know some of them were obfactable, but I'm not sure on that. Anyways, if we're keeping legacy monsters from 3-5 crimbos back, no real reason to remove this year's. Unless those ones were copy-able, unlike this one.

Anyways, as long as the monsters are still in the data files, we may as well try to keep our information accurate which (to me) means the proper drops, including amount.
 

Winterbay

Active member
True. The wiki lists Crimbco monsters and the cimbomination as the only crimbo-monsters that aren't copyable. I guess they finally decided there was no need for them :)
 

Theraze

Active member
So... what can I do to make the patch more paletable for eventual examination? It does have the [] awareness now, and 14.4 has been spun, so...
 

Theraze

Active member
Thanks much, Jason.

If anyone else looks through and notices problems before then, let me know before the weekend and I'll try to save Jason some time. Everything works as far as I've noticed... but then again, that's using things as me.
 

jasonharper

Developer
Theraze, this is... not right. Not right at all.

The whole point of this change, as I understand it, is to make the stats of scaling monsters work exactly the same as the stats of normal monsters. Your patch does the exact opposite of that: it permanently requires that every bit of mafia code that deals with monster stats now MUST call getEvaluating() in order to apply special-casing for scaling monsters. The function is not well-defined anyway, since it can return only a single value, yet there's no check that the monster actually supplied expressions for all four overrideable values.

Also, you're still fundamentally misunderstanding how the expression objects are supposed to be used. The reason why they have separate compile and evaluate steps is so that you can compile the expression ONCE (that's the time-consuming part), and then quickly evaluate them as many times as needed. Throwing away the compiled expression after every evaluation is simply insane.
 

Theraze

Active member
Actually, it has to be evaluated each time, because every time your stats change, their stats change... Gain a point of moxie? Every monster with scaling moxie has their stats change... Change your equipment? All their stats change. Though I suppose you could instead hook into the stat system and every time any stat changes, re-evaluate all the monsters... it just seemed more efficient to only call them as they were relevant, at the start of the battle or when calling safe values or the like.
 

StDoodle

Minion
It sounds to me -- and I may well be either misinterpreting jasonharper and / or too ignorant of the code, and if so my apologies -- that jasonharper is saying that it's a problem that this overhead is being applied with every call to an individual stat-related function. Sure, when the situation changes, the results may change. But you still don't want to recompile the expression if you call the attack value followed by the defense value followed by the hp.
 

Theraze

Active member
What it does is check if any of the values are set as an evaluative string, and if so, calls the evaluation for that single item... it doesn't evaluate HP if you're asking for attack. The issue (as I understand it) is that it has to re-evaluate whatever you're asking for every time, and this is because of the way that the monsters/system works. I initially had it working exactly like normal monsters... but all scaling monsters had stats of 0 (or 3, for Baron von Rats, since that's his minimum). I could have it update once when you login, but that wouldn't be accurate as soon as you changed out of your rollover gear.
 
It sounds to me like there's still some misunderstanding about the difference between compilation and evaluation. My understanding is that expressions are dealt with in two passes. The first - compilation - checks the syntax, and converts the text expression into a form that is quick to evaluate (like Java byte code). The second phase then actually carries out the evaluation. Compilation only ever needs to be done once for a given expression, while evaluation can be done many times. Even if moxie etc. change, there's still no need to recompile the expression, provided the "byte code" has a code that will make the evaluator grab the player's current moxie.

Theraze seems to be arguing that the expression needs to be evaluated each time, which is true, while Jason is arguing that it doesn't need to be recompiled each time, which should also be true. The overhead of looking up player.moxie() for a particular byte code (evaluation) is going to be really small compared with the overhead of parsing the whole expression (compilation).

Apologies if I've misunderstood the argument here...
 

Theraze

Active member
Ahh... okay then, I just need to understand how to save the compiled form in a way where it will be reevaluated... not sure how to do that. Last time I tried, I made them only get evaluated once, as I said above. :(
 
I think, instead of adding:
Code:
private final String evaluateattack;
private final String evaluatedefense;
...
to the Monster class, you need to add some kind of Expression class for each, e.g.
Code:
MonsterExpression attackExpr;
MonsterExpression defenseExpr;
When you read the monster data file, you will initialise these expressions (for scaling monsters) - the constructor for MonsterExpression would compile the expression into bytecode (which is stored in the Expression base class?).
In Monster.getAttack() etc., if attackExpr is not null then call attackExpr.eval(). eval() will grab the player's current moxie/muscle etc. for the expression, provided you have created bytecode characters to represent these.

I hope one of the devs will jump in if I'm talking rubbish...
 

Veracity

Developer
Staff member
That's not rubbish. The byte code is stored in the individual MonsterExpression object.

Frankly, I'm not sure I'd bother having a "attackExpr" and an "attack" variable and deciding to either evaluate the expression or fetch the constant whenever you need to get the current attack. Just have a compiled MonsterExpression for everything which CAN have an expression in monsters.txt. After all, the constant 200 is a perfectly good expression, which happens to be very efficient to evaluate. I think that was one of the things that specifically bugged me when I first looked at your code: it was just too complicated.

Jason might have a different opinion, based on efficiency and memory usage. Or not.
 

Theraze

Active member
Sounds good to me, since I obviously have no clue how to do it without direction. :D I'll plan on doing that unless Jason or Veracity say to do it differently.

Edit: And Veracity has, slightly. Not to what you said, but to turn everything into an expression, officially. Which makes sense... a pure number should evaluate out into itself quite quickly. Okay... will turn all 4 of those (HP/Attack/Defense/Initiative) into expressions all the time.
 
Top