Author Topic: Enchanted Cloak Value?  (Read 470 times)

Legacy_BelowTheBelt

  • Hero Member
  • *****
  • Posts: 699
  • Karma: +0/-0
Enchanted Cloak Value?
« on: December 16, 2012, 09:48:33 pm »


               Cloaks come in many varieties and I"m trying to find a simple way to identify whether a cloak is 'enchanted' and if so, what the value of the enchantment is.

I presume, that some lookup against the item property cost table 2da is warranted, but not sure how to go about this exactly.  Any thoughts?

Thanks!
               
               

               
            

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #1 on: December 21, 2012, 05:04:29 am »


               I noticed no one helped you well fortunately for you I've been working on "highv's ultimate drops system" where I did -extensive- research of nwn's item value calculations and property points. I was planning to post it to IGNVault, but I am still working on the item limitation specifications in each struct.(which allows mods to specify the RANGE of properties for each item and I consider very important to be an ultimate drops system) Anyway... To calculate the degree of value for a cloak it's:


[(base) + 1000((multiplierxmodifier)^2)]x(base item multiplier)

Base is located in the baseitems.2da file and base item multiplier is located next to the stack size. To make your life easier....

Cloak Base Cost = 1.0
Cloak Item Multiplier = 1.0

If no modifier is listed here then it's just the amount
on it. (so +6 charisma is a modifier of 6)

Thus If a cloak has +6 charisma then it has [(1.0) + 1000(1.2x6)^2]x1.0 = 51,841

ability bonus math multiplier = 1.2

AC Bonus(normal) multiplier = 0.9

AC Bonus(normal) modifier level +1 = 0.9

AC Bonus(normal) modifier level +2 = 1.9

AC Bonus(normal) modifier level +3 = 2.9

AC Bonus(normal) modifier level +4 = 3.9

AC Bonus(normal) modifier level +5 = 4.9

AC Bonus(normal) modifier level +6 = 8.5

AC Bonus(normal) modifier level +7 = 11.0

AC Bonus(normal) modifier level +8 = 14.0

AC Bonus(normal) modifier level +9 = 16.0

AC Bonus(normal) modifier level +10 = 26.0

AC Bonus(normal) modifier level +11 = 30.0

AC Bonus(normal) modifier level +12 = 34.0

AC Bonus(normal) modifier level +13 = 38.0

AC Bonus(normal) modifier level +14 = 42.0

AC Bonus(normal) modifier level +15 = 44.0

AC Bonus(normal) modifier level +16 = 46.0

AC Bonus(normal) modifier level +17 = 50.0

AC Bonus(normal) modifier level +18 = 54.0

AC Bonus(normal) modifier level +19 = 58.0

AC Bonus(normal) modifier level +20 = 62.0

AC Bonus(misc groups) multiplier = 0.5

For alignment group, damage type, and racial group the
multiplier is .5 and the modifier is the normal AC mod.

For alignment specific the mutliplier = 0.3

Weight Reduction Multiplier = 1.0

Weight Reduction Modifier 80% = 0.1

Weight Reduction Modifier 60% = 0.2

Weight Reduction Modifier 40% = 0.3

Weight Reduction Modifier 20% = 0.5

Weight Reduction Modifier 10% = 1.0

Bonus Spell Slot Multiplier = 0.5

Spell Level 0(cantrips) Modifier = 0.25

Spell Level 1 Modifier = 0.8

Spell Level 2 Modifier = 1.25

Spell Level 3 Modifier = 1.75

Spell Level 4 Modifier = 2.5

Spell Level 5 Modifier = 3.0

Spell Level 6 Modifier = 3.5

Spell Level 7 Modifier = 4.0

Spell Level 8 Modifier = 4.5

Spell Level 9 Modifier = 5.5

All soaking returns the same for amount:
+1 DR = 1.25

+2 DR = 1.75

+3 DR = 2.25

+4 DR = 2.5

+5 DR = 2.75

+6 DR = 4.0

+7 DR = 5.0

+8 DR = 6.0

+9 DR = 7.0

+10 DR = 8.0

Amount of soaking(this is multiplied into the DRs)

5 Soak = 2.0

10 Soak = 2.4

15 Soak = 2.8

20 Soak = 3.2

25 Soak = 3.6

30 Soak = 4.0

35 Soak = 5.0

40 Soak = 6.0

45 Soak = 7.0

50 Soak = 8.0

Darkvision = 1.0(literally just that)

Haste = 3.5(only)

Light Multiplier = 1.0

Light Modifier 5M Distance = 0.2

Light Modifier 10M Distance = 0.3

Light Modifier 15M Distance = 0.4

Light Modifier 20M Distance = 0.5

Regeneration Multiplier = 2.0
Uses same modifier as AC(normal)

Universal Saving Throw Bonus Multiplier = 1.25
Uses same modifier as AC(normal)

Acid Saving Throw Bonus Multiplier = 0.4
Uses same modifier as AC(normal)

Cold Saving Throw Bonus Multiplier = 0.4
Uses same modifier as AC(normal)

Death Saving Throw Bonus Multiplier = 0.75
Uses same modifier as AC(normal)

Disease Saving Throw Bonus Multiplier = 0.5
Uses same modifier as AC(normal)

Divine Saving Throw Bonus Multiplier = 0.4
Uses same modifier as AC(normal)

Electrical Saving Throw Bonus Multiplier = 0.4
Uses same modifier as AC(normal)

Fear Saving Throw Bonus Multiplier = 0.4
Uses same modifier as AC(normal)

Fire Saving Throw Bonus Multiplier = 0.5
Uses same modifier as AC(normal)

Mind Affecting Saving Throw Bonus Multiplier = 0.75
Uses same modifier as AC(normal)

Negative Saving Throw Bonus Multiplier = 0.75
Uses same modifier as AC(normal)

Poison Saving Throw Bonus Multiplier = 0.5
Uses same modifier as AC(normal)

Positive Saving Throw Bonus Multiplier = 0.4
Uses same modifier as AC(normal)

Sonic Saving Throw Bonus Multiplier = 0.4
Uses same modifier as AC(normal)

Specific Saving Throw Bonus Multiplier = 0.65
Uses same modifier as AC(normal)

Skill Bonus Multiplier = 0.12

Skill Bonus Modifier +1 = 1.0

Skill Bonus Modifier +2 = 2.0

Skill Bonus Modifier +3 = 3.0

Skill Bonus Modifier +4 = 4.0

Skill Bonus Modifier +5 = 5.0

Skill Bonus Modifier +6 = 6.0

Skill Bonus Modifier +7 = 7.0

Skill Bonus Modifier +8 = 8.0

Skill Bonus Modifier +9 = 9.0

Skill Bonus Modifier +10 = 10.0

Skill Bonus Modifier +11 = 12.0

Skill Bonus Modifier +12 = 14.0

Skill Bonus Modifier +13 = 16.0

Skill Bonus Modifier +14 = 18.0

Skill Bonus Modifier +15 = 20.0

Skill Bonus Modifier +16 = 22.0

Skill Bonus Modifier +17 = 24.0

Skill Bonus Modifier +18 = 26.0

Skill Bonus Modifier +19 = 28.0

Skill Bonus Modifier +20 = 30.0

Skill Bonus Modifier +21 = 32.0

Skill Bonus Modifier +22 = 34.0

Skill Bonus Modifier +23 = 36.0

Skill Bonus Modifier +24 = 38.0

Skill Bonus Modifier +25 = 40.0

Skill Bonus Modifier +26 = 42.0

Skill Bonus Modifier +27 = 44.0

Skill Bonus Modifier +28 = 46.0

Skill Bonus Modifier +29 = 48.0

Skill Bonus Modifier +30 = 50.0

Skill Bonus Modifier +31 = 52.0

Skill Bonus Modifier +32 = 54.0

Skill Bonus Modifier +33 = 56.0

Skill Bonus Modifier +34 = 58.0

Skill Bonus Modifier +35 = 60.0

Skill Bonus Modifier +36 = 64.0

Skill Bonus Modifier +37 = 68.0

Skill Bonus Modifier +38 = 72.0

Skill Bonus Modifier +39 = 76.0

Skill Bonus Modifier +40 = 80.0

Skill Bonus Modifier +41 = 84.0

Skill Bonus Modifier +42 = 88.0

Skill Bonus Modifier +43 = 92.0

Skill Bonus Modifier +44 = 96.0

Skill Bonus Modifier +45 = 100.0

Skill Bonus Modifier +46 = 110.0

Skill Bonus Modifier +47 = 120.0

Skill Bonus Modifier +48 = 130.0

Skill Bonus Modifier +49 = 140.0

Skill Bonus Modifier +50 = 150.0

Freedom Multiplier = 4.0

Damage Immunity Multiplier = 2.3

Damage Immunity Modifier 5% = 0.5

Damage Immunity Modifier 10% = 1.0

Damage Immunity Modifier 25% = 1.5

Damage Immunity Modifier 50% = 2.25

Damage Immunity Modifier 75% = 3.0

Damage Immunity Modifier 90% = 4.0

Damage Immunity Modifier 100% = 5.0

Immunity to Sneak Attack = 8.0(only)

Immunity to Drain = 1.5(only)

Immunity to Mindspells = 3.0(only)

Immunity to Poison = 1.0(only)

Immunity to Disease = 1.0(only)

Immunity to Fear = 1.0(only)

Immunity to Knockdown = 0.75(only)

Immunity to Paralysis = 3.0(only)

Immunity to Critical Hits = 10.0(only)

Immunity to Death Magic = 3.5(only)

Immunity to Spell School = 6.1(only)

Immunity Spell Level Multiplier = 1.2

Immunity Spell Level Modifier Level 1 = 4.0

Immunity Spell Level Modifier Level 2 = 5.0

Immunity Spell Level Modifier Level 3 = 6.0

Immunity Spell Level Modifier Level 4 = 7.0

Immunity Spell Level Modifier Level 5 = 8.0

Immunity Spell Level Modifier Level 6 = 9.0

Immunity Spell Level Modifier Level 7 = 11.0

Immunity spell Level Modifier Level 8 = 13.0

Immunity Spell Level Modifier Level 9 = 15.0

Improved Evasion = 3.0(only)

Spell Resistance Multiplier = 2.0

Spell Resistance Modifier 10 = 0.35

Spell Resistance Modifier 12 = 0.65

Spell Resistance Modifier 14 = 1.0

Spell Resistance Modifier 16 = 1.5

Spell Resistance Modifier 18 = 2.75

Spell Resistance Modifier 20 = 4.5

Spell Resistance Modifier 22 = 5.0

Spell Resistance Modifier 24 = 5.5

Spell Resistance Modifier 26 = 6.0

Spell Resistance Modifier 28 = 7.0

Spell Resistance Modifier 30 = 8.0

Spell Resistance Modifier 32 = 9.0

True Seeing = 6.1(only)

I have a notepad on my computer with exact specifications of all nwn properties down to the T. If you need any more help determining item values just let me know.(I also have bazillions of notepads for tons of other things I declared as constants that may help in other situations, but I rarely share these as I do my best not to assist a**holes like Lysan with there mods and item values fortunately do not help him since his mod has strict item limitations).
               
               

               


                     Modifié par Highv Priest, 21 décembre 2012 - 05:16 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #2 on: December 21, 2012, 05:52:20 am »


               

BelowTheBelt wrote...

Cloaks come in many varieties and I"m trying to find a simple way to identify whether a cloak is 'enchanted' and if so, what the value of the enchantment is.

I presume, that some lookup against the item property cost table 2da is warranted, but not sure how to go about this exactly.  Any thoughts?

Thanks!


I think one of the reasons you have not gotten an answer is for one I am not sure what you are asking.  

by enchanted do you mean any item proptery added to the cloak?

by 'value of the enchantment'   do you mean GP value or level of enchantment.  

if you are talking GP value are you asking per  Item Prop Or all Item Props added together?


-------------------
@ Highv Priest

Your full formula is:
ItemCost = [BaseCost + 1000*(Multiplier^2 - NegMultiplier^2) + SpellCosts]*MaxStack*BaseMult + AdditionalCost

Where:
BaseMult = ItemMultiplier column value from baseitems.2da.
AdditionalCost = AddCost Field from the Item Struct.

Multiplier =  sum of the costs of all the Item Properties whose costs are positive.

where the value of each Item Prop is. 


ItemPropertyCost = PropertyCost + SubtypeCost + CostValue

For  there everything can be looked up with 2da calls.  No need for a bunch of  lists with Item costs.  

P.S.   I am going to be off line for about a week.  Ill check back in on this thread then.  
               
               

               
            

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #3 on: December 21, 2012, 10:41:07 pm »


               

Lightfoot8 wrote...
For  there everything can be looked up with 2da calls.  No need for a bunch of  lists with Item costs. 

EDIT = ItemPropertyCost = PropertyCost + SubtypeCost + CostValue 

ItemCost = [BaseCost + 1000*(Multiplier^2 - NegMultiplier^2) + SpellCosts]*MaxStack*BaseMult + AdditionalCost
 


EDIT = I forgot to mention your formula for item property cost is -wrong-. It's not PropertyCost + SubTypeCost. It's -multiplied-(and the same applies for CostValue).

+6 charisma only comes up valid for you because 6x1.2 = 6+1.2 trolololol

Lets try +6 AC....
[1.0 + 1000x([0.9x8.5]^2 - 0^2) + SpellCosts]x1.0x1.0+0 = 58,523

[1.0 +1000x([0.9+8.5]^2 - 0^2) + SpellCosts]x1.0x1.0+0 = 88,361

A simple check in toolset by adding +6 AC to a cloak and seeing item value will show you that you're -wrong-.

Using .2DA's in a -good- drops system is impossible. It would not only be a bad idea, but would make it easily a better idea to use a simpler system. For my system I took all data from the .2DA's and placed them into structs for quick retrieval(and easy editting). This way it's not necessary for -multiple- StringToFloat calls for -every- single item property placed or even calculated.....(multiple different stringtofloat calls is one of the most expensive things to do in nwn). If I CAN I avoid using expensive functions when possible.

Example = A player uses implosion to kill 15 spawns, if each spawn rolls this system and each spawn can create an item with 4 properties. That's 2-3 Get2DAString calls for each property which then convert to floats(because item value in nwn uses decimals) using StringToFloat. Then add on top of this that each item has to be created using CreatItemOnObject. Then further add on any further stipulations. The end result is you just used up a TON of CPU whereas with the properties already defined it uses up only minimal CPU performing calculations with already defined numbers. I have no idea why any jackass mod builder would use Get2DAString universally in scripts unless it changes by the minute,(which I guess makes sense since Set2DAString exists) because despite BioWare making Get2DAString not the lagfest it originally was, it's STILL not good to convert strings back to numbers. The only reason I've ever used Get2DAString is when I'm returning a -string-(or logging it to create a table or constant somewhere with it pre-defined).

I've tried using other drops systems in the past, but they either are just too simple or too expensive. So I'm building this one because a windows 95 computer could run it easily and at the same time it's the most openly advanced system of drops I've seen(right around the range of Borderlands or Diablo in item variety). The only expensive part of the system is creating the item on the creature to apply the properties too(and the degree of expensive is minimal since it's a blank weapon). The one flaw in my drops system is the lack of cast spell properties(which is why I never used the full formula), I didn't include maxstack size because it was irrelevant for a cloak and I've tried multiple times to see this negative property in action, but I don't think properties exist -yet- that reduce item value.
               
               

               


                     Modifié par Highv Priest, 21 décembre 2012 - 10:53 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #4 on: December 31, 2012, 06:44:18 pm »


               
Quote
Highv Priest wrote...

Quote
Lightfoot8 wrote...
For  there everything can be looked up with 2da calls.  No need for a bunch of  lists with Item costs. 

EDIT = ItemPropertyCost = PropertyCost + SubtypeCost + CostValue 

ItemCost = [BaseCost + 1000*(Multiplier^2 - NegMultiplier^2) + SpellCosts]*MaxStack*BaseMult + AdditionalCost
 


EDIT = I forgot to mention your formula for item property cost is -wrong-. It's not PropertyCost + SubTypeCost. It's -multiplied-(and the same applies for CostValue).


Ahh Yes,  I forgot that there was a error in the Bioware documentation for the ItemCost calculation.  But it is definitely not PropertyCost * SubTypeCost either.   One of the two values will always be 0.   If they where multipied the prop cost would always be 0.  ItemPropertyCost = (PropertyCost + SubtypeCost)  * CostValue, Is what I came up with that works.   Sorry for the haste I posted the above responce in. 
  
Quote

Using .2DA's in a -good- drops system is impossible...

I dissagree that it is Impossible,  I Also do not know who you are writing your system for.   If it is just for your own Server how you do it does not matter much.   If you are writting it as a system for other to use, 2DA reads is the best way to go.  This will make it so that the end user does not have to modify your scripts if they run with modified 2DA's 

It would not only be a bad idea, but would make it easily a better idea to use a simpler system. For my system I took all data from the .2DA's and placed them into structs for quick retrieval(and easy editting). This way it's not necessary for -multiple- StringToFloat calls for -every- single item property placed or even calculated.....(multiple different stringtofloat calls is one of the most expensive things to do in nwn). If I CAN I avoid using expensive functions when possible.[/quote]
Most expensive things?  Agreed I have not looked into the function much.  The only thing (Without looking) I can see being expensive,  Would be multipial memory allocations and FPU pushes if your computer has slow memory and cache speeds.   

...I have no idea why any jackass mod builder would use Get2DAString universally in scripts unless it changes by the minute,...[/quote]
There we go, It is official, I am a jackass.

Quote
(which I guess makes sense since Set2DAString exists) because despite BioWare making Get2DAString not the lagfest it originally was, it's STILL not good to convert strings back to numbers. The only reason I've ever used Get2DAString is when I'm returning a -string- (or logging it to create a table or constant somewhere with it pre-defined).

There you go.  Here is one option that makes the 2da reads not impossiable, Even if they are giving you problems on your win 95 system. You also do not have to build the cache the Table all at once.    

Quote
 ...I've tried multiple times to see this negative property in action, but I don't think properties exist -yet- that reduce item value.


In the default 2da's  all of the negative properties return 0 for both  PropertyCost  and  SubtypeCost making the property have a 0 value.    I have never tried making any of the negtive to see if that part of the formula ever made the engine.   Im guessing that it did but that they ended up having problems with negative item values and just edited the 2da's to make them all 0 instead of fixing the engine.


As a side Note: If you do have slow memory access speeds and you are freequently pushing more then 100 256 vars onto the VM stack, You could could speed up the way the VM handles your scripts by incressing the amount of memory the VM originally allocats for  the VM stack, by haking the server.   That is if you have the memory to burn.   When a new script chain is ran the VM only 256 dwords are allocated for the VM stack.   When that limit is reached it a new larger memory block is allocated and the old VM stack is copied to it,  The old VM stack is then deallocated.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #5 on: January 01, 2013, 12:26:48 am »


               I think what the OP is after is much simpler.


/* Return the base AC value of oItem (only valid for armor and shields). */
int GetItemACBase (object oItem);

/* Return the AC enhancement bonus of oItem. */
int GetItemACBonus (object oItem);


int GetItemACBase (object oItem) {
    if (!GetIsObjectValid(oItem))
        return 0;

    switch (GetBaseItemType(oItem)) {
        case BASE_ITEM_SMALLSHIELD:
            return 1;

        case BASE_ITEM_LARGESHIELD:
            return 2;

        case BASE_ITEM_TOWERSHIELD:
            return 3;

        case BASE_ITEM_ARMOR:
            break;

        default:
            return 0;
    }

    int bID = GetIdentified(oItem);

    SetIdentified(oItem, FALSE);

    int nBaseAC = 0;

    switch (GetGoldPieceValue(oItem)) {
        case 5:    nBaseAC = 1; break;  // Padded
        case 10:   nBaseAC = 2; break;  // Leather
        case 15:   nBaseAC = 3; break;  // Studded Leather / Hide
        case 100:  nBaseAC = 4; break;  // Chain Shirt / Scale Mail
        case 150:  nBaseAC = 5; break;  // Chainmail / Breastplate
        case 200:  nBaseAC = 6; break;  // Splint Mail / Banded Mail
        case 600:  nBaseAC = 7; break;  // Half Plate
        case 1500: nBaseAC = 8; break;  // Full Plate
    }

    SetIdentified(oItem, bID);

    return nBaseAC;
}

int GetItemACBonus (object oItem) {
    if (!GetIsObjectValid(oItem))
        return 0;

    int nBonusAC = GetItemACValue(oItem) - GetItemACBase(oItem);

    return nBonusAC;
}

We have other armor/ac related functions as well, should you need others (like ac type, for example).

Funky
               
               

               
            

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #6 on: January 01, 2013, 08:15:41 am »


               

Lightfoot8 wrote...

Ahh Yes,  I forgot that there was a error in the Bioware documentation for the ItemCost calculation.  But it is definitely not PropertyCost * SubTypeCost either.   One of the two values will always be 0.   If they where multipied the prop cost would always be 0.  ItemPropertyCost = (PropertyCost + SubtypeCost)  * CostValue, Is what I came up with that works.   Sorry for the haste I posted the above responce in.
  


No I followed the idea they were going with in there system. The reason it never comes up 0 is the way the engine handles the actual calculations. I actually used a disassembler to read the games engine calculation when I was first researching it. The game determines the to-be-squared value by first retrieving itempropdef.2da. If the Cost field is **** the game then defaults on the SubTypeResRef's Cost field and then finally it takes the value(whether from the normal Cost Field or the sub Cost Field) and multiplies it by the Cost Field in the CostTableResRef.
When a value of 0 is actually returned then it does infact multiply by 0 and makes it zero.

However the individual properties themselves aren't multiplied together, they are added before the system squares them.

So in our example +6 charisma and +6 AC.

+6 charisma = 1.2x6 = 7.2

+6 AC = 0.9x8.5 = 7.65

7.2+7.65 = 14.85

1.0 + (1,000x(14.85)^2) x1 = 220,523(toolset verifies this as accurate when tested on a cloak, the 1.0 is the basecost and the x1 is the item multiplier and technically it's also being multiplied by a stack of 1)

I dissagree that it is Impossible,  I Also do not know who you are writing your system for.   If it is just for your own Server how you do it does not matter much.   If you are writting it as a system for other to use, 2DA reads is the best way to go.  This will make it so that the end user does not have to modify your scripts if they run with modified 2DA's.


I made replacing the 2DA values into my system -very- easy. They simply just copy and paste any edit(only one time necessary). However you've swayed me(copy and pasting one time can still be a chore if you're editting a lot of 2DA's), as a result I added the option to use Get2DAString with a simple TRUE/FALSE switch in the beginning.
I'm writing the system for anyone who wants a universal drops system capable of creating any item on any module, it's easy to implement, efficient, and depending on how strictly you enforce item properties you can have item variety similar to Diablo 2 and Borderlands. Also I apologize for being annoyed, I didn't like you pointing out how my formula was wrong when I tested it and verified I was correct with 100% accuracy. In that situation I've learned from experience the only way you'll get the point across is to assert yourself.

Most expensive things?  Agreed I have not looked into the function much.  The only thing (Without looking) I can see being expensive,  Would be multipial memory allocations and FPU pushes if your computer has slow memory and cache speeds.


According to pretty much all information on this forum and and nwnx, any string conversion functions utilize a great deal of processing time(relative to microseconds that is). I tested this with the profiler a long time ago, but it was about 300 times(citing the first number that came to mind) the function was reaching close to a second or something along those lines. I may be able to find it later. The problem is you COULD reach 300 times using this system, it doesn't repeatedly loop but it will never exceed the item value cap level for your item.(thus preventing a level 41 item from spawning for a level 40 capped server unless you specified otherwise). To make certain it doesn't, the system calculates the value of each property it applies when it applies it and then subtracts this from the item value cap. Well here comes the kicker. Each property can have up to 3 different 2da's associated with it, each with it's own cost value, each requiring a stringtofloat call. When the value of a property exceeds the cap it will attempt to place the property 1 step below it and continue downward until it reaches no value for that property and just cancels placing the property entirely(resulting in that item being a little underpowered, but at least it's not breaching a cap and it TRIED to find a good property for it without looping endlessly trying to find something).
If you killed 15 spawns instantly and each item has 6 properties that's at least 90 times it's checking, but since it can be 3 2DA's that's a possible 270 Get2DAString and 270 StringToFloat calls(and since it can try to place the property 1 step below that's an additional +1 Get2DAString and StringToFloat, which is possible for every item property which can easily allow it to reach 300). Moreover the properties use A LOT of differeny 2DAs(I believe around 30) so you need to increase your cache to that amount just to avoid that issue.

Compare that whole mess with predefined numbers. The computer is reduced entirely to being a 32 bit calculator. It takes numbers it already knows, multiplies them, and determines from them whether to apply a property to an item. I believe when I script profiled it, the results were exceptionally better. Something akin to you being able to kill 50 spawns infinitely with no lag contribution arising from this script.

Thereotically the first option could be made more efficient by calculating item value at the end, but the issue is you may end up reducing the items value TOO much. Imagine the item has +6 enhancement and it's level 41 and the computer removes the +6 enhancement. The item is now somewhere near level 30...

You could check the value of all the properties you're removing to make it just right in terms of value, but in that instance it's hardly anymore efficient lol. Now you're looping through every items properties, using multiple function calls just to GET the properties values itself(getitempropertytype, getitempropertysubtype, getcosttablevalue...) and then determining the property values using Get2DAString and StringToFloat. That option may be -more- inefficient(depending on how efficient each of the getitem info functions are).

I wanted precision, efficiency, and variety.(all the things I deem make a good drops system) So that's what I made.

I'm not entirely certain what you mean by VM. My minor in programming/data structure is utilized for the purposes of bioinformatics(my major is biology). Despite me having a fairly comprehensive knowledge of working with compiler coding,(with nwn, Java(I don't know JavaScript though, I never had much use for website programming) C++, and Python) I don't know too much of how a computer's calculations work beyond that.

(which I guess makes sense since Set2DAString exists) because despite BioWare making Get2DAString not the lagfest it originally was, it's STILL not good to convert strings back to numbers. The only reason I've ever used Get2DAString is when I'm returning a -string- (or logging it to create a table or constant somewhere with it pre-defined).


               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #7 on: January 01, 2013, 09:22:16 am »


               VM stands for Virtual Machine.
NWScript is not compiled into Native Machine Code.  It is compiled into Code that can be ran by the VM.   Vars and other information that would normally in native code be pushed onto the stack, Are pushed into a array in memory allocated by the VM.

SkyWing has a good summery of the NWN compiled code at  : http://www.nynaeve.n...tation/ncs.html if you are interested.
               
               

               
            

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #8 on: January 01, 2013, 10:07:57 am »


               Wow I honestly had no idea BioWare was using a completely different ruleset then traditional programming. Most game companies take an existing ruleset and simply expand upon it or upgrade it as opposed to defining an entirely different ruleset altogether(the latter is expensive and takes more time). They defined there own ruleset and then made the human part of it similar to java/C++ just for the sake of allowing people with a good knowledge of those languages the capability of familiarity, combine that with the DEGREE of options for customizing nwn and I have gained a great deal of respect from BioWare today. They truly worked hard on nwn. I'd buy this game for $100 lol.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #9 on: January 01, 2013, 10:25:48 am »


               

Highv Priest wrote...

Using .2DA's in a -good- drops system is impossible. It would not only be a bad idea, but would make it easily a better idea to use a simpler system. For my system I took all data from the .2DA's and placed them into structs for quick retrieval(and easy editting). This way it's not necessary for -multiple- StringToFloat calls for -every- single item property placed or even calculated.....(multiple different stringtofloat calls is one of the most expensive things to do in nwn). If I CAN I avoid using expensive functions when possible.

Without wanting to stir the pot overmuch, it's probably worth mentioning that in some circumstances, 2da calls are screaming fast. I'm hardly a fan of 2das - as anyone who spent much time on the old boards surely knows. A bit before the 1.67 update, I did a series of test runs showing how terrible 2da performance was (this is before 1.67 massively improved caching, making them a far better option for data storage). At the prompting of a Biowarean, I ALSO did some additional test runs, including ones of small, cached 2das. In those runs, 2da reads actually outpaced GetLocal reads (and on objects with very low numbers of locals).

With the ability to increase the number of cached 2das, I converted the LL system to use 2da reads instead of massive structs, which I had initially selected for reasons similar to yours - speed and moddability. It's still pretty damn fast, though we later switched to an even faster method using NWNX reads for a number of calculations (acaos' GetIsFeatAvailable, for instance). They're really a darn fine option these days, even for the speed-obsessed like me. If you want to see some of the test runs, you can find them using the NWN Omnibus, under a thread titled 'Arrays?', though it looks like later portions of the thread, with the superfast 2da reads, were cut out by the reader.

And, on a tangential note, I also did an item prop system designed to be diablo-esque, though it wound up far more complex, since we had an added layer of non-vanilla itemprops to contend with, which required special treatment. We also added augments, D&D style - over a thousand of them, applied with augmenter items. After extensive experimentation, we went with MySQL, since it allowed us to do extensive and easily modifiable weighting of various item props, though that's not likely to be ideal for a system designed for public release, like yours. Of course, if you DO decide to have it require NWNX, you can then make use of the rediculously awesome ItemPropertyDirect function, which allows you to build itemprops with the 6 struct int values (pulled from various 2da tables), instead of the myriad different bioware functions, like so:

itemproperty ipRestrict = ItemPropertyDirect(il.i0, il.i1, il.i2, il.i3, il.i4, il.i5);

We also made EXTENSIVE use of string operations, without any problems in terms of load (we have a whole library we use like crazy - they're really not bad). I'm linking the scripts to the system for you to see - they aren't useable in another PW, or without the associated databases, but they may give you ideas or insights for your own system. You can find the scripts here. The specs for the database tables are here.

Hope some of that proves useful or informative.

Funky
               
               

               
            

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #10 on: January 01, 2013, 03:47:21 pm »


               

FunkySwerve wrote...

Without wanting to stir the pot overmuch, it's probably worth mentioning that in some circumstances, 2da calls are screaming fast. I'm hardly a fan of 2das - as anyone who spent much time on the old boards surely knows. A bit before the 1.67 update, I did a series of test runs showing how terrible 2da performance was (this is before 1.67 massively improved caching, making them a far better option for data storage). At the prompting of a Biowarean, I ALSO did some additional test runs, including ones of small, cached 2das. In those runs, 2da reads actually outpaced GetLocal reads (and on objects with very low numbers of locals).


Oh I'm not debating that .2DA calls are fast when it's just one, but the problem is item properties are calling multiple -different- 2DAs. That means it requires even more caching and this is even more so since it can't delete the previous cache as the system has to call them again if the value is exceeding it's limitation and it needs to read the next step below it.

I have a weapon on my server called "Enserric the Legendary!" that uses Get2DAString something like 7 times in the script because he effectively means "On hit cast random spell in the game", but it's mostly calling the same already cached 2DA.

I do NOT think Get2DAString is inefficient. I think it's inefficient when you're calling data from somewhere, converting it, and probably doing it over and over.

With the ability to increase the number of cached 2das, I converted the LL system to use 2da reads instead of massive structs, which I had initially selected for reasons similar to yours - speed and moddability. It's still pretty damn fast, though we later switched to an even faster method using NWNX reads for a number of calculations (acaos' GetIsFeatAvailable, for instance). They're really a darn fine option these days, even for the speed-obsessed like me. If you want to see some of the test runs, you can find them using the NWN Omnibus, under a thread titled 'Arrays?', though it looks like later portions of the thread, with the superfast 2da reads, were cut out by the reader.


I'd actually like to point out I'm using structs because of the constant limitation on the default compiler and because it makes editting a lot easier in general. Any person enjoying my works will tell you I always go over the top in my works and lag can result(which is why I do my best to reduce it). I'm inherently lazy, but I wanted to make certain ANYONE could use this system. Even the guy on a 256 mb RAM laptop. The NWNX stuff is cool, I use a lot of it. I use it for database, resetting, chat hooking, different functions, and otherwise. However since this is intended for -anyone- I can't have it relying on NWNX for the public release.(on my system yea I'll probably use it)

Here is one reason in particular I'm using structs:

struct posiprops AttackData()
{
struct posiprops AB;
AB.multnorm = 0.5;
AB.multgroup = 0.4;
AB.multdam = 0.0;
AB.multrace = 0.15;
AB.multalign = 0.15;
AB.luck = 5.0;
AB.add1 = 0.9;
AB.add2 = 1.9;
AB.add3 = 2.9;
AB.add4 = 3.9;
AB.add5 = 4.9;
AB.add6 = 8.5;
AB.add7 = 11.0;
AB.add8 = 14.0;
AB.add9 = 16.0;
AB.add10 = 26.0;
AB.add11 = 30.0;
AB.add12 = 34.0;
AB.add13 = 38.0;
AB.add14 = 42.0;
AB.add15 = 44.0;
AB.add16 = 46.0;
AB.add17 = 50.0;
AB.add18 = 54.0;
AB.add19 = 58.0;
AB.add20 = 62.0;
return AB;
}

struct Armor FullplateData()
{
struct Armor FullPlate;
FullPlate.basecost = 1500.0;
FullPlate.multiplier = 1.0;
FullPlate.stack = 1.0;
FullPlate.balance = 6.0;
FullPlate.numprops = 6;
FullPlate.abilityscale = 12;
FullPlate.ACnormscale = 5;
FullPlate.ACgroupscale = 6;
FullPlate.ACdamscale = 6;
FullPlate.ACPCracescale = 7;
FullPlate.ACNPCracescale = 8;
FullPlate.ACalignscale = 7;
FullPlate.weightscale = 5;//10% of weight
FullPlate.bonuslevel0spellsscale = -1;
FullPlate.bonuslevel1spellsscale = -1;
FullPlate.bonuslevel2spellsscale = -1;
FullPlate.bonuslevel3spellsscale = -1;
FullPlate.bonuslevel4spellsscale = -1;
FullPlate.bonuslevel5spellsscale = -1;
FullPlate.bonuslevel6spellsscale = -1;
FullPlate.bonuslevel7spellsscale = -1;
FullPlate.bonuslevel8spellsscale = -1;
FullPlate.bonuslevel9spellsscale = -1;
FullPlate.DRpowerscale = 10;
FullPlate.DRsoakscale = 50;
FullPlate.darkvisionscale = TRUE;
FullPlate.hastescale = TRUE;
FullPlate.lightscale = 4;
FullPlate.regenscale = 3;
FullPlate.saveuniversalscale = -1;
FullPlate.saveacidscale = 1;
FullPlate.savecoldscale = 1;
FullPlate.savedeathscale = -1;
FullPlate.savediseasescale = -1;
FullPlate.savedivinescale = -1;
FullPlate.electricalsavescale = 1;
FullPlate.savefearscale = -1;
FullPlate.savefirescale = -1;
FullPlate.savemindscale = -1;
FullPlate.savenegativescale = -1;
FullPlate.savepoisonscale = -1;
FullPlate.savepositivescale = -1;
FullPlate.savesonicscale = 1;
FullPlate.savespecificscale = -1;
FullPlate.skillanimscale = -1;
FullPlate.skillappraisescale = -1;
FullPlate.skillbluffscale = -1;
FullPlate.skillconcscale = -1;
FullPlate.skillcraftarmscale = -1;
FullPlate.skillcraftwepscale = -1;
FullPlate.skilltrapcraftscale = -1;
FullPlate.skilldistrapscale = -1;
FullPlate.skilldiscscale = -1;
FullPlate.skillhealscale = -1;
FullPlate.skillhidescale = -1;
FullPlate.skillintscale = -1;
FullPlate.listenskillscale = -1;
FullPlate.loreskillscale = -1;
FullPlate.skillmsscale = -1;
FullPlate.skillopenscale = -1;
FullPlate.skillparryscale = -1;
FullPlate.skillperfscale = -1;
FullPlate.skillspersscale = -1;
FullPlate.skillpickscale = -1;
FullPlate.skillridescale = -1;
FullPlate.skillsearscale = -1;
FullPlate.skillsetscale = -1;
FullPlate.skillspellscale = -1;
FullPlate.skillspotscale = -1;
FullPlate.skilltauntscale = -1;
FullPlate.skilltumbscale = -1;
FullPlate.skillumdscale = -1;
FullPlate.freedomscale = -1;
FullPlate.damageimmunityelescale = -1;
FullPlate.damageimmunitysupscale = -1;
FullPlate.sneakimmunescale = -1;
FullPlate.drainimmunescale = -1;
FullPlate.mindimmunescale = -1;
FullPlate.poisonimmunescale = -1;
FullPlate.diseaseimmunescale = -1;
FullPlate.fearimmunescale = -1;
FullPlate.knockimmunescale = -1;
FullPlate.paraimmunescale = -1;
FullPlate.critimmunescale = -1;
FullPlate.deathimmunescale = -1;
FullPlate.schoolevoscale = -1;
FullPlate.schoolabjscale = -1;
FullPlate.schoolnecroscale = -1;
FullPlate.schoolilluscale = -1;
FullPlate.schoolconjscale = -1;
FullPlate.schooldivscale = -1;
FullPlate.schoolenchscale = -1;
FullPlate.schooltranscale = -1;
FullPlate.spellimmunelvlscale = -1;
FullPlate.impevasionscale = -1;
FullPlate.spellresistscale = -1;
FullPlate.trueseescale = -1;
FullPlate.spellfailurescale = 45;
return FullPlate;
}

-1 means I set it as disabled.(it can be set otherwise)
That is A LOT of definitions. I think it exceeds the constant limit 10 times over in the whole script. The beauty I wanted for this system is it is TRULY universal! Custom content? Easily added. Different rulesets? Easily editted. The beauty of a system where you control EVERYTHING with MINIMAL work and it's actually big, like really, really big.(and efficient!!!!) For instance to add one of your special properties all you'd have to do is add the property in the beginning as a struct and simply add it as a possible property in the Gen_Item function(it's a switch/case statement that you literally just have to add another case and increase the random threshhold +1).

And, on a tangential note, I also did an item prop system designed to be diablo-esque, though it wound up far more complex, since we had an added layer of non-vanilla itemprops to contend with, which required special treatment. We also added augments, D&D style - over a thousand of them, applied with augmenter items. After extensive experimentation, we went with MySQL, since it allowed us to do extensive and easily modifiable weighting of various item props, though that's not likely to be ideal for a system designed for public release, like yours. Of course, if you DO decide to have it require NWNX, you can then make use of the rediculously awesome ItemPropertyDirect function, which allows you to build itemprops with the 6 struct int values (pulled from various 2da tables), instead of the myriad different bioware functions, like so:


We actually use your system on our server now, don't take offense to this but I just feel like it's lacking in drop possibilities. I'd have to re-write the whole thing to make it have different threshholds for different item types.(maybe I don't like how rapier which basically just facially fornicates everything can have -exactly- the same numbers as a bastard sword which is both harder to get(requires exotic) and WEAKER!!!!). It breaks the whole point of using a bastardsword unless you just like being that hipster who "I was using bastardsword before it was good." and I'm not going to go the Lysan route and start editting default abilities of weapons because that's deweeding the lawn with matches and gasoline.(if you don't get what that means, I mean that's going a really extreme route that will probably make things worse then better in the end). I used a longsword throughout the whole OC because it was Enserric! I realized my weapon was weaker, but I liked the fact it had a uniqueness to it.

We also made EXTENSIVE use of string operations, without any problems in terms of load (we have a whole library we use like crazy - they're really not bad). I'm linking the scripts to the system for you to see - they aren't useable in another PW, or without the associated databases, but they may give you ideas or insights for your own system. You can find the scripts here. The specs for the database tables are here.

Hope some of that proves useful or informative.

Funky


Hmm thank you, those are pretty interesting.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #11 on: January 01, 2013, 07:24:17 pm »


               

Oh I'm not debating that .2DA calls are fast when it's just one, but the problem is item properties are calling multiple -different- 2DAs.

No, multiple different 2das doesn't matter much at all, so long as you're not exceeding the number you set as cachable in your ini - I use 10, which is plenty for my purposes. It's a little more problematic for HGLL, which accesses dozens, but as it happens it's still pretty fast. The main thing to avoid is caching a 2da, having it replaced by reading (and caching) more than your ini limit, and then rereading it, which ups the ratio of extremely slow first-time caching reads. 2das are now FAR more useable than they were before the caching modifications.

That is A LOT of definitions. I think it exceeds the constant limit 10 times over in the whole script. The beauty I wanted for this system is it is TRULY universal! Custom content? Easily added. Different rulesets? Easily editted. The beauty of a system where you control EVERYTHING with MINIMAL work and it's actually big, like really, really big.(and efficient!!!!) For instance to add one of your special properties all you'd have to do is add the property in the beginning as a struct and simply add it as a possible property in the Gen_Item function(it's a switch/case statement that you literally just have to add another case and increase the random threshhold +1).


I suspect a custom 2da would be a better solution if you're entering the same or similar data for all item types - the data would be easier to find and read, and the data reads likely faster than the structs, depending on how many other 2das you would need to access and/or create to do it. The 2da would of course be serverside only, but WOULD require some additional explanation to end-users.

If you still prefer the struct approach, I would use default values for all of those declarations where possible, and allow the end-user to plug them in where desired. That was an approach I once adopted from the original DAR subrace system by Demux, way back in the day (though again, as with itemprops, we migrated to a database-driven approach as both cleaner and faster). It cuts WAY down on script spam. He basically put a master template struct with default values in its own include, then plugged specific instances, in this case subraces rather than item types, in a switch, using it to set only the values that differed from the template for that particular instance. It was very tidy, and very end-user-friendly, without tons of redundant declarations. I highly recommend taking a look at it; you can find it here.


We actually use your system on our server now, don't take offense to this but I just feel like it's lacking in drop possibilities. I'd have to re-write the whole thing to make it have different threshholds for different item types.(maybe I don't like how rapier which basically just facially fornicates everything can have -exactly- the same numbers as a bastard sword which is both harder to get(requires exotic) and WEAKER!!!!). It breaks the whole point of using a bastardsword unless you just like being that hipster who "I was using bastardsword before it was good." and I'm not going to go the Lysan route and start editting default abilities of weapons because that's deweeding the lawn with matches and gasoline.(if you don't get what that means, I mean that's going a really extreme route that will probably make things worse then better in the end). I used a longsword throughout the whole OC because it was Enserric! I realized my weapon was weaker, but I liked the fact it had a uniqueness to it.


No, you don't use our system. As I said in my last post, our scripts simply wouldn't work for another PW, which is why they haven't been publicly released. This is, of course, also why I posted them for you, instead of pointing you to a public release on the Vault.

As for drop possiblities, I can say with confidence that ours will blow any other system out of the water, as it allows essentially unlimited drop possibilities, and starts with dozens of non-vanilla item properties and hundreds of potential augments (also with novel properties, many variable-based) - prefix, suffix, and master. It also randomizes each property, scaling them up and down within prescribed limits based on rarity, using standard deviations to create bell-curve distributions of high and low changes. The number of possible combinations for any given item is so high I couldn't possibly calculate it accurately. This does not mean you would regularly SEE all of those combinations, but that's the purpose of the standard deviations and weighting - to peg property addition, subtraction, randomization, and frequency to what felt right, making more powerful props and higher costvalue props considerably rarer.

It does NOT create new items as implemented, though it easily could, since it adds and removes props, taking into account item type. This is one reason the system wouldn't port to other servers - it's configured to randomize our current loot items, rather than generating entirely new ones. This was critical to us, because of careful balancing we'd done to keep power bloat in check. The end results, are, however, completely different items from their base versions, which leads me to a point you may not have considered yet. With any system that creates random loot, you're going to create problems for any end-user who uses string-based rather than object-based item storage for their banking systems. Have you given any thought to encoding/decoding your edits? That's something I hadn't given much thought to until late in the coding process (all 4 months of it). It's another area where the scripts I linked may prove useful to you.

Hmm thank you, those are pretty interesting.


I'm a little confused as to how you could find the scripts I linked interesting, when you also thought you were already using them on your server and found them lacking. I'm guessing you didn't look at them yet, thinking I was linking you to the string function library I had mentioned rather than the item prop system I was discussing. Anyway, I suggest having a peep, as I think you'll find them incredibly useful to your current project - I wish I had had something of the kind to base them off of, as it could've shaved months off the time I had to spend.

Funky
               
               

               
            

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #12 on: January 02, 2013, 06:56:02 am »


               The original creator of the mod I typically script for has a lot of popular scripts from IGNvault.(a considerable amount of them branding the "FunkySwerve" name) Upon inspecting I now realize this particular script was written by "Slayers of Darkmoon" and for that I apologize. I have now looked over your scripts and I can see your system is written considerably different to this particular individuals. The concepts in your system are almost identical to mine in an eerie way lol.(sigh always good to know your idea was already thought of well in advance...) Though rarity for my system is calculated in a vastly different way and mine focuses on attempting to create an item strictly enforcing the level the particular person is enforcing. However I do have some questions about your scripts if you don't mind me asking.

const int RANDOMIP_ITEM_TYPE_SHIELD_TOWER                         = 0x00000001;
const int RANDOMIP_ITEM_TYPE_SHIELD_LARGE                         = 0x00000002;
const int RANDOMIP_ITEM_TYPE_SHIELD_SMALL                         = 0x00000004;
const int RANDOMIP_ITEM_TYPE_ARMOR_HEAVY                          = 0x00000008;
const int RANDOMIP_ITEM_TYPE_ARMOR_MEDIUM                         = 0x00000010;
const int RANDOMIP_ITEM_TYPE_ARMOR_LIGHT                          = 0x00000020;
const int RANDOMIP_ITEM_TYPE_BRACER                               = 0x00000040;
const int RANDOMIP_ITEM_TYPE_GLOVE                                = 0x00000080;
const int RANDOMIP_ITEM_TYPE_HELM                                 = 0x00000100;
const int RANDOMIP_ITEM_TYPE_BELT                                 = 0x00000200;
const int RANDOMIP_ITEM_TYPE_BOOT                                 = 0x00000400;
const int RANDOMIP_ITEM_TYPE_CLOAK                                = 0x00000800;
const int RANDOMIP_ITEM_TYPE_AMULET                               = 0x00001000;
const int RANDOMIP_ITEM_TYPE_RING                                 = 0x00002000;
const int RANDOMIP_ITEM_TYPE_FLAG                                 = 0x00004000;
const int RANDOMIP_ITEM_TYPE_STAFF                                = 0x00008000;
const int RANDOMIP_ITEM_TYPE_ARMOR_ROBE                           = 0x00010000;//65536

This particular segment of code, I'm not going to pretend I understand hexadecimals(as stated earlier in this topic I learned programming as a minor for the sake of using compiler languages to write/read/predict genetic libraries.) How are you getting a random number from that?

EDIT= I forgot to mention that we definitely use that subrace system already. I also wanted to say it seems you're right. I guess I'm just too used to the old 2DA function that I've developed more or less a repulsion to it. Is the 2DA cacher used for single player modules?
               
               

               


                     Modifié par Highv Priest, 02 janvier 2013 - 07:03 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Enchanted Cloak Value?
« Reply #13 on: January 03, 2013, 04:36:20 am »


               Yeah, the 2da caching is used for SP too afaik, though I'm far from expert on SP, so you should probably check - I think the default value in the player's ini would cover it, for SP.

And yeah, it took me a long time to get accustomed to using 2das again, though we still look for better ways, whenever a script is using a bunch, to avoid recaching when possible. '<img'>

The hex numbers you ask about have nothing to do with the randomness in the system, which is introduced nearly everywhere it can be. There's a roll to see how many properties are added or subtracted, if any - if so, each is determined by a database query, using the sum of all the weights in the table and the result of a random roll. Before I delve into that, though, a quick hex primer:

Those hex numbers are just a visually simpler way of writing bits. Hex is base 16, instead of base 2, so it's 4 times as compact. That means you can fit 4 bits into one hex. Here are some examples - once you see them side by side, they become very easy to read. Hexadecimal numbers can have 16 numbers per digit, 0-9, and a-f for values 10-15. Hex is indicated by the 0x followed by the relevant digits.
decimal (base 10) --- binary (base 2) --- hexadecimal (base 16)
1 --- 1 --- 0x1
2 --- 10 --- 0x2
4 --- 100 --- 0x4
8 --- 1000 --- 0x8
16 --- 10000 --- 0x10
32 --- 100000 --- 0x20
64 --- 1000000 --- 0x40
128 --- 10000000 --- 0x80
256 --- 100000000 --- 0x100
512 --- 1000000000 --- 0x200
1024 --- 10000000000 - 0x400
2048 --- 100000000000 - 0x800
4096 --- 1000000000000 - 0x1000

As you can see, hex notation is extremely compact compared to binary, and follows a very simple 1, 2, 4, 8 progression. This makes it very visually easy to work with in flagsets. You could, if you wanted, replace all those hex numbers with decimal, and the script would work exactly the same - it's for human readability only.

So, what is it doing there? It's used to encode what properties are allowed on what items types, allowing us to cover all item types with the use of a single 17-bit number (though the field we're putting it in allows up to 64, should we want to expand the types later). That's what the rp_allow_item field in rip_props is storing. For most item properties, it is 131071, or in binary 11111111111111111, or in hex 0x1FFFF - meaning that property is allowed on all item types. If I wanted to allow it on all but, say, robes, I would simply 'shut off' the relevant bit, which in hex is 0x00010000. It's the leftmost bit in the binary, so I would just specify sixteen ones instead of 17, or 0xFFFF, or 65535.

That type is checked when adding new properties, in DoItemQualityMods, in fky_randloot_inc. The property-adding code chunk starts on line 569. The heavy lifting is done with a MySQL call:


            sConditions = "(rp_allow_item & " + IntToString(nItemType) + ") AND (' " +
                          sProps3NonStacking + " " + GetLocalString(oItem, "TempPropString") + "' NOT LIKE rp_block_ip) AND rp_inverse " +
                          (nNegative ? "< 0" : ">= 0") + sRareMod;
            fMult = (nNegative ? -1.0 : 1.0);
            rip = GetRandIPInitialData(sConditions, nAsmoRareChecks);

In english, that's basically stringing together a database call  to pull up and select an item prop of the appropriate type - one allowed on the item according to type, and either negative (ex: Weight Added) or positive (ex: Bonus to Strength), without allowing properties already on the item unless they are stacking props (that is, it'll allow a bonus to universal saves even if the item already has it, because the code later totals those props into a single prop, but not, say, immunity to death magic, which doesn't stack). It also will not allow certain props on certain specific itemsIt's inordinately complex, which is of course why the whole damn thing took me 4 months of free time to code. Here's the code comprising GetRandIPInitialData, which, when combined with the strings above, shows you the full SQL query used:


struct RIProperties GetRandIPInitialData(string sConditions, int nRarityTries = 1) {
    string sSQL;
    struct RIProperties ret, temp;
    int nX;
    for (nX = 0; nX < nRarityTries; nX++) {
        //pull up all properties that are of acceptable IP and item type, totalling weight
        sSQL = "SELECT @rp_random := FLOOR(RAND() * SUM(rp_weight)) " +
               "FROM rip_props WHERE " + sConditions;
        SQLExecDirect(sSQL);

        //select one of those properties by weight
        sSQL = "SELECT rp_type,rp_sub,rp_cval,rp_pval,rp_max,rp_min,rp_range,rp_block_ip,rp_rarity FROM rip_props WHERE (" + sConditions +
               ") AND (@rp_random := @rp_random - rp_weight) < 0 LIMIT 1";
        SQLExecDirect(sSQL);

        while (SQLFetch() != SQL_ERROR) {
            temp.type            = StringToInt(SQLGetData(1));
            temp.subtype         = StringToInt(SQLGetData(2));
            temp.costvalue       = StringToInt(SQLGetData(3));
            temp.paramvalue      = StringToInt(SQLGetData(4));
            temp.maxval          = StringToInt(SQLGetData(5));
            temp.minval          = StringToInt(SQLGetData(6));
            temp.range           = SQLGetData(7);
            temp.blockip         = SQLGetData(8);
            temp.rarity          = StringToInt(SQLGetData(9));
        }

        if (temp.rarity > ret.rarity) {
            ret.type            = temp.type;
            ret.subtype         = temp.subtype;
            ret.costvalue       = temp.costvalue;
            ret.paramvalue      = temp.paramvalue;
            ret.maxval          = temp.maxval;
            ret.minval          = temp.minval;
            ret.range           = temp.range;
            ret.blockip         = temp.blockip;
            ret.rarity          = temp.rarity;
        }
    }
    return ret;
}

Basically, that code sums up the total weights of all the item properties in that database table which match the specified criteria, then picks one at random. This approach allowed fine-tuning of relative item property rarities, which was critical to our approach. It's also disgustingly fast compared to trying to do all that in nwscript. '<img'>

Anyway, as to the randomness in the system, it's introduced at every possible juncture. Whether item properties are added or subtracted is determined randomly. If you were doing a system like yours, creating entirely new items, you would instead just determine how many props to add. Then, each property is 'slot-machined' up or down at random, according to a bell curve - both newly added properties, if any, and old properties. That's what this code chunk (and all those like it) is about:

nPropCostValInt = RoundedFloatToInt(RandomNormal(GetStandardDeviation(nPropCostValInt, nPropType, nSubType, StringToInt(sPvalCheck)), IntToFloat(nPropCostValInt)));
nPropCostValInt = RangeConformStackingPropValue(oItem, nPropType, nSubType, nPropCostValInt, nCalc);
Further, each property can have a different standard deviation set in the database table, allowing us to create more or less variation on a per-property basis. Most are set to 2.

I'm happy to go into more detail, but we should probably move it to PMs or start a new thread - we've kinda hijacked this thread, though I THINK I gave the OP the answer he was looking for above.

Funky