subtledoctor Posted September 17, 2017 Author Posted September 17, 2017 Okay, I need to re-open this discussion if possible. For a completely different mod, which adds a divine sphere system to the game, I need to wipe the memorized divine spells from joinable NPCs. Apparently if the .cre file has spells memorized but not in their spellbook, it ends up blocking spell slots from being used. But, this same problem arises: what if the NPC is set to turn into an enemy if they don't join the party? Or otherwise act in combat? If I strip out their spells then they will be weakened. I guess I could do it in-game as an effect in their clab table - those only take effect upon joining the party. But, is that possible? It seems like opcode 244 only works on arcane spells. Any ideas? Quote
Jarno Mikkola Posted September 17, 2017 Posted September 17, 2017 (edited) @subtledoctor: Suggestion: INCLUDE ~spell_rev/components/fix_spellbooks.tpa~ RANDOM_SEED 42OUTER_FOR (level = 1; level <= 7; level += 1) BEGINOUTER_SET $spell(~all~ ~%level%~ ~length~) = 0OUTER_SET $spell(~cleric~ ~%level%~ ~length~) = 0OUTER_SET $spell(~druid~ ~%level%~ ~length~) = 0OUTER_SET $spell(~bogus~ ~%level%~ ~length~) = 0ENDCOPY_EXISTING_REGEXP GLOB ~^SPPR[1-7]\(0[1-9]\|[1-4][0-9]\)\.spl$~ ~override~PATCH_IF (SOURCE_SIZE > 0x71) BEGINREAD_SHORT 0x1c spell_typePATCH_IF (spell_type == 2) BEGIN // divine, just to be sureREAD_SHORT 0x20 priest_typeREAD_SHORT 0x1e exclusion_flagsREAD_LONG 0x34 levelTO_UPPER SOURCE_RESPATCH_IF (priest_type == 0x0000) BEGIN // all priestsSPRINT type ~all~ENDELSE PATCH_IF (priest_type == 0x4000) BEGIN // druid/rangerSPRINT type ~druid~ENDELSE PATCH_IF (priest_type == 0x8000) BEGIN // cleric/paladinSPRINT type ~cleric~ENDELSE BEGIN // no priestsSPRINT type ~bogus~ENDPATCH_IF (level > 0 && level <= 7) BEGINSET index = $spell(~%type%~ ~%level%~ ~length~)SPRINT $spell(~%type%~ ~%level%~ ~%index%~) ~%SOURCE_RES%~SET $spell(~%type%~ ~%level%~ ~length~) += 1SET $spell(~%type%~ ~%SOURCE_RES%~) = 1SET $spell(~%SOURCE_RES%~ ~excl~) = (exclusion_flags BAND 0b111111) // store just the alignment bitsSET $spell(~%SOURCE_RES%~ ~level~) = levelENDENDENDBUT_ONLY// replaces currently memorised spells with an alternative and removes those spells from the spellbookDEFINE_PATCH_FUNCTION ~SWAP_BAD_MEMORISED_SPELLS~// INT_VAR// alignment = 0b000000 // bitfield organised as per the .spl alignment restrictions field// spell_type = 0 // 1 = cleric, 2 = druid, 3 = bothBEGINREAD_LONG 0x2b0 memorised_offREAD_LONG 0x2b4 num_memorisedFOR (i = 0; i < num_memorised; i += 1) BEGINREAD_ASCII (memorised_off + 0x0c*i) spellTO_UPPER spellPATCH_IF ((VARIABLE_IS_SET $spell(~bogus~ ~%spell%~)) ||(VARIABLE_IS_SET $spell(~cleric~ ~%spell%~) && spell_type == 2) ||(VARIABLE_IS_SET $spell(~druid~ ~%spell%~) && spell_type == 1)) BEGIN // spell the class shouldn't haveSET level = $spell(~%spell%~ ~level~)SET all_length = $spell(~all~ ~%level%~ ~length~)SET cleric_length = $spell(~cleric~ ~%level%~ ~length~)SET druid_length = $spell(~druid~ ~%level%~ ~length~)PATCH_IF (spell_type == 1) BEGIN // casts cleric spellsSET druid_length = 0 // make sure no druid-only spells can be randomly chosenENDELSE PATCH_IF (spell_type == 2) BEGIN // casts druid spellsSET cleric_length = 0 // make sure no cleric-only spells can be randomly chosenENDSET give_up_countdown = 5 // try 5 times to get a valid spell, then give upSET done = 0WHILE (done != 1 && give_up_countdown > 0) BEGINSET result = RANDOM (1 (all_length + cleric_length + druid_length))PATCH_IF (result == 0) BEGIN // no valid spells to choose from at this levelREMOVE_MEMORIZED_SPELL ~%spell%~ENDELSE BEGINSET result -= 1PATCH_IF (result < all_length) BEGIN // random result falls into spells available for both clerics and druidsSPRINT new_spell $spell(~all~ ~%level%~ ~%result%~)ENDELSE PATCH_IF (result < (all_length + cleric_length)) BEGIN // random result falls into spells available for clericsSET result -= all_lengthSPRINT new_spell $spell(~cleric~ ~%level%~ ~%result%~)ENDELSE PATCH_IF (result < (all_length + cleric_length + druid_length)) BEGIN // random result falls into spells available for druidsSET result -= (all_length + cleric_length)SPRINT new_spell $spell(~druid~ ~%level%~ ~%result%~)ENDSET exclusion = $spell(~%new_spell%~ ~excl~)PATCH_IF ((exclusion BAND alignment) == 0) BEGIN // usable by priests of this alignmentWRITE_ASCIIE (memorised_off + 0x0c*i) ~%new_spell%~ #8SET done = 1ENDELSE BEGINSET give_up_countdown -= 1 // decrement countdown and try once more to find a valid spellENDENDENDENDENDENDDEFINE_PATCH_MACRO ~REMOVE_SPELLS_OF_TYPE~ BEGINFOR (level = 1; level <= 7; level += 1) BEGINSET length = $spell(~%type%~ ~%level%~ ~length~)FOR (i = 0; i < length; i += 1) BEGINSPRINT spell $spell(~%type%~ ~%level%~ ~%i%~)REMOVE_KNOWN_SPELL ~%spell%~ENDENDEND// removes all spells that the class shouldn't have access to anymoreDEFINE_PATCH_FUNCTION ~REMOVE_BAD_KNOWN_SPELLS~// INT_VAR spell_type = 0 // 1 = cleric, 2 = druid, 3 = bothBEGINPATCH_IF (spell_type == 1) BEGIN // remove druid spells from clericsSPRINT type ~druid~LAUNCH_PATCH_MACRO ~REMOVE_SPELLS_OF_TYPE~ENDELSE PATCH_IF (spell_type = 2) BEGIN // remove cleric spells from druidsSPRINT type ~cleric~LAUNCH_PATCH_MACRO ~REMOVE_SPELLS_OF_TYPE~END// remove bogus spells from all classesSPRINT type ~bogus~LAUNCH_PATCH_MACRO ~REMOVE_SPELLS_OF_TYPE~END// used by function belowDEFINE_PATCH_MACRO ~ADD_SPELLS_OF_TYPE~ BEGINSET length = $spell(~%type%~ ~%level%~ ~length~)FOR (i = 0; i < length; i += 1) BEGINSPRINT spell $spell(~%type%~ ~%level%~ ~%i%~)SET level = $spell(~%spell%~ ~level~)REMOVE_KNOWN_SPELL ~%spell%~SET exclusion = $spell(~%spell%~ ~excl~)PATCH_IF ((exclusion BAND alignment) == 0) BEGIN // usable by priests of this alignmentADD_KNOWN_SPELL ~%spell%~ (level - 1) ~priest~ENDENDEND// adds new spells to spellbookDEFINE_PATCH_FUNCTION ~ADD_NEW_KNOWN_SPELLS~// INT_VAR// alignment = 0b000000 // bitfield organised as per the .spl alignment restrictions field// highest_spell_level = 0 // highest level of spells to add to spellbook// spell_type = 0 // 1 = cleric, 2 = druid, 3 = bothBEGINFOR (level = 1; level <= highest_spell_level; level += 1) BEGIN// spells available to allSPRINT type ~all~LAUNCH_PATCH_MACRO ~ADD_SPELLS_OF_TYPE~PATCH_IF (spell_type == 1) BEGIN // clericSPRINT type ~cleric~LAUNCH_PATCH_MACRO ~ADD_SPELLS_OF_TYPE~ENDELSE PATCH_IF (spell_type == 2) BEGIN // druidSPRINT type ~druid~LAUNCH_PATCH_MACRO ~ADD_SPELLS_OF_TYPE~ENDELSE PATCH_IF (spell_type == 3) BEGIN // bothSPRINT type ~cleric~LAUNCH_PATCH_MACRO ~ADD_SPELLS_OF_TYPE~SPRINT type ~druid~LAUNCH_PATCH_MACRO ~ADD_SPELLS_OF_TYPE~ENDENDEND// determines highest level of spells that can be castDEFINE_PATCH_FUNCTION ~DETERMINE_MAX_SPELL_LEVEL~RET highest_spell_levelBEGINREAD_LONG 0x2a8 memorisation_info_offREAD_LONG 0x2ac num_memorisation_infoSET highest_spell_level = 0FOR (i = 0; i < num_memorisation_info; i += 1) BEGINREAD_SHORT (memorisation_info_off + 0x10*i + 0x00) levelREAD_SHORT (memorisation_info_off + 0x10*i + 0x02) num_memorisableREAD_SHORT (memorisation_info_off + 0x10*i + 0x06) spell_typePATCH_IF (spell_type == 0 && num_memorisable > 0) BEGIN // can memorise at least 1 divine spell at this levelSET level += 1 // level is stored as one below actual valuePATCH_IF (level > highest_spell_level) BEGIN // update highest_spell_level if new level is greater than those seen previouslySET highest_spell_level = levelENDENDENDEND// fix spellbooks of divine castersCOPY_EXISTING_REGEXP GLOB ~^.+\.cre$~ ~override~PATCH_IF (SOURCE_SIZE > 0x2d3) BEGINREAD_LONG 0x1cc biographyPATCH_IF (biography > 0 && biography < 2147483647) BEGIN // party-joinable NPC (thanks bigg for easy way to determine this)READ_BYTE 0x273 classPATCH_IF (class == 3 || class == 6 || class == 8 || class == 11 || class == 12 || class == 14 || class == 15 || class == 16 || class == 17 || class == 18) BEGIN // divine castersSET cleric = 0SET druid = 0// remove old spells and replace any that were memorised with semi-equivalent onesPATCH_IF (class == 3 || class == 6 || class == 8 || class == 14 || class == 15 || class == 17) BEGIN // cleric or paladinSET cleric = 1ENDELSE PATCH_IF (class == 11 || class == 12 || class == 16) BEGIN // druid or rangerSET druid = 1ENDELSE PATCH_IF (class == 18) BEGIN // cleric/ranger multi-classSET cleric = 1SET druid = 1READ_LONG 0x10 flagsPATCH_IF ((flags BAND 0b100000000) == 0b100000000) BEGIN // original class was ranger: dual-class c/rREAD_BYTE 0x234 cleric_levelREAD_BYTE 0x235 ranger_level// if waiting to regain ranger abilities, shouldn't have access to druid spellsPATCH_IF (ranger_level <= cleric_level) BEGINSET druid = 0ENDENDENDSET spell_type = 0PATCH_IF (cleric == 1 && druid == 1) BEGINSET spell_type = 3 // spell_type 3 = casts bothENDELSE PATCH_IF (cleric == 1) BEGINSET spell_type = 1 // spell_type 1 = casts clericENDELSE PATCH_IF (druid == 1) BEGINSET spell_type = 2 // spell_type 2 = casts druidEND// match alignment to priest spell exclusion flagsREAD_BYTE 0x27b ids_alignmentSET alignment = 0PATCH_IF (ids_alignment == 0x11) BEGIN // lawful goodSET alignment = 0b010100ENDELSE PATCH_IF (ids_alignment == 0x12) BEGIN // lawful neutralSET alignment = 0b011000ENDELSE PATCH_IF (ids_alignment == 0x13) BEGIN // lawful evilSET alignment = 0b010010ENDELSE PATCH_IF (ids_alignment == 0x21) BEGIN // neutral goodSET alignment = 0b100100ENDELSE PATCH_IF (ids_alignment == 0x22) BEGIN // neutralSET alignment = 0b101000ENDELSE PATCH_IF (ids_alignment == 0x23) BEGIN // neutral evilSET alignment = 0b100010ENDELSE PATCH_IF (ids_alignment == 0x31) BEGIN // chaotic goodSET alignment = 0b000101ENDELSE PATCH_IF (ids_alignment == 0x32) BEGIN // chaotic neutralSET alignment = 0b001001ENDELSE PATCH_IF (ids_alignment == 0x33) BEGIN // chaotic evilSET alignment = 0b000011ENDLAUNCH_PATCH_FUNCTION ~SWAP_BAD_MEMORISED_SPELLS~ ENDLAUNCH_PATCH_FUNCTION ~REMOVE_BAD_KNOWN_SPELLS~ END// determines highest level of spells that can be cast so that we only add spells up to that levelLAUNCH_PATCH_FUNCTION ~DETERMINE_MAX_SPELL_LEVEL~ RET highest_spell_level = highest_spell_level ENDLAUNCH_PATCH_FUNCTION ~ADD_NEW_KNOWN_SPELLS~ ENDENDENDENDBUT_ONLY Edited September 17, 2017 by Jarno Mikkola Quote
Mike1072 Posted September 17, 2017 Posted September 17, 2017 Pretty sure that code doesn't work with sphere systems and I don't think it's what subtledoctor is looking for anyway. Quote
Jarno Mikkola Posted September 17, 2017 Posted September 17, 2017 (edited) @Mike, does it matter if it works WITH the sphere system, if you install that after the removal of spells from NPCs ? Pretty sure that's the whole point of the thing. Aka you won't use the opcode 244 as it doesn't work WITH divine spells, but edit the .cre's, and then have the NPCs regain spells from the kits clab tables. You could even do it so that the vanilla char is unchanged, but the NPC that joins according to the npclevel.2da are the only ones that are changed. ... So you use the above, but quote out this section:// adds new spells to spellbook ... up until the LAUNCH_PATCH_FUNCTION'es. ... if you notice, I put the whole file to the spoilers so it can be referenced from here, and not from the mod, as only a part of it would be used, but I didn't say which parts subtledoctor would need. Edited September 17, 2017 by Jarno Mikkola Quote
Recommended Posts
Join the conversation
You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.