Kawa-oneechan / SCICompanion

SCI Companion - an editor for Sierra SCI games, altered.
17 stars 6 forks source link

Fix local procedure disasm & decompilation when address conflicts with an exported instance #17

Closed laurence-myers closed 1 year ago

laurence-myers commented 1 year ago

In QFG4CD, script 29 exports two instances, at address offsets 4 and 24 (0x18). It also has a local procedure, which also happens to be at address offset 24 (0x18). I assume this is because the address offsets have a different starting address.

When disassembling/decompiling the script, any identified procedures are removed from internalProcOffetsTO if the address is also found in _exportsTO. Because local proc localproc_0018 and useCode both have offset address 0x18, the code thinks the proc is exported and removes it, so that later code will output the procedure (which never happens, because the procedure isn't actually exported).

The end result is that the script (rightfully) can't be compiled, because some method tries to call the non-existent localproc_0018.

Error: (doCode.sc) Unknown procedure 'localproc_0018' .  Line: 63, col: 27

I found that we can avoid the issue by calling IsExportAProcedure() when iterating over _exportsTO.

I've tested this by decompiling all the QFG4 scripts, and only script 29 is affected by the change.

This affects both the dissassembler and the decompiler.

Before

Click to expand ``` ;;; Sierra Script 1.0 - (do not remove this comment) (script# 29) (include sci.sh) (use Main) (use InvI) (use Obj) (public doCode 0 useCode 1 ) (instance doCode of Code (properties) (method (init &tmp temp0 temp1 gQGInvCurIcon gQGInvCurIconView gQGInvCurIconLoop gQGInvCurIconCel temp6) (= temp1 0) (= temp0 0) (while (< temp0 57) (if ((gQGInv at: temp0) chestAmout?) (= temp1 1) (= temp0 57) ) (++ temp0) ) (if temp1 (gQGInv showSelf: global2) (if (and (= gQGInvCurIcon (gQGInv curIcon?)) (gQGInvCurIcon isKindOf: InvI) ) (gQGInvCurIcon chestAmout: (- (gQGInvCurIcon chestAmout?) 1) ) (gQGInvCurIcon amount: (+ (gQGInvCurIcon amount?) 1)) (= gQGInvCurIconView (gQGInvCurIcon view?)) (= gQGInvCurIconLoop (gQGInvCurIcon loop?)) (= gQGInvCurIconCel (gQGInvCurIcon cel?)) ((= temp6 (ScriptID 36 2)) cursorView: gQGInvCurIconView ) (temp6 cursorLoop: gQGInvCurIconLoop) (temp6 cursorCel: gQGInvCurIconCel) ((= gQGInvCurIcon (ScriptID 36 1)) view: gQGInvCurIconView loop: gQGInvCurIconLoop cel: gQGInvCurIconCel show: ) (UpdateScreenItem gQGInvCurIcon) ) else (gGloryMessager say: 1 6 1 1 0 29) ) ) ) (instance useCode of Code (properties) (method (init param1 &tmp temp0) (= param1 (localproc_0018 param1)) (= temp0 (gQGInv at: param1)) (cond ((== param1 0) (gGloryMessager say: 1 6 2 1 0 29)) ((== param1 14) (gGloryMessager say: 1 6 6 1 0 29)) ((== param1 25) (gGloryMessager say: 1 6 7 1 0 29)) ((== param1 16) (gGloryMessager say: 1 6 9 1 0 29)) ((proc64999_5 param1 53 56 52 55 54) (gGloryMessager say: 1 6 10 1 0 29)) ( (and (== param1 5) (== ((gQGInv at: 5) amount?) 1)) (gGloryMessager say: 1 6 12 1 0 29)) ((== param1 19) (gGloryMessager say: 1 6 11 1 0 29)) ((== param1 18) (gGloryMessager say: 1 6 13 1 0 29)) ((== param1 44) (gGloryMessager say: 1 6 14 1 0 29)) ((== param1 45) (gGloryMessager say: 1 6 15 1 0 29)) ((== param1 17) (gGloryMessager say: 1 6 16 1 0 29)) (else (temp0 roomGets:) (global69 curInvIcon: 0) (if (> (temp0 amount?) 0) (gGloryMessager say: 1 6 5 1 0 29) else (gGloryMessager say: 1 6 4 1 0 29) ) ) ) ) ) ```

After

Click to expand ``` ;;; Sierra Script 1.0 - (do not remove this comment) (script# 29) (include sci.sh) (use Main) (use Print) (use InvI) (use Obj) (public doCode 0 useCode 1 ) (procedure (localproc_0018 param1) (switch param1 (56 37) (34 17) (13 51) (48 30) (53 34) (69 53) (27 12) (67 52) (47 29) (14 48) (70 54) (58 39) (22 7) (23 8) (55 36) (54 35) (45 27) (31 14) (17 2) (37 5) (43 25) (52 33) (24 9) (39 21) (59 40) (40 22) (33 16) (26 11) (41 23) (57 38) (171 49) (44 26) (18 3) (74 56) (49 31) (77 45) (29 14) (78 46) (63 42) (28 13) (16 1) (32 15) (30 14) (46 28) (15 0) (19 4) (51 32) (21 6) (72 55) (35 18) (157 47) (170 50) (66 43) (36 19) (42 24) (76 44) (25 10) (60 41) (else (proc64921_1 {FROM Verb2Enum: %d NOT FOUND} param1) (SetDebug) ) ) ) (instance doCode of Code (properties) (method (init &tmp temp0 temp1 gQGInvCurIcon gQGInvCurIconView gQGInvCurIconLoop gQGInvCurIconCel temp6) (= temp1 0) (= temp0 0) (while (< temp0 57) (if ((gQGInv at: temp0) chestAmout?) (= temp1 1) (= temp0 57) ) (++ temp0) ) (if temp1 (gQGInv showSelf: global2) (if (and (= gQGInvCurIcon (gQGInv curIcon?)) (gQGInvCurIcon isKindOf: InvI) ) (gQGInvCurIcon chestAmout: (- (gQGInvCurIcon chestAmout?) 1) ) (gQGInvCurIcon amount: (+ (gQGInvCurIcon amount?) 1)) (= gQGInvCurIconView (gQGInvCurIcon view?)) (= gQGInvCurIconLoop (gQGInvCurIcon loop?)) (= gQGInvCurIconCel (gQGInvCurIcon cel?)) ((= temp6 (ScriptID 36 2)) cursorView: gQGInvCurIconView ) (temp6 cursorLoop: gQGInvCurIconLoop) (temp6 cursorCel: gQGInvCurIconCel) ((= gQGInvCurIcon (ScriptID 36 1)) view: gQGInvCurIconView loop: gQGInvCurIconLoop cel: gQGInvCurIconCel show: ) (UpdateScreenItem gQGInvCurIcon) ) else (gGloryMessager say: 1 6 1 1 0 29) ) ) ) (instance useCode of Code (properties) (method (init param1 &tmp temp0) (= param1 (localproc_0018 param1)) (= temp0 (gQGInv at: param1)) (cond ((== param1 0) (gGloryMessager say: 1 6 2 1 0 29)) ((== param1 14) (gGloryMessager say: 1 6 6 1 0 29)) ((== param1 25) (gGloryMessager say: 1 6 7 1 0 29)) ((== param1 16) (gGloryMessager say: 1 6 9 1 0 29)) ((proc64999_5 param1 53 56 52 55 54) (gGloryMessager say: 1 6 10 1 0 29)) ( (and (== param1 5) (== ((gQGInv at: 5) amount?) 1)) (gGloryMessager say: 1 6 12 1 0 29)) ((== param1 19) (gGloryMessager say: 1 6 11 1 0 29)) ((== param1 18) (gGloryMessager say: 1 6 13 1 0 29)) ((== param1 44) (gGloryMessager say: 1 6 14 1 0 29)) ((== param1 45) (gGloryMessager say: 1 6 15 1 0 29)) ((== param1 17) (gGloryMessager say: 1 6 16 1 0 29)) (else (temp0 roomGets:) (global69 curInvIcon: 0) (if (> (temp0 amount?) 0) (gGloryMessager say: 1 6 5 1 0 29) else (gGloryMessager say: 1 6 4 1 0 29) ) ) ) ) ) ```
Kawa-oneechan commented 1 year ago

Nice, nice!

Protip: I've found Clojure to give pretty good results for SCI code blocks.

(instance doCode of Code
    (properties)

    (method (init &tmp temp0 temp1 gQGInvCurIcon gQGInvCurIconView gQGInvCurIconLoop gQGInvCurIconCel temp6)
        (= temp1 0)
        (= temp0 0)
        (while (< temp0 57)
            (if ((gQGInv at: temp0) chestAmout?)
                (= temp1 1)
                (= temp0 57)
            )
            (++ temp0)
        )
    )
)