tetracorp / k240

Exploring K240, a project to disassemble the 1994 Commodore Amiga game, K240
https://tetracorp.github.io/k240/
5 stars 1 forks source link

Attempts to make the Powerplant less of a worst building #12

Open drDragonSmoke opened 1 year ago

drDragonSmoke commented 1 year ago

In an attempt to improve the the function of the Powerplant, I made the following changes to the code:

LAB_0946: MOVEQ #0,D3 ;14f0a: 7600 TST.W 46(A4) ; inserted check for powerplants BEQ.S LAB_0948 ; inserted branch if no powerplants TST.W 184(A5) ; changed this to check for asteros in stores (instead of asteros in asteroid) BEQ.S LAB_0948 ;14f10: 6716 MOVE.B LAB_0D20,D5 ;14f12: 1a390002e45b ANDI.B #$03,D5 ;14f18: 02050003 BNE.S LAB_0947 ;14f1c: 6604 SUBQ.W #1,184(A5) ; changed this to subtract asteros from store (instead of asteros in asteroid)

Initially, this seems to work well. I tested it using one mine to get some asteros first, then built a powerplant. The number of asteros in store went up and down as intended. But when I built some more mines, the game froze. I tested it in reverse by building a powerplant first, and then the game crashed upon building several mines.

I am guessing this has something to do with creating a conflict. When I subtract directly from the asteros store, perhaps this does not match some later calculation when several mines add to the number? But then again, I don't really know what I'm doing :) Maybe I should be moving the number of asteros in stores to a D register before subtracting? But then I'll probably just mess up some other calculation. I would appreciate any ideas/comments.

drDragonSmoke commented 1 year ago

Actually, after going back to my previous version, where I had added only the check and branch for powerplants (not changed the subtraction in any way) I discovered that the freeze error happens then too. When the emperor sends the first reinforcements, the name of my asteroid appears corrupted, and upon closing that message screen, nothing else works (mouse still works, and animations on screen, but nothing is clickable).

I suppose adding code is never as easy as one hopes. By putting in a fews line here, I must have messed up some other pointer or reference, so it reads the name of the asteroid from the wrong memory spot and the errors cascade from there. Something like that?

drDragonSmoke commented 1 year ago

Alright, so I think I figured out how to do it without adding any bytes.

LAB_0946: MOVEQ #0,D3 ;14f0a: 7600 TST.W 184(A5) ;;14f0c: changed to check for asteros in stores BEQ.S LAB_0948 ;14f10: 6716 MOVE.W (46,A4),D3 ; moved this up from ;14f22: MOVE.B LAB_0D20,D5 ;14f12: 1a390002e45b ANDI.B #$03,D5 ;14f18: 02050003 BNE.S LAB_0947 ;14f1c: 6604 SUB.W D3,184(A5) ;14f1e: changed to subtract # of powerplants from stored asteros LAB_0947: ASL.W #5,D3 ;14f26: eb43

This seems to work well so far, but have not played an extended game to test fully yet. I believe this should restore the Powerplant to its intended glory. Results: Asteros in asteroid is no longer drained for no reason. Powerplant can now use Asteros in stores to produce power. Each Powerplant drains 1 Asteros (instead of just 1 regardless of # of powerplants)

The hex-edit fix for this would be to search up: 4A 6D 00 3E 67 16 1A 39 00 01 3A 7F 02 05 00 03 66 04 53 6D 00 3E 36 2C 00 2E and replace with: 4A 6D 00 B8 67 16 36 2C 00 2E 1A 39 00 01 3A 7F 02 05 00 03 66 04 97 6D 00 B8

tetracorp commented 1 year ago

I've updated playk240.68k.asm and playk240.cnf so that it should build correctly now. Somehow the .cnf had gotten some incorrect duplicate label names.

I haven't had much luck adding lines of code, since as you noticed it seems to change offsets later in the code. Perhaps adding code in even increments of 4 bytes would work better, although I haven't tested it.

Assembling the disassembled code usually creates a working executable of the same filesize as the original and with everything at its usual offset. Some of the bytes are changed but these seem to be just uninitialized memory so it doesn't affect anything.

A drawback to Powerplant drawing ore from Asteros in stores is that if you run out of Asteros, you don't have enough energy to power the Mines. Mines are 9th on power failure order so they're one of the first to fail.

drDragonSmoke commented 1 year ago

Thank you for the reply. It occurred to me that my fix might cause issues if the amount of asteros pulled goes beyond zero. I tested it with having 3 asteros and building 2 powerplants. After 4 ticks (days) the asteros went down to 1, and after 4 more ticks the asteros amount was 65535. I'm thinking we need to make the TST into a CMP and then a BGE branch. The problem with the CMP is that is changes the amount of powerplants in D3 by subtracting the number of asteros, so the power generation calculation becomes wrong (and probably other calculations as well). Any ideas?

A drawback to Powerplant drawing ore from Asteros in stores is that if you run out of Asteros, you don't have enough energy to power the Mines.

I don't see the problem with that. If you run out of asteros, the powerplant shuts down. This is intended. To restore power you either have to ship in more asteros from elsewhere, or build other power generating buildings.

drDragonSmoke commented 1 year ago

I've updated playk240.68k.asm and playk240.cnf so that it should build correctly now.

Thank you! Using your .asm and putting in extra code to check for powerplants did not freeze the game when the Emperor sent reinforcements! Game has been stable so far. I don't quite understand how you made this .asm but it must be much better at filtering out and properly labeling the branches than the one I made. So when extra code is added, the branch codes get properly updated. Amazing!

I guess the question now is whether to make the change to draw from asteros stores instead. It might be better to keep it as is, in order to not change the game mechanic.

drDragonSmoke commented 1 year ago

Emboldened by the apparent opportunity to add code, I set out to create the ultimate version of the Powerplant:

_14F0A:
    MOVEQ   #0,D3           ;14f0a: 7600
    TST.W   (46,A4)         ;; check for Powerplants
    BEQ.S   _14F28
;; If Powerplants
    MOVE.W  (46,A4),D4
    CMP.W   (62,A5),D4      ;; check if #Asteros in asteroid is less than #Powerplants
    BGT.S   _14F20
;; If enough Asteros in asteroid
    MOVE.B  intDay,D5
    ANDI.B  #$03,D5         ;; check if 4th day
    BNE.S   _14F22
; Reduce Asteros in asteroid by #Powerplants
    MOVE.W  (46,A4),D4
    SUB.W   D4,(62,A5)
    BRA.S   _14F22
_14F20:                     ;; I just made up this label name
    MOVE.W  (46,A4),D4
    CMP.W   (184,A5),D4     ;; check if #Asteros in stores is less than #Powerplants
    BGT.S   _14F28
;; If enough Asteros in stores
    MOVE.B  intDay,D5       ;14f12: 1a390002e45b
    ANDI.B  #$03,D5         ;14f18: 02050003
    BNE.S   _14F22          ;14f1c: 6604
; Reduce Asteros in stores by #Powerplants
    MOVE.W  (46,A4),D4
    SUB.W   D4,(184,A5)     ;14f1e: 536d003e
_14F22:
; Powerplant: (x32)
    MOVE.W  (46,A4),D3      ;14f22: 362c002e
    ASL.W   #5,D3           ;14f26: eb43
_14F28:

Fix:

Advantage given Powerplant:

Disadvantage given Powerplant:

There. Gonna pat myself on the back now. Thoughts and comments are always welcome.

tetracorp commented 1 year ago

Nice job!

Getting code insertion to work is a big discovery. I wasn't sure it would work before, but it should make it possible to insert things like debug code to show memory values in real time.

I think the reason why the annotated disassembly accepts changes is that it was generated from using the .cnf file which uses CODE defines to correctly identify which parts are code and which are data.

To be accurate to the manual, the Powerplant would also have to generate 8MW/day in the absence of Asteros. The manual author probably misread the code, though, since it's the CPU immediately after in the code that generates 8MW/day.

drDragonSmoke commented 1 year ago

... it was generated from using the .cnf file which uses CODE defines

Ah, yes I see those in the .cnf file. Is this something you figured out and entered manually? When I tried to make my own .asm I used the following commands: ira -a -keepzh -newstyle -compat=bi -preproc playk240 to create a .cnf (and .asm at the same time?) ira -a -keepzh -newstyle -compat=bi -config playk240 to create an .asm (or re-create it perhaps?) vasmm68k_mot -no-opt -Fhunkexe -nosym -o playk240 playk240.asm (to put it back together after editing code) I'm totally new at this, so please forgive my ignorance in this matter.

To be accurate to the manual, the Powerplant would also have to generate 8MW/day in the absence of Asteros.

I am not concerned with being accurate to the manual. Full disclosure, I am not a fan of the manual. I feel it is badly written and mostly an attempt to interpret the code, sometimes incorrectly. The manual also states that the powerplant "will use less ores to give a much reduced output of 8MW/day." I don't know how it could use "less ores" than 1. The manual also gets several other things wrong, and it would require a lot of changes if you wanted to make the game fit the manual. I prefer a minimalist approach, focusing on fixing obvious errors in the game mechanics.

tetracorp commented 1 year ago

ira generates the .asm from the executable. The -preproc option will also attempt to calculate the boundaries between code and data sections, which it stores in a .cnf file (it will also generate the .asm using these options). Thereafter, you can run with the -config to generate the .asm using the settings in that that .cnf file.

The preprocessor isn't perfect, it's usually necessary to manually edit the CODE statements in the .cnf to be correct and re-run ira. I also added a lot of comments and variable names in the .cnf, which are also incorporated into the .asm when -config is used. vasmm68_mot will thereafter reassemble the .asm into an executable.

The line "otherwise it will use less ores" is actually a typo by the person who transcribed the manual into text. The original manual reads "otherwise it will use useless ores". In other words, it uses leftover rock or something. It's just some fluff to explain why the Powerplant would generate 8MW without ores (which it doesn't, of course, the manual author is in error).

drDragonSmoke commented 1 year ago

it's usually necessary to manually edit

I am grateful for your work, dedication and skill in this matter. It has given me the chance to play a more internally consistent version of my favorite game, and to discover new things about it.

One last thing about the Powerplant: Is it possible to fix the typo on the Sci-Tek page, where it says "20MW/DAY" and change it to "32MW/DAY"? I've tried searching for hexadecimals that spell it out (in ASCII), but no luck.

tetracorp commented 1 year ago

Text strings are stored in english.mgl in a compressed format. It is possible to extract MGL format but I don't have a tool for re-packing MGL files.

Perhaps a fix is to have the init routines open string $183 and replace bytes 50 and 51 from "20" to "32" ($3230 to $3332).

drDragonSmoke commented 1 year ago

Thanks! I'm not too familiar with the code yet, so I shortened down my search and found the hexadecimals for 20MW/ in english.mgl.

I also noticed how the Sci-Tek page says that it generates "up to" 20mw/day. This may be an indication that the generation of 8mw/day with useless (i.e. no) ores was actually intended in the game.

tetracorp commented 1 year ago

This code should do it.

    JSR _LoadMGLFile        ;046de: 4eb900000d2c
fix32MW:
        move.w  #$183,d0
        jsr     _GetStringA0
        move.b  intLanguage,d0
        cmpi.b  #1,d0
        beq.s   fix32MWfr
        bpl.s   fix32MWde
fix32MWen:
        move.w  #$3332,(50,a0)
        bra.s   fix32MWde
fix32MWfr:
        move.w  #$3332,(37,a0)
fix32MWde:
    SF  flgPaused       ;046e4: 51f90002e458

It corrects it in all languages.

drDragonSmoke commented 1 year ago

Brilliant! This is certainly more elegant than hex-editing the .mgl file directly.