Jump to content

Luke

Modders
  • Posts

    879
  • Joined

Posts posted by Luke

  1. 14 minutes ago, polytope said:

    ... unless those trigger a subspell by #146

    Yeah, probably ( @subtledoctor do your ambient helper effects start with op146...? Asking because in my tests op326 does not trigger SpellCastOnMe()... Easy repro case: edit the Magic Missile scroll so that it makes use of op326 in place of op146 and use it against a Hakeashar. You will notice the creature does not get healed...)

  2. 1 minute ago, DavidW said:

    I don't see any evidence that the effect is only supposed to work on wizard and priest spells, and not on all magic effects. The Sun Soul and Blackguard powers here are clearly magical.

    There are a (very) few effects that get cast through .spl that clearly aren't magical, but it seems to me way overkill to patch every spell in the game just to block those edge cases.

    Yeah, guess you are right... My concern was about mod-added content, such as a single-target fighter kit ability, which should not probably cure such creatures... Guess such kit abilities should probably use op248/249 (see Called Shot) in order to avoid curing these creatures...

  3. So, I'm not sure if this is fixpack material or not, but just in case...

    As modders know, there are several undroppable items in these games that are supposed to act as "creature skins", i.e.: they provide all sort of immunities (passive traits) a creature should have (well, to be precise, sometimes such immunities are directly attached to the CRE file, but ok...).

    My question is: are they correct? That is to say: do they provide the intended immunities or too much / too few immunities...?

    As confirmed by other forumites who know the lore (much) better than me, AD&D 2nd edition is not very informative about that... As a result, such things are up to individual Dungeon Master interpretations and campaign settings... which in turn means that such undroppable items are probably correct... which in turn means there is not a template for each creature type to stick with...

    However, there is certainly something odd... I mean, letting aside special cases such as boss creatures and plot-armored creatures (that are normally immune to everything), let us start with the following:

    • Elementals, Salamanders and Genies are vulnerable to everything (Backstab, Entangle, Web, Grease, Petrification, Panic, Deafness, Berserk, Silence, Feeblemind, Stun, Charm, Confusion, Sleep, Blindness, Hold, Paralysis, Polymorph, Poison, Disease ...) Intended...? Probably not...?
      • In IWD:EE, they are at least immune to cure/cause wounds spells and Disease spells, which makes sense me thinks... But I suspect they should get something more...? For instance at least Salamanders should get Sleep, Charm and Hold immunity...
    • Dragons ("dragring.itm") are basically immune to everything except Polymorph and Feeblemind. Intended...? Guess so, since they are boss / very high level creatures, though I'm not 100% sure...
      • Let us say that the immunity to Slow seems out of place, unless that is part of them being boss creatures...?
      • The Monstrous Manual (at least the one I found on the net) only speaks about immunity to normal missiles... I know the games are not meant to be 100% faithful to the source material, but just to point it out
    • Plants are generally are vulnerable to everything (Backstab, Entangle, Web, Grease, Petrification, Panic, Deafness, Berserk, Silence, Feeblemind, Stun, Charm, Confusion, Sleep, Blindness, Hold, Paralysis, Polymorph, Poison, Disease ...) Intended...?
      • Probably not intended since when SoD was released, they added a new undroppable skin ("bdplant.itm") which provides immunity to Backstab, Stun, Petrification, Sleep, Hold, Paralysis, Polymorph, Poison, Disease ...
    • Demonic creatures vary between games. Intended...? Which is the correct variant...?
      • We have "ringdemn.itm" that provides the following immunities:
        • Poison, Charm, Feeblemindedness, Confusion, Polymorph, normal weapons, Panic (BG2:EE and IWD:EE only)
      • We have "bddtrai.itm" (SoD)  that provides the following immunities:
        • Panic, Stun, Poison, Charm, Sleep, Confusion, normal weapons
    • Wyverns ("ring97.itm") are immune to (Entangle, Web, Grease, Hold, Paralysis, Slow)
      • I think we can all agree that immunity to Paralysis is a relic from the past when op157 (Web) was a cosmetic-only opcode, thus it should be removed...
      • As far as Hold and Slow are concerned, they seem to be out of place...?
  4. @CamDawg

    Now that I think of it, there is probably another issue with these creatures...

    "The hakeashar is completely immune to magic, and magic will actually heal it."

    As of now, this block

    Spoiler
    IF
    	SpellCastOnMe([ANYONE],0)
    THEN
    	RESPONSE #100
    		ApplySpell(Myself,CLERIC_CURE_LIGHT_WOUNDS)  // SPPR103.SPL (Cure Light Wounds)
    END

     

    returns true for all spells, including innate and spell-like abilities such as 'BLACKGUARD_ABSORB_HEALTH' and 'SUN_SOUL_SUN_SOULRAY'... Intended...?

    Fixing this would require a bit of spell restructuring (i.e. something like patching all SPPR and SPWI files by adding an op326 effect as first effect casting 'CLERIC_CURE_LIGHT_WOUNDS'...?)

    Is this out of scope...?

  5. 6 minutes ago, argent77 said:

    The script that was responsible for the falling-down mechanism in oIWD is still in place but doesn't contain any code. Instead it's realized by REG1HP2.ITM

    The only odd thing is that not all trolls are equipped with REG1HP2... Some of them still rely upon scripts (see f.i. CDTROLL1.CRE and CDTROLL1.BCS...) Intended...? They probably forgot to update them... Also because such scripts are partially broken (cdtroll2.cre does not exist as a game resource...)

  6. On 10/11/2023 at 5:55 PM, argent77 said:

    That's handled slightly differently where the trigger delay isn't as noticeable, but the patch should work basically the same.

    Yes, the trigger condition is slightly different (i.e. HPPercentLT 25)... However, it is still checked once per round (once per 2 rounds if slowed), so you might want to patch it as well...

    On 10/11/2023 at 3:11 PM, argent77 said:

    which had been initially improved in EE games by moving it from script to spell effect

    Unless I'm missing something, in IWD:EE the falling-down mechanism still relies upon scripts...?

  7. 14 minutes ago, argent77 said:

    Slow doesn't appear to delay the falling-down trigger. Maybe it's delayed from one tick to two ticks, but that isn't noticeable by the player.

    Fine. Guess another possible solution would be that of replacing op232 with op272 (p1=1, p2=3, i.e. once per second / once per 2 seconds if slowed)... In any case, I think this tweak is suitable for inclusion in the fixpack...

    Before I forget: in SoD there are certain wolves that also have this falling-down mechanics. As a result, you might want to patch them as well...

  8. 1 hour ago, argent77 said:

    My change includes a second opcode 232 (Cast spell on condition) to the trolls' TROLLREG items which triggers an intermediate spell on "TookDamage()/instant" that executes the original falling-down spell (TROLLREG.SPL, etc.) when the current hit points fall below a certain threshold.

    Just out of curiosity: does "TookDamage()" still trigger immediately if the troll in question is slowed...?

    1 hour ago, argent77 said:

    ... without being invulnerable for another full round (in the worst case).

    As I said before, the worst case scenario is when the troll in question is slowed (i.e. two rounds)

  9. Here is a more sophisticated version of spell_to_innate. It makes sure all nested subspells (if any) are of type "innate" and can make the specified innate ability uninterruptible (while casting).

    Spoiler
    // Example usage
    
    WITH_SCOPE BEGIN
    	LAF "GET_UNIQUE_FILE_NAME" STR_VAR "extension" = "spl" RET "filename" END
    	//
    	LAF "MAKE_SPELL-LIKE_ABILITY"
    	STR_VAR
    		"source_spell" = "sppr450" // spell to clone
    		"dest_spell" = EVAL "%filename%" // resource name of the cloned spell
    	END
    END
      
    // Function definition
      
    DEFINE_ACTION_FUNCTION "MAKE_SPELL-LIKE_ABILITY"
    INT_VAR
    	"level" = 0 // default: keep levels (in case "%source_spell%" scales with level), otherwise specify a level
    	"location" = 2 // default: "Cast spell" button (F7)
    	"uninterruptible" = 0 // boolean
    STR_VAR
    	"source_spell" = "" // spell to clone
    	"dest_spell" = "" // resource name of the cloned spell
    RET_ARRAY
    	"make_spell-like_ability_reserved_hash" // this is only needed when the function calls itself (i.e., you can safely ignore it)
    BEGIN
    	// Initialize
    	OUTER_SET "last_valid_level" = "-1"
    	OUTER_SET "last_valid_target" = 1
    	//
    	COPY_EXISTING - "%source_spell%.spl" "override"
    		PATCH_IF "%uninterruptible%" BEGIN
    			READ_SLONG NAME1 "name"
    			READ_LONG 0x18 "flags"
    		END
    		GET_OFFSET_ARRAY "abilityArray" SPL_V10_HEADERS
    		PHP_EACH "abilityArray" AS "abilityIndex" => "abilityOffset" BEGIN
    			PATCH_IF "%uninterruptible%" BEGIN
    				SET "last_valid_target" = BYTE_AT ("%abilityOffset%" + 0xC)
    			END
    			// Return the last header whose "min_level" @ 0x10 is smaller or equal than "%level%"
    			PATCH_IF (SHORT_AT ("%abilityOffset%" + 0x10) <= "%level%") BEGIN
    				SET "last_valid_level" = SHORT_AT ("%abilityOffset%" + 0x10)
    			END
    		END
    	BUT_ONLY_IF_IT_CHANGES
    	// Clone the original spell
    	ACTION_IF "%uninterruptible%" BEGIN
    		LAF "GET_UNIQUE_FILE_NAME" STR_VAR "extension" = "spl" RET "shell_spell" = "filename" END
    	END ELSE BEGIN
    		OUTER_TEXT_SPRINT "shell_spell" "%dest_spell%"
    	END
    	COPY_EXISTING "%source_spell%.spl" "override/%shell_spell%.spl"
    		// Header
    		PATCH_IF "%uninterruptible%" BEGIN
    			WRITE_LONG NAME1 "-1"
    			WRITE_LONG 0x18 0 // flags
    		END
    		WRITE_SHORT 0x1C 4 // innate
    		WRITE_LONG 0x1E 0 // exclusion flags
    		// Extended header(s)
    		PATCH_WITH_SCOPE BEGIN
    			GET_OFFSET_ARRAY "abilityArray" SPL_V10_HEADERS
    			PHP_EACH "abilityArray" AS "abilityIndex" => "abilityOffset" BEGIN
    				PATCH_IF ("%last_valid_level%" != "-1") AND (SHORT_AT ("%abilityOffset%" + 0x10) != "%last_valid_level%") BEGIN
    					WRITE_BYTE "%abilityOffset%" 0xFF // mark it for later deletion
    				END ELSE BEGIN
    					WRITE_SHORT ("%abilityOffset%" + 0x2) "%location%"
    					WRITE_SHORT ("%abilityOffset%" + 0x10) ("%last_valid_level%" == "-1" ? THIS : 1)
    				END
    			END
    			// Actual deletion
    			LPF "DELETE_SPELL_HEADER" INT_VAR "header_type" = 0xFF END
    		END
    		// Feature block(s) -- make sure all op206/318/321/324/333 protect from / remove / cast the new resref
    		LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 206 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END
    		LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 318 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END
    		LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 321 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END
    		LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 324 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END
    		LPF ~ALTER_EFFECT~ INT_VAR ~silent~ = 1 ~match_opcode~ = 333 STR_VAR ~match_resource~ = EVAL ~%SOURCE_RES%~ ~resource~ = EVAL ~%DEST_RES%~ END
    		// Make sure any op146/148/326/333 cast an "innate" spell (if any)
    		GET_OFFSET_ARRAY "abilityArray" SPL_V10_HEADERS
    		PHP_EACH "abilityArray" AS "abilityIndex" => "abilityOffset" BEGIN
    			GET_OFFSET_ARRAY2 "effectArray" "%abilityOffset%" SPL_V10_HEAD_EFFECTS
    			PHP_EACH "effectArray" AS "effectIndex" => "effectOffset" BEGIN
    				READ_ASCII ("%effectOffset%" + 0x14) "res"
    				PATCH_MATCH SHORT_AT "%effectOffset%" WITH
    					146 148 326 333 WHEN ("%res%" STRING_COMPARE_CASE "%DEST_RES%") BEGIN
    						PATCH_IF !(VARIABLE_IS_SET $"make_spell-like_ability_reserved_hash"("%res%")) BEGIN
    							LPF "GET_UNIQUE_FILE_NAME" STR_VAR "extension" = "spl" RET "filename" END
    							WRITE_ASCIIE ("%effectOffset%" + 0x14) "%filename%" #8
    							TEXT_SPRINT $"make_spell-like_ability_reserved_hash"("%res%") "%filename%"
    							INNER_ACTION BEGIN
    								LAF "MAKE_SPELL-LIKE_ABILITY" INT_VAR "level" "location" STR_VAR "source_spell" = EVAL "%res%" "dest_spell" = EVAL "%filename%" RET_ARRAY "make_spell-like_ability_reserved_hash" END
    							END
    						END ELSE BEGIN
    							WRITE_ASCIIE ("%effectOffset%" + 0x14) $"make_spell-like_ability_reserved_hash"("%res%") #8
    						END
    					END
    					DEFAULT
    				END
    			END
    		END
    	BUT_ONLY_IF_IT_CHANGES
    	// Make a dummy SPL file casting the real SPL file if "%uninterruptible%"
    	ACTION_IF "%uninterruptible%" BEGIN
    		ACTION_MATCH "%last_valid_target%" WITH
    			1 BEGIN // living actor
    				OUTER_SET "opcode" = 146 // cast spell
    				OUTER_SET "target" = 2 // projectile target
    			END
    			4 BEGIN // any point within range
    				OUTER_SET "opcode" = 148 // cast spell at point
    				OUTER_SET "target" = 1 // self
    			END
    			5 7 BEGIN // caster
    				OUTER_SET "opcode" = 146 // cast spell
    				OUTER_SET "target" = 1 // self
    			END
    			DEFAULT
    				FAIL "MAKE_SPELL-LIKE_ABILITY: Should not happen"
    		END
    		COPY_EXISTING "%shell_spell%.spl" "override/%dest_spell%.spl"
    			// Header
    			WRITE_LONG NAME1 "%name%"
    			WRITE_LONG 0x18 "%flags%"
    			WRITE_SHORT 0x22 0 // casting animation
    			WRITE_ASCII 0x10 "" #8 // casting sound
    			// Extended header(s)
    			PATCH_WITH_SCOPE BEGIN
    				GET_OFFSET_ARRAY "abilityArray" SPL_V10_HEADERS
    				PHP_EACH "abilityArray" AS "abilityIndex" => "abilityOffset" BEGIN
    					PATCH_IF (SHORT_AT ("%abilityOffset%" + 0x10) != 1) BEGIN
    						WRITE_BYTE "%abilityOffset%" 0xFF // mark it for later deletion
    					END ELSE BEGIN
      						WRITE_SHORT ("%abilityOffset%" + 0x12) 0 // casting speed
      						WRITE_SHORT ("%abilityOffset%" + 0x26) IDS_OF_SYMBOL ("MISSILE" "None") // projectile
      					END
    				END
    				// Actual deletion
    				LPF "DELETE_SPELL_HEADER" INT_VAR "header_type" = 0xFF END
    			END
    			// Casting feature effects
    			LPF ~ADD_SPELL_CFEFFECT~ INT_VAR "opcode" = 101 "target" = 1 "parameter2" = 12 END // Immunity to effect => Effect: Damage (`casting_speed=0` might not be enough, hence a 0-duration immunity to damage...)
    			// Feature block(s)
    			LPF ~DELETE_SPELL_EFFECT~ INT_VAR ~opcode_to_delete~ = ~-1~ END // delete everything
    			LPF ~ADD_SPELL_EFFECT~ INT_VAR "opcode" "target" "timing" = 1 STR_VAR "resource" = EVAL "%SOURCE_RES%" END // Cast spell / Cast spell at point
    		BUT_ONLY_IF_IT_CHANGES
    	END
    END

     

     

  10. On 9/20/2023 at 12:25 PM, Galactygon said:

    It would be an extra nifty feature if the opcode could discriminate based on where the explosion point occoured relative to the creature being protected so it can block effects if the explosion occoured beyond a certain distance (unused param2 can be used). i.e. if you cast a fireball centered onto yourself but param2 is nonzero then it affects you.

    What do you mean exactly here...?

  11. 14 minutes ago, CamDawg said:

    Yes, still no on C_E_Rs. We're first in stack on a known platform, the patch list is known. I generally write a REGEXP to look for issues, then pare it down to a file list for a normal C_E.

    Fine, I'll rewrite my code then...

  12. On 8/4/2023 at 12:14 AM, Galactygon said:

    For the sake of consistency, it might be a good idea to have Hold Undead use 175 and change Hold Monster to affect everything but Undead as well as remove protection from 175 from undead immunities (i.e. RING95.itm). This way, they are affected by Free Action as well.

    Follow-up question: as you surely know (and as stated earlier in this thread), if something provides immunity to op109, then it also provides immunity to op175 (and viceversa).

    If that is indeed incorrect, then why does op162 (Cure Paralysis) remove both op109 and op175? That is to say: should we have two separate removal opcodes, one specifically for op109 and another one specifically for op175...? Now that I think of it, it would be better to edit the special field of op162 so that it can remove op109 if, say, BIT0 is set, and op175 if BIT1 is set...

  13. On 6/27/2023 at 9:10 PM, Galactygon said:

    Though it might still be a good idea to use splstates for the sake of scripting.

    As far as scripting is concerned, EEex has a new script trigger that can return true if the specified object is immune to a certain opcode (namely "EEex_IsImmuneToOpcode()").

    Such a trigger should at least partially mitigate the need of using splstates... However, splstates might still be useful to provide feedback for the player (the so called "Uneffected by effects from" string...)

  14. 4 hours ago, Luke said:

    Also, Hold Monsters and the like (which use op175) do seem to belong to the so called mind-affecting sphere, so I think it is correct for Undead (among others) to be immune to op175...

    Actually, this might be incorrect...

    I asked ChatGPT (lol) about that, and it depicted hold monsters as "a spell that affects a creature's physical movements by magically paralyzing them. It doesn't directly target the mind, but rather the body."

    • OK, nevermind, ChatGPT also states that the "Hold Monsters" spell is considered a mind-affecting spell. Mind-affecting spells are spells that target a creature's mind, influencing their thoughts, emotions, or mental faculties. "Hold Monsters" falls under this category because it affects the physical actions and movements of creatures by magically paralyzing them.

    The fact that it is an Enchantment spell is kinda misleading...

  15. 11 hours ago, Galactygon said:

    Web effects need to be changed to only rely on the Web opcode.

    Yes, I think we can all agree on that.

    11 hours ago, Galactygon said:

    For the sake of consistency, it might be a good idea to have Hold Undead use 175 and change Hold Monster to affect everything but Undead as well as remove protection from 175 from undead immunities (i.e. RING95.itm)

    Yes, I (partially) agree.

    Let's say that if you decide to implement this feature, then there's no need to strip the immunity to 175 from RING95.itm and the like...

    Also, Hold Monsters and the like (which use op175) do seem to belong to the so called mind-affecting sphere, so I think it is correct for Undead (among others) to be immune to op175...

  16. @Galactygon

    As far as this topic is concerned, is it correct that

    1) opcode #109 should only be used by creatures/items that can naturally cause paralysis (f.i. liches, ghasts, carrion crawlers, etc...)?

    2) opcode #175 should only be used by spells/items that are supposed to impose a mental control (f.i. all spells/items flagged as primary_type=4|ENCHANTER)?

    3) opcode #185 should only be used for special cases such as Otiluke, Bigby, Hold Undead, ... ?

  17. 4 hours ago, argent77 said:

    It looks like you stumbled upon another bug. The item from the first call of CreateItemGlobal() is created in the magical weapon slot, and only subsequent calls to CreateItemGlobal() will create the item in accessible inventory slots (starting in the last inventory slot).

    Indeed.

    Well, It can be worked around with GiveItemCreate() and multiple response blocks... The only issue is that it is a bit inelegant...

    Will add it to my to-fix list...

×
×
  • Create New...