Heres what I want: Player puts on +1 CON helmet, his max hps increase by 20. He takes it off, his max hps go down by 20. Similiarly with +2 CON, -6 CON, or whatever.
I know this isnt right, this seems like it would just add the hp bonus ive defined in con_app_type in const.c to the character's maxhit regardless of whether or not they are wearing the item. So someone could repeatedly take the item on and off and end up with infinite max hitpoints. But Im not sure how to write this the right way, nor where I should put the code.
What I would do is remove all references to "max_hit", and add a new function named something like "getEffectiveMaxHP" that takes the max_hit value and adds on appropriate bonuses. Of course, to do that would require a fair bit of redesign which might not be what you had in mind... :-)
In the meantime I'd go with Zeno's solution; if you want to add to somebody's HP, then have the object give an HP bonus. If you want the Con bonus as well, have it give that too. It's not as elegant, and not quite what you wanted probably, but it would work at least.
To implement something like what you have, you would have to carefully track every time a bonus is added [i]and removed[/i], and adjust the hit points accordingly. It would work a lot like how the effect system works now. (Incidentally, that system is very fragile and prone to doing weird things if things don't happen in precise and expected sequence.)
But it's a good idea, it's how most graphical games handle item based stat bonuses (and item based other bonuses as well) and it makes sense.. is the best solution really just to make it all based on wear/remove progs though?
Well actually heres my thought. The equipment part of it is really just a side-note. My real goal is to put a +current hp modifier into the const struct con_app table. I figure if a piece of equipment can give +current hitpoints as one of its modifiers, I should be able to use that same modifier in the table, no? Im gonna keep looking and see what I can find.
Okay so I decided to look to strength as a template for what I want to do. In const.c and mud.h str_app gives a modifier to hitroll and damroll, I figured if I can modify those I should be able to modify max hitpoints. Wrong. I cant find anywhere that the hitroll or damroll modifier is called on. The carry weight and wield weight are used, but the other modifiers arent as far as I can tell.
not sure if this is what you are talking about, but in my game i went through and added perm_hit to the character structure, so when i do bonus stuff i do the following:
void apply_hit_bonus( CHAR_DATA *ch )
{
int mod;
...loop through all types of bonuses, add/subtract from mod accordingly
ch->max_hit = ch->perm_hit + mod;
}
Okay, I think ive got something to work with, which is very similiar to what you're doing Dragonball, now my question is which source code file should I put this in? Seems like a dumnb question, but this is my first attempt at creating something new rather than modifying something already there.
handler.c:831: error: expected primary-expression before '[' token
Im not seeing what it is Im missing. I decided to try putting it in handler.c because I placed it right after the section that gets a character's str_app to calculate their carry weight. Ive already set the .hpbonus up in the attribute bonus structure in mud.h and the attribute bonus table in const.c
Well that is the format that is used for calling information from the attribute table in various other places so I thought it best to follow the same usage. However I did try replacing the [ ] with ( ) and this time I got the following:
handler.c: In function 'void abttribute_bonuses (CHAR_DATA*)':
handler.c:831: error: request for member 'hpbonus' in 'get_curr_con(ch)', which is of the non-class type 'short int'
now the hpbonus in mud.h is set as short, but the values only go from -200 to 200 so I dont think short was the wrong keyword, nonetheless i tried it again after changing 'short' to 'int' and got the same error
Well that is the format that is used for calling information from the attribute table in various other places so I thought it best to follow the same usage.
I am not familiar with that syntax in C or C++. Can you give an example of where you saw that?
Its actually right after this that I tried to put my code for the hp bonus. Ive seen several other examples of this in the stock code (which is SmaugFUSS 1.8). The only other one I can think of offhand was in update.c where the wis_app[get_curr_wis( ch )].practice is used to add the right amount of new practice sessions on level gain.
Okay so that allowed it to compile, though I tried it out using a test object and no luck, increasing my CON isnt increasing my max_hit. Though if I adjust the test object to give +hit, then it works. So Im going to track down the APPLY_HIT that comes from the object affects list and try to see how it works.
But my next question is, is handler.c the right source file to even be putting this snippet in? Or does it even really matter? I still havent gotten a good grounding as to which source files are doing what, alot of the code for doing anything in particular seems like its spread over three or four source files.
My other thought was maybe to put the snippet in update.c where the game would be continually checking different aspects of the character, so one of the things it could be updating is the current attributes and what bonuses they should be getting.
It doesn't matter as far as functionality is concerned. It matters only insofar as stuff is easy to find when you need to change it. So, putting it into act_comm.c might not be the best place. :-)
You know, the effects system in SMAUG kind of scares me; it's kind of hackish at points and isn't good about keeping backups (it works directly on the variables, so if it makes a mistake, you just lost data forever). You're pretty courageous to be working on this problem early on. :)
yeah i got tired of having to restore players due to a crash while they were being affected by a hit affect thats why i went the route of adding the third variable that is not modified by affects.
Hrmm. Advice duly noted. Maybe I am jumping the gun a bit, I wanted to do the attributes rather early because as you can tell my game design is very attribute-centered when it comes to the balance of whether one max leveled character will defeat another in pvp. Also, knowing ahead of time what attributes are doing helps me in race creation when it comes to which races should get pluses or negatives to which attributes.
If you want to follow this route, I strongly suggest you do what Gohan did. Spend a little time overhauling the system a bit, and add 'permanent' attributes. Those never got modified by the effect system. That way, if worse comes to worse and something does happen (which unfortunately always happens... sigh) you have a record of what the character's actual stats are.
Well the game does keep track a character's permanent attributes (STR, INT, etc) correct? Thats how they are displayed on the stock do_score output anyway. All Id have to do is put in something to keep track of the character's permanent hit, mana, move, etc right?
Alright Im gonna go through and see how it has the ones with permanent statistics already set up and see if i can use that as a template. Thanks everyone.
Personally, I didn't like the way attributes and skill levels were modified directly by the affects, so I pretty much castrated the affect modifying functions that added and subtracted directly from player file fields. I decided to make new functions that dynamically tally and calculate the applies on any given attribute whenever a call is made to them (which I called get_apply). I suppose storing it in the pfile was, at one point in computer history, a faster way to access them, but really with computer processors of today, just let them do a little math.
I also replaced the max_hit value with perm_hit, similar to suggestions here, to keep the total exp as a character gains level, THEN, I made another int function, get_max_hit, which dynamically tracks the current maximum hitpoints a character has.
This is an example, which you can't directly cut and paste, because there are more new functions (like a macro for calling the stat_app tables) and fields I've placed in my mods. But you could adapt if you wanted. I'm not claiming it to be the cleanest or the best, but it works :)
Note in my get_apply functions, I wanted the rules of the game to make the same apply NOT stack bonuses, so the results below only return the highest bonus. If you wanted to stack the bonuses original Smaug style, you would ditch the if (paf->modifier < mod) bits, and change the "=" in "put mod = paf->modifier;" to a "+="
int get_apply_minus(CHAR_DATA * ch, int apply)
{
OBJ_DATA *obj;
AFFECT_DATA *paf;
int mod = 0;
for (obj = ch->first_carrying ; obj ; obj = obj->next_content)
{
if (obj->wear_loc != WEAR_NONE)
{
for (paf = obj->first_affect ; paf ; paf = paf->next)
{
if (paf->location == apply)
{
if (paf->modifier < mod)
mod = paf->modifier;
}
}
for (paf = obj->pIndexData->first_affect ; paf ; paf = paf->next)
{
if (paf->location == apply)
{
if (paf->modifier < mod)
mod = paf->modifier;
}
}
}
}
for (paf = ch->first_affect ; paf ; paf = paf->next)
{
if (paf->location == apply)
{
if (paf->modifier < mod)
mod = paf->modifier;
}
}
return (mod);
}
And if you want the hitpoint bonus to show immediately after adding the item or spell, simply place a bit in the wear command or the spell code, before the item goes on or affect gets applied, to find the difference between your current and max_hit, then after the apply, another bit to make the character's current hit = get_max_hit(ch) - the difference.
another bit in affect_strip to compare the current hitpoints with get_max_hit and level it off will make sure that the character doesn't go around with extra hit points after the apply goes away.
You could avoid looping all the stuff twice by having the function "return" results by storing them in pointers passed in as arguments.
What I would do if I were unlazy enough to implement this would be to have a caching of sorts. This information doesn't change [i]that[/i] often, so it's worthwhile to not loop over the entire equipment and effect lists every time you need to look up a player's attributes. Instead, I would have it compute it when it needs it, and then store it away in a cache; if the equipment or effects change, invalidate the whole cache (or just relevant cache items) and compute things again the next time you need them.
Basically, it would be quicker and less looping to make new fields in the pfile that would store the get_apply tally -- in my case, probably an array, since I have round about 130 apply locations (so for example, say ch->apply[MAX_APPLY]).
Then whenever affect_modify is called it runs the tally in get_apply, and stores it in the new pfile field. Then I would call from the pfile instead of the loop. For example, "get_curr_str" will call on ch->apply[APPLY_STR] instead of the get_apply loop.
Yup, exactly. Create an array big enough to store the total for each tally type, and then whenever something changes (like equipment going on or off, a spell cast, etc.) recompute all of the tallies (or if you want to be smart, just the relevant tallies). This way, you will do the loop on the relatively rare event of a change, and have a one-step process for finding the tally on the relatively frequent case of needing one of the values.
Done. Added the array, then put calls to get_apply in affect_modify for only the location of the affect, recording it in ch->affect[location], then replacing all the other calls to get_apply in other functions was a fairly painless find/replace operation.
While I was at it, I added a bit to calculate, then add the applicable stat bonuses before and after the actual call to get_apply, so it now adds or removes the temporary bonuses (like hitpoints, move points, etc) also into affect modify, so I was able to take the calls to adjust these out of the spells and equip and unequip char.
I see about 30-40 usec difference in typing "score" which calls on all the get_curr_<everything>'s. But that should add up with multiple players doing multiple things that make calls on multiple applies.