I'm now going to post all new and altered scripts as well as hopefully all steps to be done to get it all working.
Let this be a gentle warning for the occasional "I'm trying this out because it looks like fun, but I'm glad I finally managed to get it working as I don't know much about modding myself"-type of testers.I don't want to confuse you with the following possibly over-complex tasks to fulfill only to have you end up with a non-functional mod in the end.
If you're not one of the few who know what they have to do to get certain things fixed on their own in the CS and outside of it, you might rather want to wait for a finished ESP to be released, by me or someone else who felt like sharing.
Now, that being said you will need to do certain preparations messing around with files and new item records/quests/scripts in the CS before you can even begin altering the existing ones.
I hope I'm able to tell you exactly what you need to do in exactly the right order, but truth is I'm not able to edit the ESP myself and am basically "tapping around in the dark blindly", metaphorically speaking, when it comes to the steps I'm going to explain.
First of all you should load any savegame with a dragon character you want to continue later on. Once it's loaded stop the main race control quest by typing "stopquest DrakeDragonRaceQuest" into the console. Then save and quit.This is to make the quest script update when you alter it in the ESP, as it occurred sometimes to be not taking over all changes when it was still running. I don't know if it would take over the changes correctly when you stop the quest after loading and then restart it, but I know doing the changes after the quest was stopped always worked till today.
Now let's get the new Clothwraps Complete Resource to be used by my mod and scripts.
I'll now post a list of items you need to create and which files each of them corresponds to. (It's not complicated, EditorID and filename are mostly identical.):
1. The already existing items you need to alter:- "
DrakeDragonChestWraps" (folder has changed)
male: "meshes/clothes/DrakeDragon/male/DragonChestWraps.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsTFF.nif"
- "
DrakeDragonHandWraps" (folder has changed)
male: "meshes/clothes/DrakeDragon/male/DragonHandWraps.nif"
female: "meshes/clothes/DrakeDragon/female/DragonHandWrapsTFF.nif"
- "
DrakeDragonFootWraps" (folder has changed)
male: "meshes/clothes/DrakeDragon/male/DragonFootWraps.nif"
female: "meshes/clothes/DrakeDragon/female/DragonFootWrapsTFF.nif"
- "
DrakeDragonLegWraps" (folder has changed)
male: "meshes/clothes/DrakeDragon/male/DragonLegWraps.nif"
female: "meshes/clothes/DrakeDragon/female/DragonLegWrapsTFF.nif"
2. New items to complement the replacer template resources:- "
DrakeDragonChestWrapsWinged" (occupied slots:
upperbody)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsWinged.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsWingedTFF.nif"
- "
DrakeDragonLegWrapsTailed" (occupied slots:
lowerbody)
male: "meshes/clothes/DrakeDragon/male/DragonLegWrapsTailed.nif"
female: "meshes/clothes/DrakeDragon/female/DragonLegWrapsTailedTFF.nif"
- "
DrakeDragonChestWrapsHands" (occupied slots:
upperbody, hands)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsHands.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsHandsTFF.nif"
- "
DrakeDragonChestWrapsLower" (occupied slots:
upperbody, lowerbody)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsLower.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsLowerTFF.nif"
- "
DrakeDragonChestWrapsLowerHands" (occupied slots:
upperbody, lowerbody, hand)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsLowerHands.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsLowerHandsTFF.nif"
- "
DrakeDragonChestWrapsLowerFeet" (occupied slots:
upperbody, lowerbody, foot)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsLowerFeet.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsLowerFeetTFF.nif"
- "
DrakeDragonChestWrapsLowerHandsFeet" (occupied slots:
upperbody, lowerbody, hand, foot)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsLowerHandsFeet.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsLowerHandsFeetTFF.nif"
- "
DrakeDragonChestWrapsTailedLower" (occupied slots:
upperbody, lowerbody)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsTailedLower.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsTailedLowerTFF.nif"
- "
DrakeDragonChestWrapsTailedLowerHands" (occupied slots:
upperbody, lowerbody, hand)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsTailedLowerHands.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsTailedLowerHandsTFF.nif"
- "
DrakeDragonChestWrapsTailedLowerFeet" (occupied slots:
upperbody, lowerbody, foot)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsTailedLowerFeet.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsTailedLowerFeetTFF.nif"
- "
DrakeDragonChestWrapsTailedLowerHandsFeet" (occupied slots:
upperbody, lowerbody, hand, foot)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsTailedLowerHandsFeet.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsTailedLowerHandsFeetTFF.nif"
- "
DrakeDragonChestWrapsWingedHands" (occupied slots:
upperbody, hands)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsWingedHands.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsWingedHandsTFF.nif"
- "
DrakeDragonChestWrapsWingedLower" (occupied slots:
upperbody, lowerbody)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsWingedLower.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsWingedLowerTFF.nif"
- "
DrakeDragonChestWrapsWingedLowerHands" (occupied slots:
upperbody, lowerbody, hand)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsWingedLowerHands.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsWingedLowerHandsTFF.nif"
- "
DrakeDragonChestWrapsWingedLowerFeet" (occupied slots:
upperbody, lowerbody, foot)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsWingedLowerFeet.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsWingedLowerFeetTFF.nif"
- "
DrakeDragonChestWrapsWingedLowerHandsFeet" (occupied slots:
upperbody, lowerbody, hand, foot)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsWingedLowerHandsFeet.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsWingedLowerHandsFeetTFF.nif"
- "
DrakeDragonChestWrapsWingedTailedLower" (occupied slots:
upperbody, lowerbody)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsWingedTailedLower.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsWingedTailedLowerTFF.nif"
- "
DrakeDragonChestWrapsWingedTailedLowerHands" (occupied slots:
upperbody, lowerbody, hand)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsWingedTailedLowerHands.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsWingedTailedLowerHandsTFF.nif"
- "
DrakeDragonChestWrapsWingedTailedLowerFeet" (occupied slots:
upperbody, lowerbody, foot)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsTailedWingedLowerFeet.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsTailedWingedLowerFeetTFF.nif"
- "
DrakeDragonChestWrapsWingedTailedLowerHandsFeet" (occupied slots:
upperbody, lowerbody, hand, foot)
male: "meshes/clothes/DrakeDragon/male/DragonChestWrapsWingedTailedLowerHandsFeet.nif"
female: "meshes/clothes/DrakeDragon/female/DragonChestWrapsWingedTailedLowerHandsFeetTFF.nif"
(seeing a pattern already?)
You might have guessed already what's the purpose of the slotnames at the end, or why there are always "tailed", "winged" or "wingedtailed" versions of almost each combination (chest and hands only doesn't cover the tail of course).
Those of you who are used to my scripting approach might have recognized all the "tagged" files as well, which were not used here,... yepp, you guessed it, these will of course as usual automatically be taken up by my scripts and used appropriately for the specific dragon-human-hybrid combination you selected in the config menu.
Now you need to create following "object"-type scripts (actually all new OBSE "user-functions"):
scn DrakeDragonRaceReplacerHairFunctionarray_var confArrayref itemref templatebegin Function {confArray, item} let template := DrakeEmptyItem setFunctionValue templateend
scn DrakeDragonRaceReplacerUpperFunctionarray_var confArrayref itemref templatelong slotmaskshort req0short req1short req2short req3begin Function {confArray, item} ;this one is getting a bit complex. select the fitting replacer template according to occupied slots set slotmask to getBipedSlotMask item let req0 := confArray[5]["combinations"][0]["req"] let req1 := confArray[5]["combinations"][1]["req"] let req2 := confArray[5]["combinations"][2]["req"] let req3 := confArray[5]["combinations"][3]["req"] if(req0 == 1) ;tail if eval (slotmask & 20 == 20) let template := DrakeDragonChestWrapsHands elseif eval (slotmask & 12 == 12) let template := DrakeDragonChestWrapsTailedLower elseif eval (slotmask & 28 == 28) let template := DrakeDragonChestWrapsTailedLowerHands elseif eval (slotmask & 44 == 44) let template := DrakeDragonChestWrapsTailedLowerFeet elseif eval (slotmask & 60 == 60) let template := DrakeDragonChestWrapsTailedLowerHandsFeet else let template := DrakeDragonChestWraps endif elseif(req1 == 1) ;wings if eval (slotmask & 20 == 20) let template := DrakeDragonChestWrapsWingedHands elseif eval (slotmask & 12 == 12) let template := DrakeDragonChestWrapsWingedLower elseif eval (slotmask & 28 == 28) let template := DrakeDragonChestWrapsWingedLowerHands elseif eval (slotmask & 44 == 44) let template := DrakeDragonChestWrapsWingedLowerFeet elseif eval (slotmask & 60 == 60) let template := DrakeDragonChestWrapsWingedLowerHandsFeet else let template := DrakeDragonChestWrapsWinged endif elseif(req2 == 1 || req3 == 1) ;wings and tail if eval (slotmask & 20 == 20) let template := DrakeDragonChestWrapsWingedHands elseif eval (slotmask & 12 == 12) let template := DrakeDragonChestWrapsWingedTailedLower elseif eval (slotmask & 28 == 28) let template := DrakeDragonChestWrapsWingedTailedLowerHands elseif eval (slotmask & 44 == 44) let template := DrakeDragonChestWrapsWingedTailedLowerFeet elseif eval (slotmask & 60 == 60) let template := DrakeDragonChestWrapsWingedTailedLowerHandsFeet else let template := DrakeDragonChestWrapsWinged endif else ;none of both if eval (slotmask & 20 == 20) let template := DrakeDragonChestWrapsHands elseif eval (slotmask & 12 == 12) let template := DrakeDragonChestWrapsLower elseif eval (slotmask & 28 == 28) let template := DrakeDragonChestWrapsLowerHands elseif eval (slotmask & 44 == 44) let template := DrakeDragonChestWrapsLowerFeet elseif eval (slotmask & 60 == 60) let template := DrakeDragonChestWrapsLowerHandsFeet else let template := DrakeDragonChestWraps endif endif setFunctionValue templateend
scn DrakeDragonRaceReplacerLowerFunctionarray_var confArrayref itemref templateshort req0short req2short req3begin Function {confArray, item} let req0 := confArray[5]["combinations"][0]["req"] let req2 := confArray[5]["combinations"][2]["req"] let req3 := confArray[5]["combinations"][3]["req"] if(req0 == 1 || req2 == 1 || req3 == 1) ;tail let template := DrakeDragonLegWrapsTailed else let template := DrakeDragonLegWraps endif setFunctionValue templateend
scn DrakeDragonRaceReplacerHandsFunctionarray_var confArrayref itemref templatebegin Function {confArray, item} let template := DrakeDragonHandWraps setFunctionValue templateend
scn DrakeDragonRaceReplacerFeetFunctionarray_var confArrayref itemref templatebegin Function {confArray, item} let template := DrakeDragonFootWraps setFunctionValue templateend
scn DrakeDragonRaceReplacerTailFunctionarray_var confArrayref itemref templateshort req0short req1short req2short req3begin Function {confArray, item} let req0 := confArray[5]["combinations"][0]["req"] let req1 := confArray[5]["combinations"][1]["req"] let req2 := confArray[5]["combinations"][2]["req"] let req3 := confArray[5]["combinations"][3]["req"] if(req0 == 1) ;tail let template := DrakeDragonTail elseif(req1 == 1) ;wings let template := DrakeDragonWings elseif(req2 == 1 || req3 == 1) ;wings and tail let template := DrakeDragonWingsTail else ;none of both let template := DrakeEmptyItem endif setFunctionValue templateend
scn DrakeDragonRaceReplacerSelectFunctionstring_var slotIdarray_var confArrayref itemref templatebegin Function {slotId, confArray, item} ;select proper function according to slot if eval (slotId == "upperbody") let template := Call DrakeDragonRaceReplacerUpperFunction confArray item elseif eval (slotId == "lowerbody") let template := Call DrakeDragonRaceReplacerLowerFunction confArray item elseif eval (slotId == "hands") let template := Call DrakeDragonRaceReplacerHandsFunction confArray item elseif eval (slotId == "feet") let template := Call DrakeDragonRaceReplacerFeetFunction confArray item elseif eval (slotId == "hair") let template := Call DrakeDragonRaceReplacerHairFunction confArray item elseif eval (slotId == "tail") let template := Call DrakeDragonRaceReplacerTailFunction confArray item endif setFunctionValue templateend
Here you can actually witness the birth of the new and improved template replacer selection system. There's way more space and possibilities inside those new function scripts than there'll ever be inside the token script itself or a replacer template array (as there was before). OBSE's getting quite convenient for me now isn't it?
Noticed the "tagId" changed into "confArray"? "tagId" was no longer needed, as this part of the actual filename is generated outside of the template selection now.
But I needed the "confArray" of the specific race to access your personal dragon-human-hybrid selection of choice as defined in the config menu.
Next create a new quest "DrakeDragonRaceConfigQuest". Make it
not "start game enabled" and check "allow repeating stages".
Once this is done create following "quest"-type script:
scn DrakeDragonRaceConfigQuestScriptshort choicefloat fQuestDelayTimebegin gameMode set fQuestDelayTime to 0.5 if(DrakeDragonRaceQuest.doConfig == 1) MessageBoxEX "Dragon Race > Do You want to keep all default settings?|Yes|No" set DrakeDragonRaceQuest.doConfig to -2 return elseif(DrakeDragonRaceQuest.doConfig == -2) set choice to getButtonPressed if(choice == 0) ;stick to defaults MessageBoxEX "Dragon Race > Forced unequipping:%rBy default this will also affect items%rcovering more than 1 slot at once,%r(e.g. The Arena Raiments or DB Armor)%rleaving actors running around naked,%rif they weren't adapted yet.%rDo You wish to make an exception%rto allow non-fitting combined-slot items?|Yes|No" set DrakeDragonRaceQuest.doConfig to 12 elseif(choice == 1) ;customize MessageBoxEX "Dragon Race > Select Your shape:%rDo You want to be Full-Dragon shape?|Yes|No" set DrakeDragonRaceQuest.doConfig to 2 endif return elseif(DrakeDragonRaceQuest.doConfig == 2) ;full-dragon or custom? set choice to getButtonPressed if(choice == 0) ;stay full-dragon set DrakeDragonRaceQuest.showclaws to 1 set DrakeDragonRaceQuest.showfeet to 1 set DrakeDragonRaceQuest.showtail to 1 set DrakeDragonRaceQuest.showwings to 1 MessageBoxEX "Dragon Race > Select Your shape:%rDo You want controlled helmet slot,%rnot actually force-equipping anything%rbut keeping non-fitting helmets unequipped?|Yes|No" set DrakeDragonRaceQuest.doConfig to 5 elseif(choice == 1) ;further customize MessageBoxEX "Dragon Race > Select Your shape:%rWhich wings & tail combination do You prefer?|Wings and tail|Only wings|Only tail|None at all" set DrakeDragonRaceQuest.doConfig to 3 endif return elseif(DrakeDragonRaceQuest.doConfig == 3) ;tail & wings options set choice to getButtonPressed if(choice > -1) if(choice == 0) ;both set DrakeDragonRaceQuest.showtail to 1 set DrakeDragonRaceQuest.showwings to 1 elseif(choice == 1) ;only wings set DrakeDragonRaceQuest.showtail to 0 set DrakeDragonRaceQuest.showwings to 1 elseif(choice == 2) ;only tail set DrakeDragonRaceQuest.showtail to 1 set DrakeDragonRaceQuest.showwings to 0 elseif(choice == 3) ;neither wings nor tail set DrakeDragonRaceQuest.showtail to 0 set DrakeDragonRaceQuest.showwings to 0 endif MessageBoxEX "Dragon Race > Select Your shape:%rWhich hands & feet/legs combination do You prefer?|Dragon hands and feet/legs|Dragon hands but human feet/legs|Human hands but dragon feet/legs|Human hands and human feet/legs" set DrakeDragonRaceQuest.doConfig to 4 endif return elseif(DrakeDragonRaceQuest.doConfig == 4) ;hands & feet options set choice to getButtonPressed if(choice > -1) if(choice == 0) ;both set DrakeDragonRaceQuest.showclaws to 1 set DrakeDragonRaceQuest.showfeet to 1 elseif(choice == 1) ;dragon hands, human feet set DrakeDragonRaceQuest.showclaws to 1 set DrakeDragonRaceQuest.showfeet to 0 elseif(choice == 2) ;humand hands, dragon feet set DrakeDragonRaceQuest.showclaws to 0 set DrakeDragonRaceQuest.showfeet to 1 elseif(choice == 3) ;all human set DrakeDragonRaceQuest.showclaws to 0 set DrakeDragonRaceQuest.showfeet to 0 endif MessageBoxEX "Dragon Race > Select Your shape:%rDo You want controlled helmet slot,%rnot actually force-equipping anything%rbut keeping non-fitting helmets unequipped?|Yes|No" set DrakeDragonRaceQuest.doConfig to 5 endif return elseif(DrakeDragonRaceQuest.doConfig == 5) ;helmet options set choice to getButtonPressed if(choice > -1) if(choice == 0) ;controlled helmet set DrakeDragonRaceQuest.showhelmet to 1 elseif(choice == 1) ;keep hairstyles set DrakeDragonRaceQuest.showhelmet to 0 endif MessageBoxEX "Dragon Race > Forced unequipping:%rBy default unequipping of non-fitting items%ris forced for all slots but upperbody.%rThis includes visual replacement while keeping stats.%rWhich settings do You prefer?|Keep default (All)|None at all|Customize..." set DrakeDragonRaceQuest.doConfig to 6 endif return elseif(DrakeDragonRaceQuest.doConfig == 6) set choice to getButtonPressed if(choice > -1) if(choice == 0); all slots set DrakeDragonRaceQuest.forcehelmet to 1 set DrakeDragonRaceQuest.forceupper to 0 set DrakeDragonRaceQuest.forcehands to 1 set DrakeDragonRaceQuest.forcelower to 1 set DrakeDragonRaceQuest.forcefeet to 1 set DrakeDragonRaceQuest.forcetail to 1 MessageBoxEX "Dragon Race > Forced unequipping:%rBy default this will also affect items%rcovering more than 1 slot at once,%r(e.g. The Arena Raiments or DB Armor)%rleaving actors running around naked,%rif they weren't adapted yet.%rDo You wish to make an exception%rto allow non-fitting combined-slot items?|Yes|No" set DrakeDragonRaceQuest.doConfig to 12 elseif(choice == 1) ;none at all set DrakeDragonRaceQuest.forcehelmet to 0 set DrakeDragonRaceQuest.forceupper to 0 set DrakeDragonRaceQuest.forcehands to 0 set DrakeDragonRaceQuest.forcelower to 0 set DrakeDragonRaceQuest.forcefeet to 0 set DrakeDragonRaceQuest.forcetail to 0 MessageBoxEX "Dragon Race > Forced unequipping:%rBy default this will also affect items%rcovering more than 1 slot at once,%r(e.g. The Arena Raiments or DB Armor)%rleaving actors running around naked,%rif they weren't adapted yet.%rDo You wish to make an exception%rto allow non-fitting combined-slot items?|Yes|No" set DrakeDragonRaceQuest.doConfig to 12 elseif(choice == 2) ;customize MessageBoxEX "Dragon Race > Forced unequipping:%rDo You want the helmet/hair slot to be forced?%r(Only relevant, if it is controlled.)|Yes|No" set DrakeDragonRaceQuest.doConfig to 7 endif endif return elseif(DrakeDragonRaceQuest.doConfig == 7) set choice to getButtonPressed if(choice > -1) if(choice == 0) ;yes set DrakeDragonRaceQuest.forcehelmet to 1 elseif(choice == 1) ;no set DrakeDragonRaceQuest.forcehelmet to 0 endif MessageBoxEX "Dragon Race > Forced unequipping:%rDo You want the lowerbody/legs slot to be forced?%r(Only relevant, if it is in Dragon shape.)|Yes|No" set DrakeDragonRaceQuest.doConfig to 8 endif return elseif(DrakeDragonRaceQuest.doConfig == 8) ;lowerbody set choice to getButtonPressed if(choice > -1) if(choice == 0) ;yes set DrakeDragonRaceQuest.forcelower to 1 elseif(choice == 1) ;no set DrakeDragonRaceQuest.forcelower to 0 endif MessageBoxEX "Dragon Race > Forced unequipping:%rDo You want the hands slot to be forced?%r(Only relevant, if it is in Dragon shape.)|Yes|No" set DrakeDragonRaceQuest.doConfig to 9 endif return elseif(DrakeDragonRaceQuest.doConfig == 9) ;hands set choice to getButtonPressed if(choice > -1) if(choice == 0) ;yes set DrakeDragonRaceQuest.forcehands to 1 elseif(choice == 1) ;no set DrakeDragonRaceQuest.forcehands to 0 endif MessageBoxEX "Dragon Race > Forced unequipping:%rDo You want the feet slot to be forced?%r(Only relevant, if it is in Dragon shape.)|Yes|No" set DrakeDragonRaceQuest.doConfig to 10 endif return elseif(DrakeDragonRaceQuest.doConfig == 10) ;feet set choice to getButtonPressed if(choice > -1) if(choice == 0) ;yes set DrakeDragonRaceQuest.forcefeet to 1 elseif(choice == 1) ;no set DrakeDragonRaceQuest.forcefeet to 0 endif MessageBoxEX "Dragon Race > Forced unequipping:%rDo You want the tail slot to be forced?%r(Only relevant, if tail or wings were selected.)|Yes|No" set DrakeDragonRaceQuest.doConfig to 11 endif return elseif(DrakeDragonRaceQuest.doConfig == 11) ;tail set choice to getButtonPressed if(choice > -1) if(choice == 0) ;yes set DrakeDragonRaceQuest.forcetail to 1 elseif(choice == 1) ;no set DrakeDragonRaceQuest.forcetail to 0 endif MessageBoxEX "Dragon Race > Forced unequipping:%rBy default this will also affect items%rcovering more than 1 slot at once,%r(e.g. The Arena Raiments or DB Armor)%rleaving actors running around naked,%rif they weren't adapted yet.%rDo You wish to make an exception%rto allow non-fitting combined-slot items?|Yes|No" set DrakeDragonRaceQuest.doConfig to 12 endif return elseif(DrakeDragonRaceQuest.doConfig == 12) ;combined-slot items exception set choice to getButtonPressed if(choice > -1) if(choice == 0) ;yes set DrakeDragonRaceQuest.forcecombined to 0 elseif(choice == 1) ;no set DrakeDragonRaceQuest.forcecombined to 1 endif set DrakeDragonRaceQuest.doConfig to 13 endif return elseif(DrakeDragonRaceQuest.doConfig == 13) ;finish MessageBoxEX "Dragon Race: Thank You for your time.%rYour Dragon race should now be successfully configured.%rIf You wish to do this again, just type%r'startquest DrakeDragonRaceConfigQuest'%rinto the console.%rIf You called this in the middle of a game,%rYou might need to reequip your clothing,%rfor the changes to take effect!" set DrakeDragonRaceQuest.doConfig to 0 stopQuest DrakeDragonRaceConfigQuest else ;either coming from racequest init (-1) or from startquest via console (0) set DrakeDragonRaceQuest.doConfig to 1 endifend
Once this script exists assign it to your newly created quest.
The new and improved main control quest script:
scn DrakeDragonRaceQuestScriptlong adaptedItemsArraylong itemsDCpartcArraylong itemsDCpartfArraylong itemsDCpartcfArraylong itemsDCpartArraylong itemsDCpartfoArraylong itemsDCpartfcArrayshort showclawsshort showfeetshort showtailshort showwingsshort showhelmetshort forcehelmetshort forceuppershort forcelowershort forcehandsshort forcefeetshort forcetailshort forcecombinedshort initshort initArraysshort debugshort debugShowRaceTokenshort debugShowRevTokenshort doConfigshort choicearray_var confArrayarray_var itemArrayarray_var defaultItemArrayarray_var tempArrayarray_var itemstring_var raceIdlong framesToSkiplong itemsRevertPerFrameref sourceref actorRacefloat timerfloat playerXfloat playerYfloat playerZfloat fQuestDelayTimebegin gameMode set fQuestDelayTime to 0.5 if(init == 0) if(getOBSEVersion < 18) MessageBoxEX "Dragon Race:%rCurrent release requires OBSE v0018 beta 5 or higher to run.%rYou don't have a proper version of OBSE!" set init to -1 return endif if(initArrays == 0) let itemArray := ar_Construct StringMap let itemArray["original"] := ar_Construct StringMap ;let itemArray["original"][x] := original_BaseId let itemArray["dcpartc"] := ar_Construct StringMap let itemArray["dcpartf"] := ar_Construct StringMap let itemArray["dcpartcf"] := ar_Construct StringMap let itemArray["dcpartw"] := ar_Construct StringMap let itemArray["dcpartt"] := ar_Construct StringMap let itemArray["dcpartwt"] := ar_Construct StringMap let itemArray["dcpart"] := ar_Construct StringMap ;let itemArray[tagCode][x] := adapted_BaseId ;matching indices "x"! set initArrays to 1 endif set showhelmet to 1 set showclaws to 1 set showfeet to 1 set showtail to 1 set showwings to 1 set forcehelmet to 0 set forceupper to 0 set forcelower to 1 set forcehands to 1 set forcefeet to 1 set forcetail to 1 set forcecombined to 0 let confArray := ar_Construct StringMap let confArray["races"] := ar_Construct StringMap let confArray["races"]["dragon"] := DrakeDragon let confArray["races"]["dragonblack"] := DrakeDragonBlack let confArray["races"]["dragonredgold"] := DrakeDragonRedGold foreach item <- confArray["races"] let raceId := item["key"] let confArray[raceId] := ar_Construct Array let confArray[raceId][0] := ar_Construct StringMap let confArray[raceId][0]["slotname"] := "upperbody" let confArray[raceId][0]["slotmask"] := 4 let confArray[raceId][0]["combinations"] := ar_Construct Array let confArray[raceId][0]["combinations"][0] := ar_Construct StringMap let confArray[raceId][0]["combinations"][0]["tag"] := "dcpartc" let confArray[raceId][0]["combinations"][0]["req"] := eval (showclaws == 1 && showfeet == 0) let confArray[raceId][0]["combinations"][1] := ar_Construct StringMap let confArray[raceId][0]["combinations"][1]["tag"] := "dcpartf" let confArray[raceId][0]["combinations"][1]["req"] := eval (showclaws == 0 && showfeet == 1) let confArray[raceId][0]["combinations"][2] := ar_Construct StringMap let confArray[raceId][0]["combinations"][2]["tag"] := "dcpartcf" let confArray[raceId][0]["combinations"][2]["req"] := eval (showclaws == 1 && showfeet == 1) let confArray[raceId][0]["combinations"][3] := ar_Construct StringMap let confArray[raceId][0]["combinations"][3]["tag"] := "dcpart" let confArray[raceId][0]["combinations"][3]["req"] := showclaws let confArray[raceId][0]["forced"] := forceupper let confArray[raceId][1] := ar_Construct StringMap let confArray[raceId][1]["slotname"] := "lowerbody" let confArray[raceId][1]["slotmask"] := 8 let confArray[raceId][1]["combinations"] := ar_Construct Array let confArray[raceId][1]["combinations"][0] := ar_Construct StringMap let confArray[raceId][1]["combinations"][0]["tag"] := "dcpart" let confArray[raceId][1]["combinations"][0]["req"] := showfeet let confArray[raceId][1]["forced"] := forcelower let confArray[raceId][2] := ar_Construct StringMap let confArray[raceId][2]["slotname"] := "hands" let confArray[raceId][2]["slotmask"] := 16 let confArray[raceId][2]["combinations"] := ar_Construct Array let confArray[raceId][2]["combinations"][0] := ar_Construct StringMap let confArray[raceId][2]["combinations"][0]["tag"] := "dcpart" let confArray[raceId][2]["combinations"][0]["req"] := showclaws let confArray[raceId][2]["forced"] := forcehands let confArray[raceId][3] := ar_Construct StringMap let confArray[raceId][3]["slotname"] := "feet" let confArray[raceId][3]["slotmask"] := 32 let confArray[raceId][3]["combinations"] := ar_Construct Array let confArray[raceId][3]["combinations"][0] := ar_Construct StringMap let confArray[raceId][3]["combinations"][0]["tag"] := "dcpart" let confArray[raceId][3]["combinations"][0]["req"] := showfeet let confArray[raceId][3]["forced"] := forcefeet let confArray[raceId][4] := ar_Construct StringMap let confArray[raceId][4]["slotname"] := "hair" let confArray[raceId][4]["slotmask"] := 2 let confArray[raceId][4]["combinations"] := ar_Construct Array let confArray[raceId][4]["combinations"][0] := ar_Construct StringMap let confArray[raceId][4]["combinations"][0]["tag"] := "dcpart" let confArray[raceId][4]["combinations"][0]["req"] := showhelmet let confArray[raceId][4]["forced"] := forcehelmet let confArray[raceId][5] := ar_Construct StringMap let confArray[raceId][5]["slotname"] := "tail" let confArray[raceId][5]["slotmask"] := 32768 let confArray[raceId][5]["combinations"] := ar_Construct Array let confArray[raceId][5]["combinations"][0] := ar_Construct StringMap let confArray[raceId][5]["combinations"][0]["tag"] := "dcpartt" let confArray[raceId][5]["combinations"][0]["req"] := eval (showtail == 1 && showwings == 0) let confArray[raceId][5]["combinations"][1] := ar_Construct StringMap let confArray[raceId][5]["combinations"][1]["tag"] := "dcpartw" let confArray[raceId][5]["combinations"][1]["req"] := eval (showtail == 0 && showwings == 1) let confArray[raceId][5]["combinations"][2] := ar_Construct StringMap let confArray[raceId][5]["combinations"][2]["tag"] := "dcpartwt" let confArray[raceId][5]["combinations"][2]["req"] := eval (showtail == 1 && showwings == 1) let confArray[raceId][5]["combinations"][3] := ar_Construct StringMap let confArray[raceId][5]["combinations"][3]["tag"] := "dcpart" let confArray[raceId][5]["combinations"][3]["req"] := eval (showtail == 1 && showwings == 1) let confArray[raceId][5]["forced"] := forcetail Loop let defaultItemArray := ar_Construct StringMap let defaultItemArray["hair"] := ar_Construct StringMap let defaultItemArray["hair"]["dcpart"] := DrakeEmptyItem let defaultItemArray["upperbody"] := ar_Construct StringMap let defaultItemArray["upperbody"]["dcpartc"] := DrakeDragonUpperbody let defaultItemArray["upperbody"]["dcpartf"] := DrakeEmptyItem let defaultItemArray["upperbody"]["dcpartcf"] := DrakeDragonUpperbody let defaultItemArray["upperbody"]["dcpart"] := DrakeDragonUpperbody let defaultItemArray["lowerbody"] := ar_Construct StringMap let defaultItemArray["lowerbody"]["dcpart"] := DrakeDragonLegs let defaultItemArray["hands"] := ar_Construct StringMap let defaultItemArray["hands"]["dcpart"] := DrakeDragonClaws let defaultItemArray["feet"] := ar_Construct StringMap let defaultItemArray["feet"]["dcpart"] := DrakeDragonFeet let defaultItemArray["tail"] := ar_Construct StringMap let defaultItemArray["tail"]["dcpartt"] := DrakeDragonTail let defaultItemArray["tail"]["dcpartw"] := DrakeDragonWings let defaultItemArray["tail"]["dcpartwt"] := DrakeDragonWingsTail let defaultItemArray["tail"]["dcpart"] := DrakeEmptyItem let tempArray := ar_Construct StringMap set framesToSkip to 10 set itemsRevertPerFrame to 100 MessageBoxEX "Dragon Race:%rAll requirements met. Arrays initialized successfully." set doConfig to -1 startQuest DrakeDragonRaceConfigQuest set init to 1 endif if(doConfig != 0) ;stay idle until config menu is done return endif foreach item <- confArray["races"] let raceId := item["key"] ;update shape shift settings, just in case let confArray[raceId][0]["combinations"][0]["req"] := eval (showclaws == 1 && showfeet == 0) let confArray[raceId][0]["combinations"][1]["req"] := eval (showclaws == 0 && showfeet == 1) let confArray[raceId][0]["combinations"][2]["req"] := eval (showclaws == 1 && showfeet == 1) let confArray[raceId][0]["combinations"][3]["req"] := showclaws let confArray[raceId][1]["combinations"][0]["req"] := showfeet let confArray[raceId][2]["combinations"][0]["req"] := showclaws let confArray[raceId][3]["combinations"][0]["req"] := showfeet let confArray[raceId][4]["combinations"][0]["req"] := showhelmet let confArray[raceId][5]["combinations"][0]["req"] := eval (showtail == 1 && showwings == 0) let confArray[raceId][5]["combinations"][1]["req"] := eval (showtail == 0 && showwings == 1) let confArray[raceId][5]["combinations"][2]["req"] := eval (showtail == 1 && showwings == 1) ;update forced unequipping, just in case let confArray[raceId][0]["forced"] := forceupper let confArray[raceId][1]["forced"] := forcelower let confArray[raceId][2]["forced"] := forcehands let confArray[raceId][3]["forced"] := forcefeet let confArray[raceId][4]["forced"] := forcehelmet let confArray[raceId][5]["forced"] := forcetail Loop if(actorRace != player.getRace) set actorRace to player.getRace let raceId := ar_Find actorRace confArray["races"] if eval (raceId != "") if(player.getItemCount DrakeDragonRaceToken < 1) player.addItemNS DrakeDragonRaceToken 1 endif else if(player.getItemCount DrakeDragonRaceReverterToken < 1) player.addItemNS DrakeDragonRaceReverterToken 1 endif endif endif set source to DrakeDragonRaceScanner ;move into new cell with player and reset count so spell is cast immediately if(source.getInSameCell player != 1) source.moveTo player set timer to 0 endif if(timer <= 0) set playerX to player.getPos X source.setPos X playerX set playerY to player.getPos Y source.setPos Y playerY set playerZ to player.getPos Z source.setPos Z playerZ source.cast DrakeDragonRaceScannerAura player set timer to 1 else set timer to (timer - getSecondsPassed) endifend
Notice the "itemArray" initialization being isolated inside its own do-once condition? If all's well, then this should make updating between existing savegames much easier now.
The whole configuration menu thing was exported into its own quest script, the "confArray"'s slots are indexed by numbers now, as I realized "foreach" is iterating an alphabetically "sorted" array with string indices and not in the order I created it in, which caused trouble with combined adapted items most likely not being equipped properly because "upperbody" was not the 1st slot to be processed as intended, the replacer template array vanished in favor of the new user-function-driven design, and quite some other minor changes.
Note: The checks for requirements like OBSE are still not improved, as you can see in the unaltered GetOBSEVersion line close to the top!Now, there's one more user-function to be created, which will shorten the token scripts always containing the same twice, in menumode and in gamemode, drastically:
scn DrakeDragonRaceTokenFunctionarray_var confArrayarray_var repeatArrayref actorRefshort actorFemaleshort slotNumref oldslotContentarray_var itemArrayarray_var defaultItemArrayref actslotContentref tempItemref tempItem2short switchItemsshort wearsAdaptedshort foundAdaptedshort requirementshort foundRequirementshort currentRequirementshort slotCodeshort index2short slotEnforcedlong slotMasklong tempNumarray_var itemarray_var item2string_var slotIdstring_var indexstring_var tagIdstring_var tagCodestring_var currentlyWearingstring_var shouldBeWearingfloat healthBufferbegin Function {confArray, repeatArray, actorRef, actorFemale, slotNum, oldslotContent} let itemArray := DrakeDragonRaceQuest.itemArray let defaultItemArray := DrakeDragonRaceQuest.defaultItemArray ;check slot for changes let slotId := confArray[slotNum]["slotname"] let slotMask := confArray[slotNum]["slotmask"] set actslotContent to (actorRef.getEquipmentSlotMask slotMask) set slotEnforced to 0 if eval (confArray[slotNum]["forced"] == 1) ;forced unequipping for this slot if eval (getBipedSlotMask actslotContent == slotMask || DrakeDragonRaceQuest.forcecombined == 1 || getBipedSlotMask actslotContent == 1 + 2) ;must not be a combined-slot item or combined-slot items exception must be turned off, full-helmets being an exception set slotEnforced to 1 endif endif if eval (actslotContent != oldslotContent || repeatArray[slotId] == 1) let index := "" let index2 := ar_First confArray[slotNum]["combinations"] While eval ((index == "") && (index2 != ar_BadNumericIndex)) let tagId := confArray[slotNum]["combinations"][index2]["tag"] let index := ar_Find oldslotContent itemArray[tagId] let index2 := ar_Next confArray[slotNum]["combinations"] index2 Loop if eval (index != "") ;needs exchange if(actorRef.getItemCount oldslotContent > 0) let tempItem := itemArray["original"][index] actorRef.removeItemNS oldslotContent 1 actorRef.addItemNS tempItem 1 endif endif let shouldBeWearing := "original" set foundAdapted to 0 set foundRequirement to 0 ForEach item2 <- confArray[slotNum]["combinations"] let tagId := item2["value"]["tag"] if eval (item2["key"] == ar_Last confArray[slotNum]["combinations"]) let tagCode := "_" + tagId else let tagCode := "_" + tagId + ".nif" endif let requirement := item2["value"]["req"] if(actorFemale == 1 && isBipedModelPathValid 1 actslotContent == 1) set wearsAdapted to compareFemaleBipedPath $tagCode actslotContent else set wearsAdapted to compareMaleBipedPath $tagCode actslotContent endif if(wearsAdapted == 1 && foundAdapted != 1) ;always take the 1st one set foundAdapted to 1 let currentlyWearing := tagId set currentRequirement to requirement endif if(requirement == 1 && foundRequirement != 1) ;always take the 1st one set foundRequirement to 1 let shouldBeWearing := tagId endif Loop set switchItems to 0 if(foundAdapted == 1) ;is wearing an adapted item if(foundRequirement == 1) ;only if slot in question should be controlled according to selected shape if(currentRequirement == 0) ;in case of shape shifting races and worn adapted item not fitting selected shape let index := ar_Find actslotContent itemArray[currentlyWearing] if eval (index != "") ;safety check let tempItem := itemArray[shouldBeWearing][index] set switchItems to 1 endif endif else ;is wearing adapted item or bodypart but should not let index := ar_Find actslotContent itemArray[currentlyWearing] if eval (index != "") ;no bodypart let tempItem := itemArray["original"][index] set switchItems to 1 else ;bodypart set tempItem to 0 set switchItems to 2 endif endif else ;not wearing any adapted item if(foundRequirement == 1) ;only if slot in question should be controlled according to selected shape if(actslotContent != 0) ;normal clothing let index := ar_Find actslotContent itemArray["original"] if eval (index != "") ;already an adapted present if eval (ar_HasKey itemArray[shouldBeWearing] index) let tempItem := itemArray[shouldBeWearing][index] else let tempItem := itemArray[(ar_Last itemArray)][index] endif set switchItems to 1 else ;try to find adapted item set switchItems to 3 endif else ;empty let tempItem := defaultItemArray[slotId][shouldBeWearing] set switchItems to 2 endif endif endif ;handle updates let repeatArray[slotId] := 0 if(switchItems == 1 && tempItem != 0 && tempItem != DrakeEmptyItem) ;just swap if(actorFemale == 1 && isBipedModelPathValid 1 tempItem == 1) set wearsAdapted to compareFemaleBipedPath $tagCode tempItem else set wearsAdapted to compareMaleBipedPath $tagCode tempItem endif if(wearsAdapted == 1) ;has passed gender-dependent validity check above set slotCode to getEquipmentSlot actslotContent set healthBuffer to actorRef.getEquippedCurrentHealth slotCode actorRef.addItemNS tempItem 1 actorRef.equipItemNS tempItem actorRef.removeItemNS actslotContent 1 actorRef.setEquippedCurrentHealth healthBuffer slotCode else set switchItems to 3 ;use replacer template for missing gender for the time being endif endif if(switchItems == 2) ;equip bodyparts if(tempItem == 0 || tempItem == DrakeEmptyItem) actorRef.unequipItemNS actslotContent else actorRef.equipItemNS tempItem endif endif if(switchItems == 3) ;check for presence of alternatives let index := ar_Find actslotContent itemArray["original"] ;first check if we're coming from switchItems == 1 if eval (index == "") let index := $(ar_Size itemArray["original"]) ;else proceed creating a new entry as usual endif ForEach item2 <- confArray[slotNum]["combinations"] let tagId := item2["value"]["tag"] let tagCode := ".nif|_" + tagId + ".nif" if(isBipedModelPathValid 0 actslotContent == 0 || isBipedModelPathValid 1 actslotContent == 0) ;at least one gender is missing from the start if(slotEnforced == 1) ;forced unequipping for this slot let tempItem2 := Call DrakeDragonRaceReplacerSelectFunction slotId confArray actslotContent ;determine fitting replacer template for current settings and item to replace visuals of endif endif if(isBipedModelPathValid 0 actslotContent == 1) copyMaleBipedPath actslotContent DrakeTempItem else setMaleBipedPath "empty" DrakeTempItem if(slotEnforced == 1) ;forced unequipping for this slot if(tempItem2 != DrakeEmptyItem && tempItem2 != 0) if(isBipedModelPathValid 0 tempItem2 == 1) copyMaleBipedPath tempItem2 DrakeTempItem endif endif endif endif modMaleBipedPath $tagCode DrakeTempItem if(isBipedModelPathValid 1 actslotContent == 1) copyFemaleBipedPath actslotContent DrakeTempItem else setFemaleBipedPath "empty" DrakeTempItem if(slotEnforced == 1) ;forced unequipping for this slot if(tempItem2 != DrakeEmptyItem && tempItem2 != 0) if(isBipedModelPathValid 1 tempItem2 == 1) copyFemaleBipedPath tempItem2 DrakeTempItem endif endif endif endif modFemaleBipedPath $tagCode DrakeTempItem if(isBipedModelPathValid 0 DrakeTempItem == 0 || isBipedModelPathValid 1 DrakeTempItem == 0) ;at least one gender is missing adapted clothing if(slotEnforced == 1) ;forced unequipping for this slot let tempItem2 := Call DrakeDragonRaceReplacerSelectFunction slotId confArray actslotContent ;determine fitting replacer template for current settings and item to replace visuals of endif endif if(isBipedModelPathValid 0 DrakeTempItem == 1 || isBipedModelPathValid 1 DrakeTempItem == 1 || slotEnforced == 1) ;adapted clothing exists for at least one gender or forced unequipping for this slot if eval ((ar_HasKey itemArray["original"] index) == 0) let itemArray["original"][index] := actslotContent ;do this only once endif if eval ((ar_HasKey itemArray[tagId] index) == 0) set tempItem to cloneForm actslotContent ;create new entry else let tempItem := itemArray[tagId][index] ;update existing one instead endif endif if(isBipedModelPathValid 0 DrakeTempItem == 1) ; male does exist copyMaleBipedPath DrakeTempItem tempItem else if(slotEnforced == 1) ;forced unequipping for this slot setMaleBipedPath "empty" tempItem if(tempItem2 != DrakeEmptyItem && tempItem2 != 0) if(isBipedModelPathValid 0 tempItem2 == 1) copyMaleBipedPath tempItem2 tempItem modMaleBipedPath $tagCode tempItem endif endif endif endif if(isBipedModelPathValid 1 DrakeTempItem == 1) ; female does exist copyFemaleBipedPath DrakeTempItem tempItem else if(slotEnforced == 1) ;forced unequipping for this slot setFemaleBipedPath "empty" tempItem if(tempItem2 != DrakeEmptyItem && tempItem2 != 0) if(isBipedModelPathValid 1 tempItem2 == 1) copyFemaleBipedPath tempItem2 tempItem modFemaleBipedPath $tagCode tempItem endif endif endif endif let itemArray[tagId][index] := tempItem Loop if eval (ar_HasKey itemArray["original"] index) ;at least 1 adapted clothing was found during foreach let repeatArray[slotId] := 1 ;do exchange next frame else ;no adapted clothing found if(slotEnforced == 1) ;forced unequipping for this slot let tempItem := defaultItemArray[slotId][shouldBeWearing] if(tempItem == 0 || tempItem == DrakeEmptyItem) actorRef.unequipItemNS actslotContent else actorRef.equipItemNS tempItem endif endif endif endif endif ;clean up string_vars sv_Destruct slotId sv_Destruct index sv_Destruct tagId sv_Destruct tagCode sv_Destruct currentlyWearing sv_Destruct shouldBeWearingend
Well, here's a "hopefully" neat and clever way to keep track of all tokens ever provided to actors, be it NPCs or the player, race control tokens or reverter tokens.
This little invention manages a list of actors which already got a token.
It checks for "internal" version numbers of these in its arrays and will immediately replace any left-over tokens with out-dated scripts (in case a token's script didn't update, don't know if it can happen at all, but now this system will know when, just in case).
Also if it finds any tokens on actors not in its list, it replaces them right away with proper ones.
The tokens should regularly update their respective "timeout" records in its lists, while the tracker itself will make them count down, and whenever one of these entries reaches "0", which usually means its token didn't update for a long time, i.e. "is dead", it will be removed and, if necessary, replaced by a working one.
Now whenever a script on a token stalls for whatever reason, it will stop resetting its timeout and thus ultimately end up being removed and replaced.
As an additional bonus feature, now that I always have a list of all provided race control and reverter tokens and the actors carrying them, I can also easily implement something to remove all race control tokens, revert all items in inventories and then remove all reverter tokens either, before uninitializing and shutting down the main control quest, so you can safely update a running game with new releases of my scripts in the future.
Well, if everything turns out as planned, that is, I think this little feature will come in really handy.
Alright, here's the quest script for the new quest "DrakeDragonRaceTokenTrackingQuest", "start game enabled" and nothing else:
scn DrakeDragonRaceTokenTrackingQuestScriptarray_var actorArrayarray_var raceTokenArrayarray_var reverterTokenArrayshort initshort timeOutCountshort replaceRaceTokenshort replaceReverterTokenstring_var index1string_var index2string_var versionNumberref containerReffloat fQuestDelayTimebegin gameMode set fQuestDelayTime to 0.5 if(init == 0) let actorArray := ar_Construct StringMap let raceTokenArray := ar_Construct StringMap let reverterTokenArray := ar_Construct StringMap let versionNumber := "0.0.7_0.0" set timeOutCount to 100 let index1 := "" let index2 := "" set init to 1 endif if eval ((ar_Size raceTokenArray) > 0) if eval (index1 == "" || index1 == ar_Last raceTokenArray) let index1 := ar_First raceTokenArray endif set replaceRaceToken to 0 let containerRef := actorArray[index1] if(containerRef != 0) if eval (raceTokenArray[index1]["version"] != versionNumber) set replaceRaceToken to 1 endif if eval (raceTokenArray[index1]["timeout"] > 0) let raceTokenArray[index1]["timeout"] := raceTokenArray[index1]["timeout"] - 1 else set replaceRaceToken to 1 endif if(replaceRaceToken == 1) if(containerRef.getItemCount DrakeDragonRaceToken > 0) containerRef.removeItemNS DrakeDragonRaceToken 1 endif if(containerRef.getInSameCell player == 1) containerRef.addItemNS DrakeDragonRaceToken 1 endif endif endif let index1 := ar_Next raceTokenArray index1 endif if eval ((ar_Size reverterTokenArray) > 0) if eval (index2 == "" || index2 == ar_Last reverterTokenArray) let index2 := ar_First reverterTokenArray endif set replaceReverterToken to 0 let containerRef := actorArray[index2] if(containerRef != 0) if eval (reverterTokenArray[index2]["timeout"] > 0) let reverterTokenArray[index2]["timeout"] := reverterTokenArray[index2]["timeout"] - 1 else set replaceReverterToken to 1 endif if(replaceReverterToken == 1) if(containerRef.getItemCount DrakeDragonRaceReverterToken > 0) containerRef.removeItemNS DrakeDragonRaceReverterToken 1 endif if(containerRef.getInSameCell player == 1) containerRef.addItemNS DrakeDragonRaceReverterToken 1 endif endif endif let index2 := ar_Next reverterTokenArray index2 endifend
The new spell script for the scanner aura:
scn DrakeDragonRaceScannerAuraScriptshort GAT ; GetActorTypearray_var confArrayarray_var actorArrayarray_var raceTokenArrayarray_var reverterTokenArraystring_var raceIdstring_var indexref actorRefbegin scriptEffectUpdate if(DrakeDragonRaceQuest.init != 1 || DrakeDragonRaceTokenTrackingQuest.init != 1) dispel DrakeDragonRaceScannerAura return endif let confArray := DrakeDragonRaceQuest.confArray let actorArray := DrakeDragonRaceTokenTrackingQuest.actorArray let raceTokenArray := DrakeDragonRaceTokenTrackingQuest.raceTokenArray let reverterTokenArray := DrakeDragonRaceTokenTrackingQuest.reverterTokenArray set GAT to (getIsCreature * 8) + (getIsGhost) + (getVampire * 2) + (isActor) + (isEssential * 4) - 1 if(getIsReference player == 1 || (GAT >= 0 && GAT < 8)) ; only run on actors and only on NPCs, dont run on creatures! set actorRef to getSelf let index := ar_Find actorRef actorArray if eval (index == "") ;not in list, must be a non-tracked one if(getItemCount DrakeDragonRaceReverterToken > 0) removeItemNS DrakeDragonRaceReverterToken 1 endif if(getItemCount DrakeDragonRaceToken > 0) removeItemNS DrakeDragonRaceToken 1 endif endif let raceId := ar_Find (getRace) confArray["races"] if eval (raceId == "") ;definitely is NOT a Dragon if(getItemCount DrakeDragonRaceReverterToken < 1) addItemNS DrakeDragonRaceReverterToken 1 endif else if(getItemCount DrakeDragonRaceToken < 1) addItemNS DrakeDragonRaceToken 1 endif endif endif if(getItemCount DrakeDragonEyeSensesMarker < 1) addItemNS DrakeDragonEyeSensesMarker 1 endif dispel DrakeDragonRaceScannerAuraend
The new race control token script:
scn DrakeDragonRaceTokenScriptref actorRefref actorRaceref actslotContentref oldslotContentref tempItemshort initshort actorFemaleshort switchItemsshort wearsAdaptedshort foundAdaptedshort requirementshort foundRequirementshort currentRequirementshort slotCodeshort slotNumshort index2long frameNumlong slotMasklong tempNumarray_var confArrayarray_var itemArrayarray_var defaultItemArrayarray_var slotArrayarray_var repeatArrayarray_var keysArrayarray_var itemarray_var item2array_var actorArrayarray_var raceTokenArrayarray_var reverterTokenArraystring_var indexstring_var tagIdstring_var tagCodestring_var currentlyWearingstring_var shouldBeWearingstring_var slotIdstring_var raceIdstring_var actorIdfloat healthBufferbegin gameMode if eval(-1 == ar_Size confArray) set init to 0 endif if(init != 1) set actorRef to 0 if(DrakeDragonRaceQuest.init != 1) return endif if(DrakeDragonRaceTokenTrackingQuest.init != 1) return endif let confArray := DrakeDragonRaceQuest.confArray let itemArray := DrakeDragonRaceQuest.itemArray let defaultItemArray := DrakeDragonRaceQuest.defaultItemArray let actorArray := DrakeDragonRaceTokenTrackingQuest.actorArray let raceTokenArray := DrakeDragonRaceTokenTrackingQuest.raceTokenArray let reverterTokenArray := DrakeDragonRaceTokenTrackingQuest.reverterTokenArray let slotArray := ar_Construct StringMap let repeatArray := ar_Construct StringMap let actorId := "" set frameNum to 0 set actorFemale to -1 set init to 1 endif if(actorRef == 0) set actorRef to getContainer return endif if(actorFemale == -1) set actorFemale to actorRef.isFemale endif if(DrakeDragonRaceQuest.debug == 1 && DrakeDragonRaceQuest.debugShowRaceToken == 1) actorRef.playMagicShaderVisuals DrakeDEFriendlyDetectedXR else actorRef.stopMagicShaderVisuals DrakeDEFriendlyDetectedXR endif if(actorRace != actorRef.getRace) set actorRace to actorRef.getRace let confArray := DrakeDragonRaceQuest.confArray let raceId := ar_Find actorRace confArray["races"] if eval (raceId != "") let confArray := confArray[raceId] ;race-specific part of confArray let keysArray := ar_Keys confArray ForEach item <- keysArray let slotNum := item["value"] let slotId := confArray[slotNum]["slotname"] let slotArray[slotId] := DrakeEmptyItem ;initialize empty let repeatArray[slotId] := 0 Loop set slotNum to 0 let slotId := "" if(DrakeDragonRaceQuest.debug == 1 && actorRef.getIsReference player == 1) printToConsole "Player race identified as dragon." endif else ;is not a dragon, remove bodyparts, if present! ForEach item <- defaultItemArray ForEach item2 <- item["value"] let tempItem := item2["value"] set tempNum to actorRef.getItemCount tempItem if(tempItem != DrakeEmptyItem && tempNum > 0) actorRef.removeItemNS tempItem tempNum endif Loop Loop if(DrakeDragonRaceQuest.debug == 1 && actorRef.getIsReference player == 1) printToConsole "Player race identified as NON-dragon!" endif removeMe ;is not a dragon, should not have this! endif return endif if eval (actorId == "") let actorId := ar_Find actorRef actorArray if eval (actorId == "") let actorId := $(ar_Size actorArray) let actorArray[actorId] := actorRef ;add actor to tracking list endif return endif if(frameNum < DrakeDragonRaceQuest.framesToSkip) set frameNum to (frameNum + 1) return ;dont run every frame endif if eval (ar_HasKey raceTokenArray actorId == 0) ;initialize let raceTokenArray[actorId] := ar_Construct StringMap let raceTokenArray[actorId]["version"] := DrakeDragonRaceTokenTrackingQuest.versionNumber let raceTokenArray[actorId]["timeout"] := DrakeDragonRaceTokenTrackingQuest.timeOutCount else let raceTokenArray[actorId]["timeout"] := DrakeDragonRaceTokenTrackingQuest.timeOutCount ;keep i-am-alive ticker ticking endif if eval (slotNum <= 0 || slotNum == ar_Last confArray) let slotNum := ar_First confArray set frameNum to 0 ;finished all slots this run endif let slotId := confArray[slotNum]["slotname"] if(actorRef.getInSameCell player != 1) if(DrakeDragonRaceQuest.debug == 1 && DrakeDragonRaceQuest.debugShowRaceToken == 1) actorRef.stopMagicShaderVisuals DrakeDEFriendlyDetectedXR endif set init to 0 removeMe endif ;provide with bodyparts ForEach item2 <- defaultItemArray[slotId] let tempItem := item2["value"] if(tempItem != DrakeEmptyItem && actorRef.getItemCount tempItem < 1) actorRef.addItemNS tempItem 1 endif Loop let oldslotContent := slotArray[slotId] Call DrakeDragonRaceTokenFunction confArray, repeatArray, actorRef, actorFemale, slotNum, oldslotContent let slotMask := confArray[slotNum]["slotmask"] set oldslotContent to (actorRef.getEquipmentSlotMask slotMask) let slotArray[slotId] := oldslotContent let slotNum := ar_Next confArray slotNum ;proceed with next slot next frameendbegin menuMode 1002 || 1008 if eval(-1 == ar_Size confArray) set init to 0 endif if(init != 1) set actorRef to 0 if(DrakeDragonRaceQuest.init != 1) return endif if(DrakeDragonRaceTokenTrackingQuest.init != 1) return endif let confArray := DrakeDragonRaceQuest.confArray let itemArray := DrakeDragonRaceQuest.itemArray let defaultItemArray := DrakeDragonRaceQuest.defaultItemArray let actorArray := DrakeDragonRaceTokenTrackingQuest.actorArray let raceTokenArray := DrakeDragonRaceTokenTrackingQuest.raceTokenArray let reverterTokenArray := DrakeDragonRaceTokenTrackingQuest.reverterTokenArray let slotArray := ar_Construct StringMap let repeatArray := ar_Construct StringMap let actorId := "" set frameNum to 0 set actorFemale to -1 set init to 1 endif if(actorRef == 0) set actorRef to getContainer return endif if(actorRef.getIsReference player != 1) return ;NPCs don't need control during MenuMode endif if(actorFemale == -1) set actorFemale to actorRef.isFemale endif if(actorRace != actorRef.getRace) set actorRace to actorRef.getRace let confArray := DrakeDragonRaceQuest.confArray let raceId := ar_Find actorRace confArray["races"] if eval (raceId != "") let confArray := confArray[raceId] ;race-specific part of confArray let keysArray := ar_Keys confArray ForEach item <- keysArray let slotNum := item["value"] let slotId := confArray[slotNum]["slotname"] let slotArray[slotId] := DrakeEmptyItem ;initialize empty let repeatArray[slotId] := 0 Loop set slotNum to 0 let slotId := "" if(DrakeDragonRaceQuest.debug == 1 && actorRef.getIsReference player == 1) printToConsole "Player race identified as dragon." endif else ;is not a dragon, remove bodyparts, if present! ForEach item <- defaultItemArray ForEach item2 <- item["value"] let tempItem := item2["value"] set tempNum to actorRef.getItemCount tempItem if(tempItem != DrakeEmptyItem && tempNum > 0) actorRef.removeItemNS tempItem tempNum endif Loop Loop if(DrakeDragonRaceQuest.debug == 1 && actorRef.getIsReference player == 1) printToConsole "Player race identified as NON-dragon!" endif removeMe ;is not a dragon, should not have this! endif return endif if eval (actorId == "") let actorId := ar_Find actorRef actorArray if eval (actorId == "") let actorId := $(ar_Size actorArray) let actorArray[actorId] := actorRef ;add actor to tracking list endif return endif if(frameNum < DrakeDragonRaceQuest.framesToSkip) set frameNum to (frameNum + 1) return ;dont run every frame endif if eval (ar_HasKey raceTokenArray actorId == 0) ;initialize let raceTokenArray[actorId] := ar_Construct StringMap let raceTokenArray[actorId]["version"] := DrakeDragonRaceTokenTrackingQuest.versionNumber let raceTokenArray[actorId]["timeout"] := DrakeDragonRaceTokenTrackingQuest.timeOutCount else let raceTokenArray[actorId]["timeout"] := DrakeDragonRaceTokenTrackingQuest.timeOutCount ;keep i-am-alive ticker ticking endif if eval (slotNum <= 0 || slotNum == ar_Last confArray) let slotNum := ar_First confArray set frameNum to 0 ;finished all slots this run endif let slotId := confArray[slotNum]["slotname"] if(actorRef.getInSameCell player != 1) if(DrakeDragonRaceQuest.debug == 1 && DrakeDragonRaceQuest.debugShowRaceToken == 1) actorRef.stopMagicShaderVisuals DrakeDEFriendlyDetectedXR endif set init to 0 removeMe endif ;provide with bodyparts ForEach item2 <- defaultItemArray[slotId] let tempItem := item2["value"] if(tempItem != DrakeEmptyItem && actorRef.getItemCount tempItem < 1) actorRef.addItemNS tempItem 1 endif Loop let oldslotContent := slotArray[slotId] call DrakeDragonRaceTokenFunction confArray, repeatArray, actorRef, actorFemale, slotNum, oldslotContent let slotMask := confArray[slotNum]["slotmask"] set oldslotContent to (actorRef.getEquipmentSlotMask slotMask) let slotArray[slotId] := oldslotContent let slotNum := ar_Next confArray slotNum ;proceed with next slot next frameend
You see how much shorter this one got by using the same user-function where previously was the whole code in both blocks?
Now I can only hope I didn't screw up the interface of this function!
And the new reverter token script:
scn DrakeDragonRaceReverterTokenScriptref actorRefref tempItemref tempItem2array_var itemarray_var item2long numItemslong endilong ilong tempNumstring_var tagIdstring_var indexlong frameNumarray_var itemArrayarray_var defaultItemArrayarray_var actorArrayarray_var raceTokenArrayarray_var reverterTokenArraystring_var actorIdshort equippedshort initshort init2float healthBuffershort slotCodebegin menuMode 1002 || 1008 if(init != 1) set actorRef to 0 if(DrakeDragonRaceQuest.init != 1) return endif if(DrakeDragonRaceTokenTrackingQuest.init != 1) return endif let itemArray := DrakeDragonRaceQuest.itemArray let defaultItemArray := DrakeDragonRaceQuest.defaultItemArray let actorArray := DrakeDragonRaceTokenTrackingQuest.actorArray let raceTokenArray := DrakeDragonRaceTokenTrackingQuest.raceTokenArray let reverterTokenArray := DrakeDragonRaceTokenTrackingQuest.reverterTokenArray let actorId := "" set frameNum to 0 set init2 to 0 set init to 1 endif if eval (-1 == ar_Size itemArray) ;shouldn't happen, but just in case if(DrakeDragonRaceQuest.debug == 1 && DrakeDragonRaceQuest.debugShowRevToken == 1) actorRef.stopMagicShaderVisuals DrakeDEHostileDetectedXR endif removeMe endif if(actorRef == 0) set actorRef to getContainer return endif if eval (actorId == "") let actorId := ar_Find actorRef actorArray if eval (actorId == "") let actorId := $(ar_Size actorArray) let actorArray[actorId] := actorRef ;add actor to tracking list endif return endif if(init2 != 1) set numItems to actorRef.getNumItems set i to (numItems - 1) set init2 to 1 endif if(frameNum < DrakeDragonRaceQuest.framesToSkip) set frameNum to (frameNum + 1) return ;dont run every frame else set frameNum to 0 set endi to (i - DrakeDragonRaceQuest.itemsRevertPerFrame) endif if eval (ar_HasKey reverterTokenArray actorId == 0) ;initialize let reverterTokenArray[actorId] := ar_Construct StringMap let reverterTokenArray[actorId]["timeout"] := DrakeDragonRaceTokenTrackingQuest.timeOutCount else let reverterTokenArray[actorId]["timeout"] := DrakeDragonRaceTokenTrackingQuest.timeOutCount ;keep i-am-alive ticker ticking endif label if(i >= endi && i >= 0) set tempItem to actorRef.getInventoryObject i if((isArmor tempItem == 1) || (isClothing tempItem == 1)) ForEach item <- itemArray if eval (item["key"] == "original") Continue endif let tagId := item["key"] let index := ar_Find tempItem itemArray[tagId] if eval (index != "") ;needs exchange let tempItem2 := itemArray["original"][index] set equipped to (actorRef.getEquipped tempItem) if(equipped == 1) set slotCode to getEquipmentSlot tempItem set healthBuffer to actorRef.getEquippedCurrentHealth slotCode endif actorRef.removeItemNS tempItem 1 actorRef.addItemNS tempItem2 1 if(equipped == 1) actorRef.equipItemNS tempItem2 actorRef.setEquippedCurrentHealth healthBuffer slotCode endif endif Loop endif set i to (i - 1) goto endif if(i < 0) set init to 0 if(DrakeDragonRaceQuest.debug == 1 && DrakeDragonRaceQuest.debugShowRevToken == 1) actorRef.stopMagicShaderVisuals DrakeDEHostileDetectedXR endif ;remove bodyparts, if present! ForEach item <- defaultItemArray ForEach item2 <- item["value"] let tempItem := item2["value"] set tempNum to actorRef.getItemCount tempItem if(tempItem != DrakeEmptyItem && tempNum > 0) actorRef.removeItemNS tempItem tempNum endif Loop Loop removeMe ;we're done, remove us endifendbegin gameMode if(init != 1) set actorRef to 0 if(DrakeDragonRaceQuest.init != 1) return endif if(DrakeDragonRaceTokenTrackingQuest.init != 1) return endif let itemArray := DrakeDragonRaceQuest.itemArray let defaultItemArray := DrakeDragonRaceQuest.defaultItemArray let actorArray := DrakeDragonRaceTokenTrackingQuest.actorArray let raceTokenArray := DrakeDragonRaceTokenTrackingQuest.raceTokenArray let reverterTokenArray := DrakeDragonRaceTokenTrackingQuest.reverterTokenArray let actorId := "" set frameNum to 0 set init2 to 0 set init to 1 endif if eval (-1 == ar_Size itemArray) ;shouldn't happen, but just in case if(DrakeDragonRaceQuest.debug == 1 && DrakeDragonRaceQuest.debugShowRevToken == 1) actorRef.stopMagicShaderVisuals DrakeDEHostileDetectedXR endif removeMe endif if(actorRef == 0) set actorRef to getContainer return endif if eval (actorId == "") let actorId := ar_Find actorRef actorArray if eval (actorId == "") let actorId := $(ar_Size actorArray) let actorArray[actorId] := actorRef ;add actor to tracking list endif return endif if(init2 != 1) set numItems to actorRef.getNumItems set i to (numItems - 1) set init2 to 1 endif if(frameNum < DrakeDragonRaceQuest.framesToSkip) set frameNum to (frameNum + 1) return ;dont run every frame else set frameNum to 0 set endi to (i - DrakeDragonRaceQuest.itemsRevertPerFrame) endif if eval (ar_HasKey reverterTokenArray actorId == 0) ;initialize let reverterTokenArray[actorId] := ar_Construct StringMap let reverterTokenArray[actorId]["timeout"] := DrakeDragonRaceTokenTrackingQuest.timeOutCount else let reverterTokenArray[actorId]["timeout"] := DrakeDragonRaceTokenTrackingQuest.timeOutCount ;keep i-am-alive ticker ticking endif if(DrakeDragonRaceQuest.debug == 1) if(DrakeDragonRaceQuest.debugShowRevToken == 1) actorRef.playMagicShaderVisuals DrakeDEHostileDetectedXR else actorRef.stopMagicShaderVisuals DrakeDEHostileDetectedXR endif endif label if(i >= endi && i >= 0) set tempItem to actorRef.getInventoryObject i if((isArmor tempItem == 1) || (isClothing tempItem == 1)) ForEach item <- itemArray if eval (item["key"] == "original") Continue endif let tagId := item["key"] let index := ar_Find tempItem itemArray[tagId] if eval (index != "") ;needs exchange let tempItem2 := itemArray["original"][index] set equipped to (actorRef.getEquipped tempItem) if(equipped == 1) set slotCode to getEquipmentSlot tempItem set healthBuffer to actorRef.getEquippedCurrentHealth slotCode endif actorRef.removeItemNS tempItem 1 actorRef.addItemNS tempItem2 1 if(equipped == 1) actorRef.equipItemNS tempItem2 actorRef.setEquippedCurrentHealth healthBuffer slotCode endif endif Loop endif set i to (i - 1) goto endif if(i < 0) set init to 0 if(DrakeDragonRaceQuest.debug == 1 && DrakeDragonRaceQuest.debugShowRevToken == 1) actorRef.stopMagicShaderVisuals DrakeDEHostileDetectedXR endif ;remove bodyparts, if present! ForEach item <- defaultItemArray ForEach item2 <- item["value"] let tempItem := item2["value"] set tempNum to actorRef.getItemCount tempItem if(tempItem != DrakeEmptyItem && tempNum > 0) actorRef.removeItemNS tempItem tempNum endif Loop Loop removeMe ;we're done, remove us endifend
The tracking is done by the tokens and the other scripts, but the regular checks for validity of the provided tokens or stalled scripts are for now only taking place in "gamemode".
I could expand this to menumode as well later, but I thought not letting items get removed or added in menumode without knowing about the current circumstances would be better and safer.
Now, I only hope this new approach will work as intended... and that I didn't make any stupid syntax mistakes anywhere anymore. :rolleyes:
Now when you saved this and started the game with one of your savegames, by all means let the first thing you do before re-starting the main control quest be to type
"set DrakeDragonRaceQuest.initArrays to 1"
into console, so this section of the script shouldn't be entered anymore even when you do
"set DrakeDragonRaceQuest.init to 0"
next to take over all changes to the arrays and such.
If you start a new game though, this of course won't be necessary at all.I can only hope this all works the way I intended it to do. My apologies in advance, if it won't.
I know it's quite a lot, but currently the only way for you to test my latest (hopefully)"improvements". I'm sorry.
Now I hope at least some of you will try out the latest changes and tell me if there's anything still working at all.
(Please keep in mind you can only say a feature is broken when it doesn't work on a "new" game, as in "created after installation".)