IMarv's Charactersheet and Format

Show off your RPG maps, campaigns, and tokens. Share your gaming experiences and stories under General Discussion and save this forum for things you've created that may help others run their own games. Use the subforums when appropriate.

Moderators: dorpond, trevor, Azhrei, Gamerdude

Post Reply
User avatar
IMarvinTPA
Dragon
Posts: 467
Joined: Mon Sep 11, 2006 10:12 am
Contact:

IMarv's Charactersheet and Format

Post by IMarvinTPA »

On my website, I have a character creation tool.
I have one character sheet view so far, but I do intend on adding at least one more when I have time (Paizo stat block style, maybe classic 3.5 char sheet after that).
Normal Character sheet: http://prpg.imarvintpa.com/ACharacter.php?ID=8
Data structures used to build it: http://prpg.imarvintpa.com/RawCharacter.php?ID=8

The structure is a specialized key-value pair type thing where the value is a delayed calculation until after everything is done being added.
The critical properties of the object are a "Attribute flag", CachedValue and an array of source objects. The Attribute flag is used because I gave the same name to the Int total as the Int Bonus and the flag gives them a different behavior than the the other values. By default for attribues, you get the bonus when looking up its value where is other variables you get the value..

Each source object has a "Type", CachedValue, ModType, Expression, ConditionExpression, and a SourceID. The type is a DnD Bonus Type for stacking rules. The CachedValue is the total previously calculated for performance. You must/should clear all cached values in the whole structure to recalculate. Modifier Types are Mod, Pen, Bon, Ceiling, and Floor. Mods are normal modifiers, Pens are 0 or less, Bons are 0 or higher, Ceiling gives the variable a maximum value cap, and Floor gives the variable a minimum value limit. Penalties stack differently from Mods and Bons.

The math symbols processed are ()^*/%+- and conditionals are <, >, >=, <=, =, ==, !=, and Booleans &&, ||.
Conditionals and Booleans return 0 or 1 values which can be used as part of the value expression. The carat is an exponent and % is modulo.
Sample JSON:

Code: Select all

{"Name":"FORT","VariableType":"Normal","CacheValue":"2"
,"Derivation":[{"BonusType":"Base","CacheValue":"1"
,"ModifierType":"Mod","CacheConditionResult":"1"
,"Expression":"1","Condition":"1","SourceId":"Base"}
,{"BonusType":"Ability","CacheValue":"1"
,"ModifierType":"Mod","CacheConditionResult":"Yes"
,"Expression":"CON","Condition":"1","SourceId":"CON"}
,{"BonusType":"Racial","CacheValue":"0"
,"ModifierType":"Mod","CacheConditionResult":"No"
,"Expression":"2","Condition":"EFFECT_ENCHANTMENT"
,"SourceId":"Ability:Situational Save Modifiers (Enchantment)"}]}
All variables live at the same scope to easily reference each other. If a variable is missing, its value is 0. This allows leaving hooks that can seek a value when something is present but not go crazy if it is not. Frequently used for weapon proficiencies.

To get a particular variable's value for a bonus type, use a dot notation. FORT.ABILITY would fetch Ability's contribution to Fort (this ignores the ceiling and floor). Again, defaults to 0 if not found.

There are Prefix semi-functions which are separated by a colon:
P:Fort would return 0 if Fort is higher than 0 or the current value for the fortitude save penalty. More likely used on an attribute.

T for Total (Used with Attributes to get the actual value.)
R is a synonym for .Ranks or .Base
ABS returns absolute value.
Bool returns 0 or 1 from a number
NBool returns 1 or 0 from a number
B is a bonus Max(value, 0)
P is a penalty Min(value, 0)
Resize is a function caller that is used to resize the dice expression that comes with it.
Anything else returns the modifier value.

More later,
IMarv

PS, I'm trying to figure out whether to implement similar logic in a a lib token or convert the elements to work in the properties values.

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Re: IMarv's Charactersheet and Format

Post by Azhrei »

That all sounds like good stuff. :)

I presume variables names are not case-sensitive?

In the implementation you might consider throwing a warning message when attempting to access a variable that doesn't exist for debugging purposes. That will make it easier to find typos and such.

It might be useful to have a "Description" field for each variable so that the variable name "FORT" can be displayed as "Fortitude" in the user interface.

You could certainly implement this in a Lib: token in MT. If you want a more dynamic token, then doing the math on the fly in MT is the way to go. If you're willing to do the number crunching outside of MT and just import the results you'd obviously have a much faster token to work with in MT.

CharTool must be doing a lot of this already (all of it?) but I don't know anything about the internals of CT. Back when I had Java 5 I wasn't able to use CT (very easily) and now that I've got J6 I'm too busy with other stuff to investigate it. :| One of the things about CT that I recall is that it has an export module that allows you to define which values get stored into which token properties. So a single character can be exported to different frameworks and the correct properties are populated...

Overall this sounds like a fun project. :)

User avatar
IMarvinTPA
Dragon
Posts: 467
Joined: Mon Sep 11, 2006 10:12 am
Contact:

Re: IMarv's Charactersheet and Format

Post by IMarvinTPA »

variables are even better than not case sensitive:

Code: Select all

	function parenscores($str) {
		$str = Replace($str, " (", "_");
		$str = Replace($str, "(", "_");
		$str = Replace($str, ")", "_");
		$str = Replace($str, " [", "_");
		$str = Replace($str, "[", "_");
		$str = Replace($str, "]", "_");
		$str = Replace($str, " ", "_");

		//Math
		$str = Replace($str, "-", "_");
		$str = Replace($str, "+", "_");
		$str = Replace($str, "*", "_");
		$str = Replace($str, "/", "_");
		
		//Logic
		$str = Replace($str, "=", "_");
		$str = Replace($str, "<", "_");
		$str = Replace($str, ">", "_");
		$str = Replace($str, "&", "_");
		$str = Replace($str, "|", "_");
		$str = Replace($str, "!", "_");
		
		//Internal
		$str = Replace($str, ":", "_");

		//Cleanup
		while (instr($str, '__') > 0)
			$str = Replace($str, "__", "_");
		
		if (Right($str, 1) == '_') {
			$str = Left($str, Len($str) - 1);
		}

		if (Left($str, 1) == '_') {
			$str = Mid($str, 2);
		}

		return ucase($str);
	}
If it is looking at something that should be a variable name only, it converts most non alpha-numerics to underscores and consolidates the underscores to 1 per series and removes any leading or trailing underscores. As well as making it upper case.

This is so occurrences of knowledge [arcana] get turned into knowledge_arcana.

I actually do have an error property in my implementation that does just that, but I tend to ignore it...

Descriptions are handled out-of-scope with the variables since they are intended to solve DnD math. The description for them lives with the thing that created it. (I may try to figure out how to get them to fit in later though, but I didn't think hard enough on that when I started.)

I'm wondering how the caching would work work in MT since I don't know if you can pass a JSON by reference... My website is calculating them and populating the cache values, so that's practically done. On the flip side, I'd like dynamic things in MT to adjust those properly so I'd like it to work in both places.

I've been working on it for years off-and-on. Mostly when I'm playing in a game.

IMarv

User avatar
IMarvinTPA
Dragon
Posts: 467
Joined: Mon Sep 11, 2006 10:12 am
Contact:

Re: IMarv's Charactersheet and Format

Post by IMarvinTPA »

Moved from another thread.
Azhrei wrote:
IMarvinTPA wrote:Natural Armor and Natural are two different bonus types. The former does not stack, the latter does.
I can see we'd have to discuss this one in more detail. ;)
I may also be confusing Natural with Racial. I don't think I have a "Natural" bonus in my data set so far. Natural Armor is a strange beast since it is also a variable that can be heavily modified. I also have a type of "NoStackBase" which is treated as a base in all ways except each one does not stack with another. (There is no way to SET a variable to a value and discard all other modifiers.)
Azhrei wrote:
They don't need to be sorted, you create a bin for each bonus type and if the current value is less, replace it with the higher one. If they stack, add instead. Penalties reverse the logic in smaller values win and usually stack...
Your technique will work, of course, but keeping them sorted means a little extra overhead when modifying the arrays (the time required to search through the array and insert the new value in the correct place) and a LOT faster lookup when reading the array (since all non-negative values can be skipped it means the entire array doesn't need to be processed so less iterations through the loop). Given that reads are done much more often than writes it should be a huge win to keep them sorted. At least, if you're going to use this at the game table. If this is all pre-game setup then maximum performance isn't that much of an issue (but why not do it anyway?).
I try to cache calculated values to speed up re-reads. If a write is performed, a reset of all cached values would be needed. (Or smarter if quickly can find just the affected values.)
Hmm, I think I know where I would cache them now in MT, and it isn't where I thought it would be.
(SetProperty("cache.Property", val))
(SetProperty("cache.Property.BonusType", BonusVal))
and not in the JSON itself at all. Walk the JSON to clear them or walk the entire getPropertyNames and clear all of the cache.*.
Azhrei wrote: Given that the modsets in the current FW are changed maybe once per round per token in a level 8+ game, I would estimate that the read-to-write ratio must be somewhere around 12:1 in such a game. That includes mouseovers to see the AC values, calculating weapon attacks, applying damage and incorporating DR/ER, and so on.
If you have a chance, I made a nice table out of the variables to help see the effect.
IMarv
I'd be happy to look at it. I replied to other post as well -- looks good. :)

DMGenie implemented something like this a few years ago (wow, that long?) and PC-Gen too, of course. The PC-Gen formulas as stored in the LST files are a bit cumbersome to read/write, but they do work. You could perhaps extract the data from the LST files and build your own database in JSON form. That would give you the weapon, armor, and similar items pretty quickly I would think. :)

I mentioned DMGenie since it has the stacking rules well implemented and with some nice touches. For example, the stacking types are user-editable so that the GM can create new ones on the fly if needed. And the modifier value can be input as a string in which case it's read as another property name on the creature. This allows the property to be modified elsewhere in the code, such as in the Power Attack feat that when activated modifies the AB and DmgBonus.

One thing that DMGenie didn't do for a long time was a modifier for spell slot manipulation (so it was tough to do the Enervation spell, for example). Caster Level is another one that isn't obvious, but spells like Death Knell and the Incense of Meditation affect it. There was another one too, but I don't recall right now. (Maybe it was Spell Penetration?)
Those modifiers is somewhere I hit early. Some of the data is stored in my normalized database for the items, etc. I also have a table that defines bonuses.
Name, Selection, Expression, Type, Condition, Notes
The actual name is "Name (Selection)" when it processes it, but it helps visually manage it.
It would be nice to see if I can convert either of those data sets into my database though. Currently, I add what I need when I need it... Bard 1-5 was a pain.

IMarv

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Re: IMarv's Charactersheet and Format

Post by Azhrei »

I'll try to cover these in the order you put them in the last two posts.

Not sure why you're using multiple calls to a Replace() function. This looks like JS code and you can just create a regex object and use regular expressions. I'd have to look up the specific syntax 'cuz I can never remember it, but it's something like...

Code: Select all

var $str = "Knowledge (Arcana)"
var pattern = new RegExpr("/ ?[][()]+/g")
$str = $str.replace(pattern, "_") 
There are no JSON references in MT since the JSON only exists as a JSON object while it's being manipulated. Once you store it into a token property it is "exported" as a string. The next time you read the property it will be converted back into a JSON object. (This will change in 1.4; token properties will be any primitive JS type most likely. We have finished working out the details yet.) This means it's best to not store large, multi-nested JSONs in token properties in MT 1.3 if you're going to read/write them frequently. Your cache idea of using property names with dots in them is a good one. (As an aside it would be really cool if MT's scripting language implemented such dotted property names as stems like REXX does, but that's not going to happen. ;))

There is only a single natural armor bonus and it's called Natural Armor. There are enhancement bonuses, racial bonuses, and other types of bonuses to NA but they all affect the single value. (Note that it's murky because many of the feat and spell descriptions from PF were copied from D&D3.x and they didn't clean up the language, so some spells might say that they provide a "bonus to NA" or a "bonus of NA" or even "+X NA" and not say whether they are enhancement or racial. I have house ruled that spells like FotD provide a racial bonus so it doesn't stack with any existing racial bonus.)

User avatar
IMarvinTPA
Dragon
Posts: 467
Joined: Mon Sep 11, 2006 10:12 am
Contact:

Re: IMarv's Charactersheet and Format

Post by IMarvinTPA »

Azhrei wrote:I'll try to cover these in the order you put them in the last two posts.

Not sure why you're using multiple calls to a Replace() function. This looks like JS code and you can just create a regex object and use regular expressions. I'd have to look up the specific syntax 'cuz I can never remember it, but it's something like...

Code: Select all

var $str = "Knowledge (Arcana)"
var pattern = new RegExpr("/ ?[][()]+/g")
$str = $str.replace(pattern, "_") 
It is actually Bastardized PHP by creating VBScript function names that wrap PHP calls. I'm not good with regex, so I do things that stay clear to me. I had created a script to convert the ASP pages into PHP pages and the function wrappers were an easy way to help that along.

IMarv

User avatar
IMarvinTPA
Dragon
Posts: 467
Joined: Mon Sep 11, 2006 10:12 am
Contact:

Re: IMarv's Charactersheet and Format

Post by IMarvinTPA »

Azhrei wrote: There is only a single natural armor bonus and it's called Natural Armor. There are enhancement bonuses, racial bonuses, and other types of bonuses to NA but they all affect the single value. (Note that it's murky because many of the feat and spell descriptions from PF were copied from D&D3.x and they didn't clean up the language, so some spells might say that they provide a "bonus to NA" or a "bonus of NA" or even "+X NA" and not say whether they are enhancement or racial. I have house ruled that spells like FotD provide a racial bonus so it doesn't stack with any existing racial bonus.)
There is a Natural Armor Bonus variable that gets the base value and any modifiers in my system. Then that variable is added to AC as a "Natural Armor" bonus type.

Racial bonuses stack. http://www.d20pfsrd.com/basics-ability- ... #TOC-Bonus
The important aspect of bonus types is that two bonuses of the same type don't generally stack. With the exception of dodge bonuses, most circumstance bonuses, and racial bonuses, only the better bonus of a given type works. Bonuses without a type always stack, unless they are from the same source.
IMarv

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Re: IMarv's Charactersheet and Format

Post by Azhrei »

IMarvinTPA wrote:Racial bonuses stack. http://www.d20pfsrd.com/basics-ability- ... #TOC-Bonus
The important aspect of bonus types is that two bonuses of the same type don't generally stack. With the exception of dodge bonuses, most circumstance bonuses, and racial bonuses, only the better bonus of a given type works. Bonuses without a type always stack, unless they are from the same source.
Yeah, that's badly worded at best and just plain *wrong* at worst. If I have two racial bonuses to Stealth, for example, they don't stack. I don't know how you'd get two bonuses except via a spell, but it doesn't matter -- you only get the better one. Treat the word "racial" just like the word "enhancement" and ignore the paragraph you quoted because it makes it look like ALL racial modifiers stack and they don't.

Check out this post and the one right below it on Paizo's forums for a discussion of this. The one I linked to quotes the PFSRD (not the d20pfsrd.org site, but the actual Paizo-maintained SRD). In particular, Patryn has it right and does a pretty good job of explaining it. He's got it spelled out in his first post at the top of the thread, but some of the variables haven't been discussed at that point so his post is incomplete.

There's also this thread that I created to specifically discuss the badly worded Form of the Dragon spell (or at least, badly worded IMO). I posted again on Oct 30th about how various items might stack (class abilities, racial abilities, spell effect, magic item effect) but it's not quite as germane to our discussion here.

And yes, it's confusing. And they could've done a better job of defining it. But it is what it is. :roll:

User avatar
IMarvinTPA
Dragon
Posts: 467
Joined: Mon Sep 11, 2006 10:12 am
Contact:

Re: IMarv's Charactersheet and Format

Post by IMarvinTPA »

I find that a lot of things have an unnamed but not "unnamed" bonus value which I call "Base." These just are the value they are. A suit of armor has an Armor Bonus of 4, but where did that 4 come from? It is the Base for Armor Bonus.

Natural Armor should not use Base but "NoStackBase" if multiple sources attempt to grant it to allow only the best one to be used. Sometimes I use the word Inherent in my mind.

"Base" is my bonus type word for "the rules said so."

IMarv

Telarus
Giant
Posts: 129
Joined: Sat May 22, 2010 11:16 pm

Re: IMarv's Charactersheet and Format

Post by Telarus »

Nice, I'm also going to be using dot syntax to break up having to nest JSONs. Good to see I'm not the only one with the idea..

User avatar
IMarvinTPA
Dragon
Posts: 467
Joined: Mon Sep 11, 2006 10:12 am
Contact:

Re: IMarv's Charactersheet and Format

Post by IMarvinTPA »

Telarus wrote:Nice, I'm also going to be using dot syntax to break up having to nest JSONs. Good to see I'm not the only one with the idea..
I saw a campaign properties profile that had a dot in two of the entries. I'm knee deep in underscores with my names that I couldn't justify using them more and find dots available as an alternative option.

IMarv

Post Reply

Return to “User Creations”