Aller au contenu

Photo

Easiest way for Random armor/weapons?


  • Veuillez vous connecter pour répondre
19 réponses à ce sujet

#1
Zeidae

Zeidae
  • Members
  • 38 messages
Greets.
I finally finished all of the areas in my mod a little while ago. Now I  need to fix the random monster armor script.

Currently the script randomly adds properties and then makes sure that the item is not too high of a level.
Unfortunately, this takes too long and the monster is more likely to stand there waiting for the armor to be produced than to fight.

So I  wish to scrap that setup.

But now I  am not certain of the best way to proceed.

I would like all monsters to have random item properties on their equipment so as to make every encounter unique. Some would be very easy and some could be downright challenging if an NPC  happened to get all of the good stuff.

There are many levels of skill. AC  1-20, damage 1-2d12. etc

I could sit here and produce 20 property lists based on estimated worth. IE AC +1 and AB +1 would be in one list and AC +20 and AB +20, and everything that correlates, could be in another list, with everything inbetween.

I  don't know that having 40+ property lists would be a very good thing. I'd need ranked lists for both armor and weapons.

The way I  am currently creating NPC's is to give them a certain number of blank armor pieces. So all of the low creatures would have just 1 piece of armor to add random properties to, and all of the top monsters would have 9. I would then need to get the appropriate level item property to be placed on each piece of equipment the monster has.
Not only that, but if possible, I would have the script run multiple times based on the PC's level. If a L40 comes walking through a L1 area, I would attempt to give the L1 creatures 8+ item properties instead of a standard 1. However, this is not critical.

I should be satisfied with having just 1 item property be placed on the equipment the NPC is wearing. I  can make creatures easier or tougher by either giving them more equipment or making them use an easier or tougher item property list.


Please do not make the suggestion of having pre-created armors and using those or some such standard idea. One of the primary goals of my mod from the start was a random factor. I  did not want to face the same exact kobold 100 times with the same exact gear and abilities, for once you can kill one, you can kill all. Yawn. Thank you, but "standard" is not what I  am seeking and that idea has already been suggested to me in the past, so I  wish to head it off now ;)


Basically, my question is, how can I get a L1 creature to add L1 type properties and L40 creature add L40 properties without creating 40+ lists. If I  have to create 40 lists, fine, but i'm sure there must be a better way.
Also, a L1 creature could conceivably be wearing items that are too high for it. Even adding Bright Light puts it past L1 if I  remember correctly. And there will be plenty of "useless" properties in the lists that make the item's level high, but keep the creature from being "high". So to the best of my knowledge, a value check would not be a good way to avoid 40 property lists.

Thanks!

#2
HipMaestro

HipMaestro
  • Members
  • 1 515 messages
I am just wondering.

If you have found an effective way to seed random properties on equipment but it's sole drawback is that it is screwing up combat effectiveness, (i.e. pausing to complete all the calculations) could you build an inaccessible area to be used exclusively to house these custom spawns as one enters a trigger area, possibly at a location with enough lead time to allow the prop seeding to complete before entering the designed combat area, and then simply drop each NPC (or group of NPCs) in from the holding area to the combat zone as needed?

Just a scripting dunce making a stab in the dark and hoping for the best.

#3
Greyfort

Greyfort
  • Members
  • 234 messages
I like your random Idea, seems like it should work. If we set aside level use, and gear, just start with creature skin thats one way to adjust and randomly add to creature. Next we take armor wich aslong as creature not in combat I dont think its an issue. then finaly weapon.

Q1) are all items preequiped in creature toolset resref, if so seems it shold be easyier.

I will try a fewthings out and see what I come up with. my plate is pretty full, but one can always have a little more ;)

EDIT ADD:  Your script may be great, perhaps change some of it to functions, If you wish to post it we could look it over to see if we can make it faster.  Or send me a pm with email and I can look it over once we connect.

upon closer reading of your post it looks like you almost had it just had a spawn standing you said...seems fixable

Modifié par Greyfort, 28 mai 2011 - 10:25 .


#4
Karvon

Karvon
  • Members
  • 243 messages
A script I've used in the past, might prove helpful as it can be used to equip creatures.

A4 Easy Building Series: Treasure Tables, Equipment and Stores

Karvon

#5
Zeidae

Zeidae
  • Members
  • 38 messages

HipMaestro wrote...

I am just wondering.

If you have found an effective way to seed random properties on equipment but it's sole drawback is that it is screwing up combat effectiveness, (i.e. pausing to complete all the calculations) could you build an inaccessible area to be used exclusively to house these custom spawns as one enters a trigger area, possibly at a location with enough lead time to allow the prop seeding to complete before entering the designed combat area, and then simply drop each NPC (or group of NPCs) in from the holding area to the combat zone as needed?

Just a scripting dunce making a stab in the dark and hoping for the best.


My script also greatly lags the server. Just spawning the npc's in a different spot wouldn't solve that. Not to mention, i think it would be rather complex to spawn the creature to the correct area once they do have gear.

Thanks though.
It's the level check that makes it take so long. But i can't just get rid of it because i have every level of property in the current list. Obviously I don't want to add 20 AC  to mr 1 level rat :)

#6
Zeidae

Zeidae
  • Members
  • 38 messages

Greyfort wrote...

I like your random Idea, seems like it should work. If we set aside level use, and gear, just start with creature skin thats one way to adjust and randomly add to creature. Next we take armor wich aslong as creature not in combat I dont think its an issue. then finaly weapon.

Q1) are all items preequiped in creature toolset resref, if so seems it shold be easyier.

I will try a fewthings out and see what I come up with. my plate is pretty full, but one can always have a little more ;)

EDIT ADD:  Your script may be great, perhaps change some of it to functions, If you wish to post it we could look it over to see if we can make it faster.  Or send me a pm with email and I can look it over once we connect.

upon closer reading of your post it looks like you almost had it just had a spawn standing you said...seems fixable


Creatures are all pre-equipped with blank armor. I  tried not having them wear it to start but that didn't work well. I had it that way so that I  would not have to do the level check. I would just randomly spawn X pieces of equipment onto the creature and if they could wear it, fine, if not, fine.

I will have to include the script later as I don't have the toolset open just now ;) It isn't terribly complex. It's just that it loops a TON so that the item properties don't make the armor go above the creature level. When you get a group of 6 monsters spawned at one time, there is noticable server lag. I can't imagine having multiple players spawning creatures all the time. The lag would be too much. Not to mention that I had to greatly chop down the properties list just to try and speed it up, but i would rather have every property be available.

And for the record, player loot is all nice and random as well! But that one works at least heh. It does make it interesting finding good gear, which was also part of the point.

#7
Xardex

Xardex
  • Members
  • 217 messages
It would be much simpler and easier to handle this with effects. This would essentially end your performance problems since no loops and reduce your personal hassle, with the 9 items and all...

(example)
Make you mob receive supernatural permanent AC increase on spawn equal to Level/4 + d10.
You would have your random factor and it would scale with the creatures level. (+11-20 at level 40)

#8
Zeidae

Zeidae
  • Members
  • 38 messages
I will be using effects in addition to item properties to boost things like HP and AC. But from what I have seen, I cannot get anywhere near all of the item properties into effects. This isn't just about AC or AB. There are tons of other affects that can be added to items.
Can you add "on hit cast spell" with an effect?
Can you add "light dim yellow" with an effect?
Can you add "Tumble +30" with an effect?
Can you add Damage reduction with an effect?
etc

Ability bonus, AC, AC vs Align, AC vs Race, AC vs Dmg Type, Bonus feats, saving throws, saving throws vs dmg type, spell resistance, damage immunity, damage reduction, damage resistance, darkvision, freeaction, haste, misc immunity, immunity to spell level, improved evasion, light, on hit cast spell, regen, skill bonus, school immunity, spell immunity, true seeing, item weight reduction. Those are the properties i'm adding to the armor. Then there's also the weapons.

Thanks ;)

#9
Xardex

Xardex
  • Members
  • 217 messages
You can use effects for all of those and more, except On Hit property, bonus feats (without nwnx) and weigth reduction. (which seems kinda pointless) Besides, who's to say you couldn't use a mix of item properties and effects. You are applying the item properties with a script anyway...

Generally you can do much more with effects then item properties, unless its some On Hit property. (Which by the way at least with 'cast spells' launches a script that applies effects to the enemy hit)

#10
Zeidae

Zeidae
  • Members
  • 38 messages
i don't think your suggestion, though, has solved the problem I described.
It may be easy to do a graded AC scale, but what about the other properties? How can I get the AC bonus (if there is one) to sometimes be vs alignment or race and not universal?

How can I get weapon damage onto a weapon?

I am not a scripter. I use lilacs for most things. And the last time I fiddled with effects, I couldn't do nearly as much as I wanted via Lilacs. I remember trying to add hit points, but the best I could do was the temporary hit points spell which was too limiting.

I am a little torn in how to set up the monster scaling. On one side, I would love that L1 monster to not be a 1 hit easy kill for Mr L40 who is walking through. But on the other side, I find that always facing monsters of the same ability as yourself gets to be boring (aka Oblivion). So I am more leaning towards not having the monsters scaled based on level with perhaps exception to something like hit points, or simple things. Having Random abilities is my primary concern. Monsters already get random skill bonuses from another script I downloaded, but that isn't easily seen. A monster with an additional 2-4 con is likely to still be just as weak as his buddies.

#11
omen_shepperd

omen_shepperd
  • Members
  • 194 messages
I use Commche’s random loot system to generate random weapons and armors; it also generates random items as well. And commche has been very helpful in making adjustments when I needed the adjustments made and he responds fairly promptly to e-mails. Here is a link
http://nwvault.ign.c....Detail&id=3233 hope this helps.

Modifié par omen_shepperd, 29 mai 2011 - 04:48 .


#12
Zeidae

Zeidae
  • Members
  • 38 messages
Would it generate random weapons and armors on NPC's for them to use in combat?
I can generate random loot. I just can't do what i'm trying to do lol not effectively anyway

#13
Xardex

Xardex
  • Members
  • 217 messages
Well since you are going with the item properties....
ItemPropertyACBonus
ItemPropertyACBonusVsAlign
ItemPropertyACBonusVsDmgType
ItemPropertyACBonusVsRace
ItemPropertyACBonusVsSAlign
Use these, look 'em up in the nwscript

Though if you dont know nwscript and dont want to spend time getting into it, commche's system is should do just fine.

#14
Zeidae

Zeidae
  • Members
  • 38 messages

Xardex wrote...

Well since you are going with the item properties....
ItemPropertyACBonus
ItemPropertyACBonusVsAlign
ItemPropertyACBonusVsDmgType
ItemPropertyACBonusVsRace
ItemPropertyACBonusVsSAlign
Use these, look 'em up in the nwscript

Though if you dont know nwscript and dont want to spend time getting into it, commche's system is should do just fine.


I  have the entire ItemProperty list. That is not my problem.
My problem is getting the right level ItemProperty on to the right level NPC! There are 20 levels of AC, AB and other properties. I  can get AC 1 or AC 20 onto any NPC. I can get onhit cast acid spash 1 or 40. What I  can't do is get AC 1 and onhitcast acidspash 1 on a L1 monster or AC 20 and onhitcast acidsplash 40 on a level 40 monster. Not without creating 40 lists! There are 2300 item properties! What I  want to know is how to get the low properties onto the low monters and the high ones onto the high monsters.

I think I am going to end up simply having to create 1 big massive list. Then i'll give low level monsters like 1 piece of armor and high level monsters 9 pieces, and then maybe have the script run through X times so that the L1 monster is only going to get 1 random item property on his 1 piece of equipment while a L40 monster could get 8 properties on 9 pieces of equipment (just an example not actual numbers =P). If a L1 NPC happens to get 20 AC, I  guess i'll have to live with that. It should not happen very often. 1% of the time perhaps. There are hundreds of item properties when you include all of the levels and variables. 1 random property on 1 piece of armor should hopefully not cause too much grief. I  would hate to run into the L1 monster with onhitcast L40 firebrand though lol. I am not opposed to keeping onhits relatively weak though.

#15
Xardex

Xardex
  • Members
  • 217 messages
Use GetHitDice to get the creatures level. You can derive other numbers from it as you wish.
Here is an simple example...

int iLvl = GetHitDice(oNPC);
int iAC = iLvl/2;
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyACBonus(iAC), oItem);


This would add an item AC bonus property equal to half the NPC's level to oItem.

Modifié par Xardex, 29 mai 2011 - 06:34 .


#16
Zeidae

Zeidae
  • Members
  • 38 messages
Thanks. But there is much more to what i want than that :)

#17
Xardex

Xardex
  • Members
  • 217 messages
If I understood you correctly you want the item properties to scale with the NPCs level? If that is all, you can use this method for pretty much every single item property... I hope I am not missing something.

#18
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
Xardex's answer is far and away the best solution for you, if you aren't really a scripter, as you say. We have a true random loot system on HG, and it took me, with help from acaos, a good three months to write it. It also requires oodles of functionality that native nwn doesn't have (you would want linux nwnx to be able to dynamically assemble item properties without having to use the clunky bioware functions, or it'd take far longer).

We actually do almost ALL of our monster/NPC attributes with variables read from onspawn. It would be relatively simple, by comparison, to make them add randomly instead of reading from variable. Here's a script called fky_ai_locals, that executs from our onspawn, with one line to #include "fky_ai_locals" and a second to     ApplyLocals();

Pardon the length of the script below, but if you think THIS is complicated, you REALLY do not want to try to do anything similar using item props. Again, this is not precisely what you want, it is an example of how to alter monster attributes from onspawn using effects. Instead of reading vars off the monsters, you would probably instead simply want to use dice functions or Random() to pick what wgets applied:

[code=auto:0]
const int DAMAGE_BEHAVIOR_HEAL          = 0x00000010;

int GetDamagePowerFromNumber (int nNum) {
    if (nNum < 6)
        return nNum;
    else
        return nNum + 1;
}

int GetHighestDigit (int nInt) {
    int i, nHighDigit = -1, nHighValue = 0;

    for (i = 0; nInt > 0; i++) {
        if (nInt % 10 > nHighValue) {
            nHighDigit = i;
            nHighValue = nInt % 10;
        }

        nInt /= 10;
    }

    return nHighDigit;
}

int GetOverHealType (int nImm) {
    int nDiv   = (nImm % 10);
    int nNeg   = (nImm /= 10) % 10;
    int nPos   = (nImm /= 10) % 10;
    int nMag   = (nImm /= 10) % 10;
    int nSonic = (nImm /= 10) % 10;
    int nFire  = (nImm /= 10) % 10;
    int nElec  = (nImm /= 10) % 10;
    int nCold  = (nImm /= 10) % 10;
    int nAcid  = (nImm /= 10) % 10;

    if (nAcid == 9 && nElec <= 7)
        return DAMAGE_TYPE_ACID;
    if (nCold == 9 && nFire <= 7)
        return DAMAGE_TYPE_COLD;
    if (nElec == 9 && nAcid <= 7)
        return DAMAGE_TYPE_ELECTRICAL;
    if (nFire == 9 && nCold <= 8)
        return DAMAGE_TYPE_FIRE;
    if (nAcid == 9 && nElec <= 8)
        return DAMAGE_TYPE_ACID;
    if (nCold == 9 && nFire <= 8)
        return DAMAGE_TYPE_COLD;
    if (nElec == 9 && nAcid <= 8)
        return DAMAGE_TYPE_ELECTRICAL;
    if (nNeg == 9 && nPos <= 7)
        return DAMAGE_TYPE_NEGATIVE;
    if (nPos == 9 && nNeg <= 7)
        return DAMAGE_TYPE_POSITIVE;
    if (nSonic == 9)
        return DAMAGE_TYPE_SONIC;
    return 0;
}

void ApplyImmunities (object oSelf, int nImm, int bVuln=FALSE, int nAdd=10) {
    effect eEff;

    int nDigit0 = (nImm % 10);
    int nDigit1 = (nImm /= 10) % 10;
    int nDigit2 = (nImm /= 10) % 10;
    int nDigit3 = (nImm /= 10) % 10;
    int nDigit4 = (nImm /= 10) % 10;
    int nDigit5 = (nImm /= 10) % 10;
    int nDigit6 = (nImm /= 10) % 10;
    int nDigit7 = (nImm /= 10) % 10;
    int nDigit8 = (nImm /= 10) % 10;

    if (bVuln) {
        if (nDigit8 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityDecrease(DAMAGE_TYPE_ACID, (nDigit8 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit7 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityDecrease(DAMAGE_TYPE_COLD, (nDigit7 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit6 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityDecrease(DAMAGE_TYPE_ELECTRICAL, (nDigit6 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit5 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityDecrease(DAMAGE_TYPE_FIRE, (nDigit5 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit4 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityDecrease(DAMAGE_TYPE_SONIC, (nDigit4 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit3 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityDecrease(DAMAGE_TYPE_MAGICAL, (nDigit3 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit2 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityDecrease(DAMAGE_TYPE_POSITIVE, (nDigit2 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit1 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityDecrease(DAMAGE_TYPE_NEGATIVE, (nDigit1 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit0 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityDecrease(DAMAGE_TYPE_DIVINE, (nDigit0 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }
    } else {
        if (nDigit8 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_ACID, (nDigit8 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit7 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, (nDigit7 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit6 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_ELECTRICAL, (nDigit6 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit5 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_FIRE, (nDigit5 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit4 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_SONIC, (nDigit4 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit3 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_MAGICAL, (nDigit3 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit2 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_POSITIVE, (nDigit2 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit1 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_NEGATIVE, (nDigit1 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit0 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_DIVINE, (nDigit0 * 10) + nAdd));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }
    }
}

void ApplyAutocast (object oSelf, string sAutocast) {
    int i, nSpell, nMeta, nLevel, nElem, nCasts = GetStringSubStrings(sAutocast);

    if (!GetIsObjectValid(oSelf))
        return;

    if (!GetIsObjectValid(GetArea(oSelf))) {
        DelayCommand(1.0, ApplyAutocast(oSelf, sAutocast));
        return;
    }

    for (i = 0; i < nCasts; i++) {
        string sCast = GetStringSubString(sAutocast, i);

        nElem  = GetStringSubStrings(sCast, ",");
        nMeta  = METAMAGIC_NONE;
        nLevel = 0;

        if (nElem > 2)
            nLevel = StringToInt(GetStringSubString(sCast, 2, ","));
        else
            nLevel = 0;

        if (nElem > 1)
            nMeta = StringToInt(GetStringSubString(sCast, 1, ","));
        else
            nMeta = METAMAGIC_NONE;

        if (nElem > 1)
            nSpell = StringToInt(GetStringSubString(sCast, 0, ","));
        else
            nSpell = StringToInt(sCast);

        AssignCommand(oSelf, ActionCastSpellAtObject(nSpell,
            oSelf, nMeta, TRUE, nLevel, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
    }
}

void ApplyDynamicEquipmentProperties (object oOwner, int nSlot, string sProps, int nTries=3) {
    if (!GetIsObjectValid(oOwner))
        return;

    object oItem = GetItemInSlot(nSlot, oOwner);

    if (!GetIsObjectValid(oItem)) {
        if (nTries < 1)
            return;

        DelayCommand(1.0, ApplyDynamicEquipmentProperties(oOwner, nSlot, sProps, nTries - 1));
        return;
    }

    ApplyDynamicItemProperties(sProps, oItem);

    int i, nVars = GetLocalInt(oOwner, "ItemVariables_" + IntToString(nSlot));

    for (i = 1; i <= nVars; i++) {
        string sVar = GetLocalString(oOwner, "ItemVariable_" + IntToString(nSlot) + "_" + IntToString(i));

        RestoreLocals(oItem, sVar);
    }
}

void ApplyDynamics (object oSelf) {
    int i;

    if (!GetIsObjectValid(oSelf))
        return;


    /* Dynamic Item Properties */
    int nMask = GetLocalInt(oSelf, "ItemProperties_Mask");
    string sProps;
    for (i = 0; i < 18; i++) {
        if (nMask & (1 << i)) {
            sProps = GetLocalString(oSelf, "ItemProperties_" + IntToString(i));

            if (sProps != "")
                DelayCommand(2.0, ApplyDynamicEquipmentProperties(oSelf, i, sProps));
        }
    }


    /* Dynamic Effects */
    string sEffs = GetLocalString(oSelf, "Effects");

    if (sEffs != "")
        DelayCommand(1.0, ApplyDynamicEffects(sEffs, oSelf, -2, -1.0, SUBTYPE_SUPERNATURAL));


    /* Autocasting */
    string sAutocast = GetLocalString(oSelf, "Autocast");

    if (sAutocast != "")
        DelayCommand(1.0, ApplyAutocast(oSelf, sAutocast));


    /* Events */
    string sEvents = GetLocalString(oSelf, "Events");

    if (sEvents != "") {
        if (FindSubString(sEvents, "HEARTBEAT") >= 0)
            SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT);

        /* sigh deeply at the stupid misspelling by the NWN creators */
        if (FindSubString(sEvents, "PERCEIVE") >= 0)
            SetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT);

        if (FindSubString(sEvents, "ATTACKED") >= 0)
            SetSpawnInCondition(NW_FLAG_ATTACK_EVENT);

        if (FindSubString(sEvents, "SPELL") >= 0)
            SetSpawnInCondition(NW_FLAG_SPELL_CAST_AT_EVENT);

        if (FindSubString(sEvents, "DAMAGED") >= 0)
            SetSpawnInCondition(NW_FLAG_DAMAGED_EVENT);

        if (FindSubString(sEvents, "DISTURBED") >= 0)
            SetSpawnInCondition(NW_FLAG_DISTURBED_EVENT);

        if (FindSubString(sEvents, "ROUND") >= 0)
            SetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT);

        if (FindSubString(sEvents, "DIALOGUE") >= 0)
            SetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT);

        if (FindSubString(sEvents, "DEATH") >= 0)
            SetSpawnInCondition(NW_FLAG_DEATH_EVENT);
    }
}

void ApplyCrafting (object oSelf) {
    int i, nMask = GetLocalInt(oSelf, "ItemCrafting_Mask");
    if (!nMask)
        return;

    string sCraft;
    for (i = 0; i <= 6; i++) {
        if (nMask & (1 << i)) {
            sCraft = GetLocalString(oSelf, "ItemCrafting_" + IntToString(i));

            if (sCraft != "") {
                object oItem = GetItemInSlot(i, oSelf);
                RestoreItemAppearance(oItem, sCraft);
            }
        }
    }
}

void ApplyLocals () {
    object oSelf = OBJECT_SELF;

    int nPlot = GetLocalInt(oSelf, "Plot");
    if (nPlot)
        SetPlotFlag(oSelf, TRUE);

    int nAILevel = GetLocalInt(oSelf, "AILevel");
    if (nAILevel)
        SetAILevel(oSelf, nAILevel);


    int nRandDrop = GetLocalInt(oSelf, "RandDrop");

    if (nRandDrop) {
        object oNPC = oSelf;
        object oItem = GetFirstItemInInventory(oNPC);

        while (GetIsObjectValid(oItem)) {
            if (GetDroppableFlag(oItem) == FALSE) {
                int nDroppable = d100() > 50;

                SetDroppableFlag(oItem, nDroppable);
            }

            oItem = GetNextItemInInventory(oNPC);
        }
    }


    int i, nDigit0, nDigit1, nDigit2, nDigit3, nDigit4, nDigit5, nDigit6, nDigit7, nDigit8, nDigit9;
    effect eEff;

    /* Cutscene Ghost */
    int nGhost = GetLocalInt(oSelf, "Ghost");
    if (nGhost) {
        eEff = SupernaturalEffect(EffectCutsceneGhost());

        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
    }


    /* Ability AB override */
    int nAbilityAB = GetLocalInt(oSelf, "AbilityAB");

    if (nAbilityAB)
        SetAbilityAB(oSelf, nAbilityAB);


    /* Add AB */
    int nAddAB = GetLocalInt(oSelf, "AddAB");

    if (nAddAB) {
        eEff = SupernaturalEffect(EffectAttackIncrease(nAddAB));

        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
    }


    /* Extra Attacks */
    int nAddAttacks = GetLocalInt(oSelf, "AddAttacks");

    if (nAddAttacks) {
        eEff = SupernaturalEffect(EffectModifyAttacks(nAddAttacks));

        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
    }


    /* Saves: 9NMDfrwFRW
     *   9: Unused
     *
     *   N: Negative            (2 points per)
     *   M: Mind Spells/Fear    (2 points per)
     *   D: Death Magic         (2 points per)
     *
     *   f: Fortitude Penalty   (2 points per)
     *   r: Reflex Penalty      (2 points per)
     *   w: Will Penalty        (2 points per)
     *
     *   F: Fortitude Bonus     (2 points per)
     *   R: Reflex Bonus        (2 points per)
     *   W: Will Bonus          (2 points per)
     */
    int nSaves = GetLocalInt(oSelf, "Saves");

    if (nSaves) {
        nDigit0 = (nSaves % 10);
        nDigit1 = (nSaves /= 10) % 10;
        nDigit2 = (nSaves /= 10) % 10;
        nDigit3 = (nSaves /= 10) % 10;
        nDigit4 = (nSaves /= 10) % 10;
        nDigit5 = (nSaves /= 10) % 10;
        nDigit6 = (nSaves /= 10) % 10;
        nDigit7 = (nSaves /= 10) % 10;
        nDigit8 = (nSaves /= 10) % 10;
        nDigit9 = (nSaves /= 10) % 10;

        if (nDigit8 > 0) {
            eEff = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_ALL, nDigit8 * 2, SAVING_THROW_TYPE_NEGATIVE));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit7 > 0) {
            eEff = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_ALL, nDigit7 * 2, SAVING_THROW_TYPE_MIND_SPELLS));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);

            eEff = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_ALL, nDigit7 * 2, SAVING_THROW_TYPE_FEAR));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit6 > 0) {
            eEff = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_ALL, nDigit6 * 2, SAVING_THROW_TYPE_DEATH));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit5 > 0) {
            eEff = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_FORT, nDigit5 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit4 > 0) {
            eEff = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_REFLEX, nDigit4 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit3 > 0) {
            eEff = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_WILL, nDigit3 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit2 > 0) {
            eEff = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_FORT, nDigit2 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit1 > 0) {
            eEff = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_REFLEX, nDigit1 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit0 > 0) {
            eEff = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_WILL, nDigit0 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }
    }


    /* Conceal */
    int nConceal = GetLocalInt(oSelf, "Conceal");

    if (nConceal) {
        eEff = SupernaturalEffect(EffectConcealment(nConceal));

        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
    }


    /* PhysImmunities: H V 7 6 BI PI SI BR PR SR
     *
     *   H: 1 = Haste
     *
     *   V: 1 = True Seeing          4 = Darkvision             7 = TS/SI/Darkvision
     *      2 = See Invisible        5 = TS/Darkvision
     *      3 = TS/SI                6 = SI/Darkvision
     *
     *   7: UNUSED
     *   6: UNUSED
     *
     *   BI: 10 + (digit * 10)% bludgeoning
     *   PI: 10 + (digit * 10)% piercing
     *   SI: 10 + (digit * 10)% slashing
     *
     *   BR: (digit * 5)/- bludgeoning
     *   PR: (digit * 5)/- piercing
     *   SR: (digit * 5)/- slashing
     */
    int nRes = GetLocalInt(oSelf, "PhysImmunities");

    if (nRes) {
        nDigit0 = (nRes % 10);
        nDigit1 = (nRes /= 10) % 10;
        nDigit2 = (nRes /= 10) % 10;
        nDigit3 = (nRes /= 10) % 10;
        nDigit4 = (nRes /= 10) % 10;
        nDigit5 = (nRes /= 10) % 10;
        nDigit6 = (nRes /= 10) % 10;
        nDigit7 = (nRes /= 10) % 10;
        nDigit8 = (nRes /= 10) % 10;
        nDigit9 = (nRes /= 10) % 10;

        if (nDigit9 > 0) {
            eEff = SupernaturalEffect(EffectHaste());
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit8 > 0) {
            if (nDigit8 & 1) {
                eEff = SupernaturalEffect(EffectTrueSeeing());
                ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
            }

            if (nDigit8 & 2) {
                eEff = SupernaturalEffect(EffectSeeInvisible());
                ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
            }

            if (nDigit8 & 4) {
                eEff = SupernaturalEffect(EffectUltravision());
                ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
            }
        }

        if (nDigit5 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, (nDigit5 * 10) + 10));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit4 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_PIERCING, (nDigit4 * 10) + 10));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit3 > 0) {
            eEff = SupernaturalEffect(EffectDamageImmunityIncrease(DAMAGE_TYPE_SLASHING, (nDigit3 * 10) + 10));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit2 > 0) {
            eEff = SupernaturalEffect(EffectDamageResistance(DAMAGE_TYPE_BLUDGEONING, nDigit2 * 5));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit1 > 0) {
            eEff = SupernaturalEffect(EffectDamageResistance(DAMAGE_TYPE_PIERCING, nDigit1 * 5));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit0 > 0) {
            eEff = SupernaturalEffect(EffectDamageResistance(DAMAGE_TYPE_SLASHING, nDigit0 * 5));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }
    }


    /* Ability Boosting- str dex con int wis cha - increase by twice the input number - from 2-12 */
    int nAbility = GetLocalInt(oSelf, "Ability");

    if (nAbility) {
        nDigit0 = (nAbility % 10);
        nDigit1 = (nAbility /= 10) % 10;
        nDigit2 = (nAbility /= 10) % 10;
        nDigit3 = (nAbility /= 10) % 10;
        nDigit4 = (nAbility /= 10) % 10;
        nDigit5 = (nAbility /= 10) % 10;

        if (nDigit0) {
            eEff = SupernaturalEffect(EffectAbilityIncrease(ABILITY_CHARISMA, nDigit0 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit1) {
            eEff = SupernaturalEffect(EffectAbilityIncrease(ABILITY_WISDOM, nDigit1 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit2) {
            eEff = SupernaturalEffect(EffectAbilityIncrease(ABILITY_INTELLIGENCE, nDigit2 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit3) {
            eEff = SupernaturalEffect(EffectAbilityIncrease(ABILITY_CONSTITUTION, nDigit3 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit4) {
            eEff = SupernaturalEffect(EffectAbilityIncrease(ABILITY_DEXTERITY, nDigit4 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit5) {
            eEff = SupernaturalEffect(EffectAbilityIncrease(ABILITY_STRENGTH, nDigit5 * 2));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }
    }

    /* Skill increase - 5 + (5 * input number) */
    /* Taunt/Bluff/Persuade/Intimidate/Perform/Heal/AniEmp MS Hide Listen Spot Tumble Parry Conc Disc */
    int nSkill = GetLocalInt(oSelf, "Skill");

    if (nSkill) {
        nDigit0 = (nSkill % 10);
        nDigit1 = (nSkill /= 10) % 10;
        nDigit2 = (nSkill /= 10) % 10;
        nDigit3 = (nSkill /= 10) % 10;
        nDigit4 = (nSkill /= 10) % 10;
        nDigit5 = (nSkill /= 10) % 10;
        nDigit6 = (nSkill /= 10) % 10;
        nDigit7 = (nSkill /= 10) % 10;
        nDigit8 = (nSkill /= 10) % 10;

        if (nDigit0) {
            eEff = SupernaturalEffect(EffectSkillIncrease(SKILL_DISCIPLINE, 5 + (nDigit0 * 5)));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit1) {
            eEff = SupernaturalEffect(EffectSkillIncrease(SKILL_CONCENTRATION, 5 + (nDigit1 * 5)));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit2) {
            eEff = SupernaturalEffect(EffectSkillIncrease(SKILL_PARRY, 5 + (nDigit2 * 5)));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit3) {
            eEff = SupernaturalEffect(EffectSkillIncrease(SKILL_TUMBLE, 5 + (nDigit3 * 5)));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit4) {
            eEff = SupernaturalEffect(EffectSkillIncrease(SKILL_SPOT, 5 + (nDigit4 * 5)));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit5) {
            eEff = SupernaturalEffect(EffectSkillIncrease(SKILL_LISTEN, 5 + (nDigit5 * 5)));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit6) {
            eEff = SupernaturalEffect(EffectSkillIncrease(SKILL_HIDE, 5 + (nDigit6 * 5)));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit7) {
            eEff = SupernaturalEffect(EffectSkillIncrease(SKILL_MOVE_SILENTLY, 5 + (nDigit7 * 5)));
            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }

        if (nDigit8) {
            eEff = EffectSkillIncrease(SKILL_PERFORM, 5 + (nDigit8 * 5));
            eEff = EffectLinkEffects(eEff, EffectSkillIncrease(SKILL_TAUNT, 5 + (nDigit8 * 5)));
            eEff = EffectLinkEffects(eEff, EffectSkillIncrease(SKILL_BLUFF, 5 + (nDigit8 * 5)));
            eEff = EffectLinkEffects(eEff, EffectSkillIncrease(SKILL_PERSUADE, 5 + (nDigit8 * 5)));
            eEff = EffectLinkEffects(eEff, EffectSkillIncrease(SKILL_INTIMIDATE, 5 + (nDigit8 * 5)));
            eEff = EffectLinkEffects(eEff, EffectSkillIncrease(SKILL_HEAL, 5 + (nDigit8 * 5)));
            eEff = EffectLinkEffects(eEff, EffectSkillIncrease(SKILL_ANIMAL_EMPATHY, 5 + (nDigit8 * 5)));
            eEff = SupernaturalEffect(eEff);

            ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
        }
    }


    /* SR */
    int nSR = GetLocalInt(oSelf, "SR");

    if (nSR) {
        eEff = SupernaturalEffect(EffectSpellResistanceIncrease(nSR));

        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
    }


    /* Regen */
    int nRegen = GetLocalInt(oSelf, "Regen");

    if (nRegen) {
        eEff = SupernaturalEffect(EffectRegenerate(nRegen, 6.0));

        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
    }


    /* Soak - specified as Soak+Plus (defaults to 20+1; specify 0+0 for no soak) */
    string sSoak = GetLocalString(oSelf, "Soak");

    if (sSoak != "") {
        struct SubString ss, spss;

        ss.rest = sSoak;

        while (ss.rest != "") {
            ss = GetFirstSubString(ss.rest, " ");

            if (ss.first != "0+0" && ss.first != "0") {
                spss = GetFirstSubString(ss.first, "+");

                int nSoak = StringToInt(spss.first);
                int nPlus = GetDamagePowerFromNumber(StringToInt(spss.rest));

                eEff = SupernaturalEffect(EffectDamageReduction(nSoak, nPlus));

                ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
            }
        }
    } else {
        eEff = SupernaturalEffect(EffectDamageReduction(20, DAMAGE_POWER_PLUS_ONE));

        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oSelf);
    }


    /* Acid Cold Elec Fire Sonic Magic Positive Negative Divine */

    int nImm = GetLocalInt(oSelf, "OverImmunities");
    if (nImm) {
        int nHealDigit = -1, nOverHeal = GetLocalInt(oSelf, "OverHeal");

        /* if set, the highest immunity will actually heal damage of that type */
        if (nOverHeal) {
            int nHealMult = 0, nHealType = GetLocalInt(oSelf, "OverHealType");

            if (nHealType == 0)
                nHealType = GetOverHealType(GetLocalInt(oSelf, "EnergyImmunities"));

            if (nHealType) {
                switch (nHealType) {
                    case DAMAGE_TYPE_ACID:       nHealDigit = 8; break;
                    case DAMAGE_TYPE_COLD:       nHealDigit = 7; break;

#19
Baaleos

Baaleos
  • Members
  • 1 330 messages
I've Resurrected my own PW, which has a Pseudo-Random Loot Generator of its own.

Everytime a player logs in, it parses their inventory, gathering Item Properties and Item ResRefs.
(Harvest Phase)

It stores these to nwnx database - the Item Properties are stored as int values which relate to their specific properties.
-2013297536 = Vampiric Regeneration +9 etc


Anyhow...
Thats the Harvest Phase.

Next comes the spawn phase of Monsters.

When a Monster Spawns, it gets the Nearest Player Character - potentially the one who spawned him, and then ascertains the average ability scores of the team that player is a member of.

It then Works out its own Ability Scores in relation to the players Teams Scores, and calculates what the difference is, and tries to balance the difference out by adding Ability Score Bonuses to the Creature.

Ala - Dynamic Level Scaling Monsters - the Monsters however only scale a certain amount, and only after a Certain CR Level.


Anyhow...
Inside the Dynamic Spawn system, I have my Dynamic Loot generator function called.

If this is a Scaled Spawn - (level increases etc)
It rolls a dice to determine should we spawn an item....

If yes....
Roll a Dice to determine its Tier.
Tier 1 = Low Level (Blue Text)
2 = Medium (Green)
3 = High (Magenta)
4 = Very High (Gold/Yellow)

The tiers determine the amount of Properties the item can have maximum - of each type.

eg - Tier 4 can have 3 Damage Bonus Properties Maximum, and upto 5 other properties....
Tier 1 can have 1 Damage Bonus, and 2 Other Properties.

The Properties are selected at random from the Repository of Item Properties via a Select SQL Statement which is ordered via

order = Rand() limit 1 (select 1 random row)


This is looped over in nwn script, and each property is added to the item that was spawned.


It then renames the items in a similar way.

I have a large repository of Item Name Prefixes and Suffix's,

Drow xxxxxx of the Sunset
Demon's xxxxxx of the Night

etc

The items are then re-named according to a randomly selected prefix and suffix..


The Uber Secret Tier 5 items ONLY spawn if item Prefixes and Suffixes of certain types come together with an appropriate Item Type.

eg

Bhaal's Ring of Immortality might spawn as a normal Dynamic Loot item of tier 1 to 4
But
Bhaal's Long Sword of Immortality would spawn as a Tier 5 item, and would have SPECIFIC item properties stored for that combo item in the database. These tier 5 items are UBER Rare, and I've only seen one of them appear once - which is kinda good, means theres lots of variation, and possibility.



So.. anyway.
Hope this gives you some ideas.

#20
Zeidae

Zeidae
  • Members
  • 38 messages
Thanks for all the replies.
I've decided on just creating 5 item property groupings and will add the properties based on creature level. I'll control the difficulty of the monsters by the number of armors they have and how many properties they'll get. And then use effects to adjust for player level.