Ardanis Posted January 20, 2009 Share Posted January 20, 2009 DEFINE_PATCH_MACRO pro_spell BEGIN READ_LONG 0x64 ab_off READ_SHORT 0x68 ab_num READ_LONG 0x6a ef_off FOR (i=0;i<ab_num;i+=1) BEGIN READ_SHORT (ab_off+i*0x28+0x1e) ef_num READ_SHORT (ab_off+i*0x28+0x20) ef_ind WRITE_SHORT (ab_off+i*0x28+0x1e) ef_num + 1 WRITE_SHORT (ab_off+i*0x28+0x20) ef_off + i SET off=(ef_off+(ef_ind+i)*0x30) READ_LONG (off+0xe) time // i know, might occasionally read the effect with zero duration, but that's another matter READ_BYTE (off+0x3) power INSERT_BYTES off 0x30 WRITE_SHORT off 206 // opcode WRITE_BYTE (off+0x2) 1 // target WRITE_BYTE (off+0x3) power WRITE_LONG (off+0xe) time WRITE_EVALUATED_ASCII (off+0x14) ~%spell%~ END END BEGIN ~globe~ COPY_EXISTING ~spwi406.spl~ ~override~ // yes, AI won't like me for that, but i disagree SPRINT spell ~spwi326~ LAUNCH_PATCH_MACRO pro_spell Works fine. However when I try to patch it with the 2nd resource SPRINT spell ~another.spl~ LAUNCH_PATCH_MACRO pro_spell I get the [./override/spwi406.spl] loaded, 16130 bytesERROR: illegal 4-byte read from offset 33040 of 16130-byte file spwi406.spl ERROR: [spwi406.spl] -> [override] Patching Failed (COPY) (Failure("spwi406.spl: read out of bounds")) The problem seems to be the SET off=(ef_off+(ef_ind+i)*0x30) line. Could someone point out the right direction? Did I forget to WRITE something else when shifting effects? I feel I wrote them all but who knows. Link to comment
Taimon Posted January 20, 2009 Share Posted January 20, 2009 Check this line again: WRITE_SHORT (ab_off+i*0x28+0x20) ef_off + i Link to comment
Ardanis Posted January 21, 2009 Author Share Posted January 21, 2009 DEFINE_PATCH_MACRO pro_spell BEGIN READ_LONG 0x64 ab_off READ_SHORT 0x68 ab_num READ_LONG 0x6a ef_off FOR (i=0;i<ab_num;i+=1) BEGIN READ_SHORT (ab_off+i*0x28+0x1e) ef_num READ_SHORT (ab_off+i*0x28+0x20) ef_ind FOR (k=0;k<ef_num;k+=1) BEGIN // we can't know exact values to write in our new effect, so we have // to find a good example within an ability and clone it's properties SET check=0 READ_SHORT (ef_off+(k+ef_ind)*0x30) guide_op PATCH_IF ((check = 0) AND (guide_op = 204)) BEGIN // 'immunity to spell school' is a good example SET check=1 SET gu_eff=(ef_off+(k+ef_ind)*0x30) // effect-guide? hmm... READ_BYTE (gu_eff+0x2) target READ_BYTE (gu_eff+0x3) power READ_BYTE (gu_eff+0xd) dispel READ_LONG (gu_eff+0xe) duration // the only part required actually, but let's it be more universal READ_BYTE (gu_eff+0x12) prob1 // which one of... READ_BYTE (gu_eff+0x13) prob2 // ...these is 100%? END // other stuff - saving throws, dice, etc. - aren't needed for our particular case (they're zero) END SET off=(ef_off+(ef_ind+i)*0x30) INSERT_BYTES off 0x30 WRITE_SHORT off 206 // 'protection from spell' WRITE_BYTE (off+0x2) target WRITE_BYTE (off+0x3) power WRITE_BYTE (off+0xd) dispel WRITE_LONG (off+0xe) duration WRITE_BYTE (off+0x12) prob1 WRITE_BYTE (off+0x13) prob2 WRITE_EVALUATED_ASCII (off+0x14) ~%spell%~ WRITE_SHORT (ab_off+i*0x28+0x1e) ef_num + 1 // shifting WRITE_SHORT (ab_off+i*0x28+0x20) ef_ind + i // shifting END END Now it's very confusing. I've modified the macro a bit, used it onto globes to 100% success then decided to fix Spell Immuties as well. Each of them has 12 ability headers and while the first 6 are patched correctly, the latter six's values lag behind by one - 7th added effect uses values read from 6th 'example', 8th - from 7th, etc., be it duration or something else (I intentionally changed 'target' of the 6th and voila - it popped up not only in new 6th but in 7th as well). More than that, it happened to Evoc, Necr, Alt and Conj immunities, while Abj was absolutely fine. I'm really out of guesses. Link to comment
Taimon Posted January 21, 2009 Share Posted January 21, 2009 You may want to think about your logics again. Why is there a check variable? It's set inside the inner for loop and checked immediately afterwards. (Maybe you wanted to set it outside of the for loop?) And in this line READ_SHORT (ef_off+(k+ef_ind)*0x30) guide_op you are not taking into account, that you might have added an effect on the previous ability, so it should read READ_SHORT (ef_off+(k+ef_ind+i)*0x30) guide_op instead. Same for the SET gu_eff line. By the way, your code is based on the assertion that every ability has at least one effect with opcode #204. Link to comment
Ardanis Posted January 21, 2009 Author Share Posted January 21, 2009 you are not taking into account, that you might have added an effect on the previous abilityAre you sure? I did indeed make a similar mistake when wrote the very first variant - forgot to add '+i' into SET off=(ef_off+(ef_ind+i)*0x30). But I believe it's already attended by FOR (i=0;i<ab_num;i+=1) BEGIN READ_SHORT (ab_off+i*0x28+0x1e) ef_num READ_SHORT (ab_off+i*0x28+0x20) ef_ind ... WRITE_SHORT (ab_off+i*0x28+0x1e) ef_num + 1 // shifting WRITE_SHORT (ab_off+i*0x28+0x20) ef_ind + i // shifting END Why is there a check variable? It's set inside the inner for loop and checked immediately afterwards. (Maybe you wanted to set it outside of the for loop?) By the way, your code is based on the assertion that every ability has at least one effect with opcode #204.Indeed, thanks for pointing out. Sadly it doesn't shed more light, still only the first six affected abilities are patched the way they should be (tried to remove 204 from one, now it's skipped, 6 others are updated, starting at 8th they begin to lag). Weird. Link to comment
Taimon Posted January 21, 2009 Share Posted January 21, 2009 you are not taking into account, that you might have added an effect on the previous abilityAre you sure? I did indeed make a similar mistake when wrote the very first variant - forgot to add '+i' into SET off=(ef_off+(ef_ind+i)*0x30). But I believe it's already attended by FOR (i=0;i<ab_num;i+=1) BEGIN READ_SHORT (ab_off+i*0x28+0x1e) ef_num READ_SHORT (ab_off+i*0x28+0x20) ef_ind ... WRITE_SHORT (ab_off+i*0x28+0x1e) ef_num + 1 // shifting WRITE_SHORT (ab_off+i*0x28+0x20) ef_ind + i // shifting END Partly. You are only updating the ef_ind of the current ability. But after you added at least one effect, the ef_ind the following abilities are refering to is not correct anymore. That's why I suggested adding that "+i" to the two lines. (Where you read guide_op and the SET gu_eff line.) Again, that's all based on the assumption, that you add exactly one effect per ability, and I'm not sure if this holds true in your case. By the way, there is an ADD_SPELL_EFFECT macro shipped with WeiDU. Link to comment
Ardanis Posted January 21, 2009 Author Share Posted January 21, 2009 I know of ADD_SPELL_EFFECT but I thought doesn't allow to keep newly added effects in pace with already present ones. Unless there're more of syntax I'm unaware of. Well, it indeed was missing '+i', the very same oversight I did when outlining macro for the first time. In this particular case the assumption 'one eff for each abil' holds true, lest the spell is bugged on its own, meaning it couldn't be harmed anymore than it already would be, although more versatility certainly wouldn't hurt. Thanks for help. DEFINE_PATCH_MACRO pro_spell BEGIN READ_LONG 0x64 ab_off READ_SHORT 0x68 ab_num READ_LONG 0x6a ef_off SET new=0 FOR (i=0;i<ab_num;i+=1) BEGIN READ_SHORT (ab_off+i*0x28+0x1e) ef_num READ_SHORT (ab_off+i*0x28+0x20) ef_ind SET check=0 FOR (k=0;k<ef_num;k+=1) BEGIN READ_SHORT (ef_off+(k+ef_ind+new)*0x30) PATCH_IF ((check = 0) AND (guide_op = checker)) BEGIN SET check=1 SET gu_eff=(ef_off+(k+ef_ind+new)*0x30) READ_BYTE (gu_eff+0x2) READ_BYTE (gu_eff+0x3) READ_BYTE (gu_eff+0xd) READ_LONG (gu_eff+0xe) duration READ_BYTE (gu_eff+0x12) prob1 READ_BYTE (gu_eff+0x13) prob2 END END PATCH_IF (check=1) BEGIN SET off=(ef_off+(ef_ind+new)*0x30) INSERT_BYTES off 0x30 WRITE_SHORT off 206 // 'protection from spell' WRITE_BYTE (off+0x2) target WRITE_BYTE (off+0x3) power WRITE_BYTE (off+0xd) dispel WRITE_LONG (off+0xe) duration WRITE_BYTE (off+0x12) prob1 WRITE_BYTE (off+0x13) prob2 WRITE_EVALUATED_ASCII (off+0x14) ~%resource%~ WRITE_SHORT (ab_off+i*0x28+0x1e) ef_num + 1 // shifting WRITE_SHORT (ab_off+i*0x28+0x20) ef_ind + new // shifting SET new+=1 END END END In case someone would want to use it, set 'checker' and 'resource' to whatever you need and that's all. SET checker=xxx // desired opcode's number SPRINT resource ~name~ // spell's filename Link to comment
Recommended Posts
Archived
This topic is now archived and is closed to further replies.