Mercenary: Een technische analyse van een Commodore 64-meesterwerk

01. De stad in lijnen: Eén gebouw tegelijk

Om het renderen beheersbaar te houden, houdt het spel slechts één gebouw tegelijk in het geheugen. Het vierkant waarin de speler zich bevindt, bepaalt welk gebouw actief is.

Het gebouw van het huidige vierkant wordt alleen geladen wanneer het hoge byte van de X- of Y-coördinaat verandert ($94FE-$952F), en wordt alleen getekend als de speler laag genoeg is (hoogte onder 65.536). Hierdoor lijken gebouwen pas te verschijnen ('pop in') wanneer men het vierkant betreedt.

Vanaf grotere hoogte zijn de wegen zichtbaar. Deze worden getekend vanaf hoogte 2.048 als lijnen tussen de centra van de vierkanten die ze verbinden. Bij een hoogte van $200000 wordt dit vervangen door een vast beeld van 13 wegen ($902A).

02. Bug: De Colony Craft-lift

Bij de start crashlandt de speler op positie 08-08. De Colony Craft hangt direct boven de speler op hoogte 64.997. Hoewel er op de grond geen lift is, bevindt zich daar een onzichtbaar stuk gras (1.024 eenheden breed, ongeveer 14 seconden lopen vanaf het landingspunt) dat reageert op de E-toets alsof het de lift op het dek van de Colony Craft is.

De rit 'omlaag' leidt naar de hangar van de Colony Craft; het opnieuw indrukken van de E-toets brengt de speler omhoog naar het dek.

Technische achtergrond

De lift is vermelding 8 in de tabel van lift-vierkanten op $B4B6/$B4BE. De test voor de E-toets controleert het vierkant en de middelste bytes van X en Y, maar leest nooit de hoogte. Daarom werkt het stuk gras onder het dek exact hetzelfde als de lift zelf.

De rit omlaag eindigt in kamer 8 (de hangar). De lift omhoog vanuit kamer 8 werkt zoals verwacht: zodra deze de oppervlakte bereikt, voegt $A312 de waarde $40FF00 toe aan de hoogte, waardoor de speler op het dek eindigt. De ondergrond heeft geen eigen hoogte; een kamer is een aparte box en er ligt geen kamer onder een willekeurig punt in de stad.

03. Buiten de stad: Exotische bestemmingen

De stad Targ is 16 vierkanten breed in een wereld van 256. In het omliggende niemandsland bevinden zich vier objecten: twee liften naar hangars, een piramide en een mast.

Geen enkel gebouw wordt buiten de stad getekend; het spel laadt alleen modellen voor vierkanten 0 tot 15 op beide assen ($952B). De twee liften buiten de stad zijn daarom objecten (61 en 62), bestaande uit vier gestapelde vierkanten van 1.024 eenheden breed. Onder deze liften liggen twee hangarcomplexen: hangar 6 heeft drie kamers, en hangar 7 heeft er zeven (hier start object 3, het jetvliegtuig).

Overige objecten:

  • De piramide (object 56): Wanneer dit object wordt gedragen, kan de D-toets het object in de lucht laten vallen, waar het op de huidige hoogte blijft hangen ($98FE).
  • De mast (object 50): Dit object heeft geen naam in de code en het is onbekend waarvoor het dient.

04. De andere vaartuigen

Het schip van de zwager

Er vliegt één schip autonoom vanaf het begin van het spel. Het is eigendom van de zwager van de Palyar-commandant, heeft de vorm van een Dart en vliegt eeuwig in een lus langs de westelijke rand van de stad op hoogte 32.769 (ALT 00500).

Het schip is object 0 (model $3B25). De X-coördinaat is constant $006F41 en de hoogte is altijd 32.769; alleen de Y-coördinaat verandert. Niemand kan dit schip besturen, omdat men er niet op kan landen. Toch heeft het een eigen bewegingsrecord (record 0) en is het het snelste vaartuig in het spel met een topsnelheid van 11.475.

Het neerschieten van dit schip start script 27: "YOU HAVE JUST DESTROYED THE PALYAR COMMANDER'S BROTHER-IN-LAWS NEW SHIP", gevolgd door "PALYAR SHIP ATTACKING". Dit activeert de woede van de zwager (bit 5 van $BEC0).

Het aanvalsschip

Een aanval bestaat uit één schip (object 15). Het richt zich op de speler, vliegt 46 passen en richt zich opnieuw. Het overschiet de speler telkens, waardoor het in een zigzagpatroon dichterbij komt. Pas als het aan het einde van een 'leg' binnen 12.288 eenheden op elke as is, vuurt het ($893E).

Het afgevuurde projectiel (object 14) vliegt in een rechte lijn zonder sturing. Een voltreffer flitst het scherm wit, print "SHIP DESTROYED" en brengt de speler in de valmodus.

Het gehuurde schip

Het interstellaire schip (object 7) komt aan nadat men het heeft gehuurd via de radio in kamer $10. Het verschijnt op een hoogte van 8.323.072 eenheden en daalt over 779 passen af naar de oppervlakte.

Stationaire Darts

Objecten 8 tot 15 zijn bewegende objecten, maar slechts drie krijgen een 'levensduur'. Object 9 kan echter verschijnen als de speler via CTRL+Q zijn huidige vaartuig dumpt terwijl hij valt. Dit resulteert in een Dart op de grond die niet kan worden betreden, omdat de B-toets (board) alleen objecten 0 tot 7 accepteert.

05. Geheim: Onopgemerkt gebouwen vernietigen

Een gebouw dat wordt beschoten vanuit een aangrenzend vierkant wordt vernietigd, maar het spel registreert dit pas als de speler binnen 16 passen het betreffende vierkant betreedt.

Wanneer een projectiel binnen 4.096 eenheden van het centrum van een vierkant komt (onder hoogte 2.048), markeert $871B het vierkant als vernietigd in $2B00 en start een aftelling van 16 passen in $F4. Pas na deze aftelling wordt het gebouw daadwerkelijk laten zinken, worden de statistieken van de Palyars of Mechanoids bijgewerkt en wordt het bijbehorende script gestart. Als de speler niet in het vierkant staat, loopt de timer af zonder dat het spel de vernietiging meldt of een aanval start.

06. De oorlog van de reclameborden

Tien vierkanten in de stad bevatten reclameborden: vijf met het Commodore-logo en vijf met dat van Atari. Het vernietigen hiervan levert verschillende reacties op.

  • Commodore-logo's (o.a. 13-04, 03-13): Vernietiging resulteert in de melding "TRAITOR!".
  • Atari-logo's (o.a. 14-05, 14-08): Vernietiging resulteert in de melding "GOOD SHOW!".

De tabel op $2B00 bepaalt de eigenaar van het vierkant en het scriptnummer n. Bij vernietiging wordt script 32 + n uitgevoerd. Scripts 36 tot 48 noemen het specifieke herkenningspunt (bijv. "BOSHER STADIUM"), terwijl scripts 49 en 50 enkel de korte reactie geven.

07. Het scherm en rendering

Het beeld is een bitmap van 160 bij 136 pixels. Er wordt gebruikgemaakt van double buffering: het spel tekent in de ene bitmap terwijl de andere wordt getoond. De bitmaps bevinden zich in de tweede bank van de videochip op $4000 en $6000.

De framerate varieert: vanuit een hoog overzicht over de stad duurt het 13 frames om een beeld te tekenen (ongeveer 4 fps). Op de grond, waar slechts één gebouw getekend hoeft te worden, loopt de loop op naar 5 fps.

08. Het vliegmodel

Alle vaartuigen (behalve het interstellaire schip) gebruiken hetzelfde vliegmodel. De handling wordt gelezen uit een record van 16 bytes.

Belangrijke kenmerken:

  • Gashendel: De snelheid streeft naar een doelsnelheid. Elke pas wordt de snelheid berekend als (snelheid + gas × stuwkracht) × behoud.
  • Starten: Op de grond wordt de neus waterpas gehouden bij snelheden onder 128. Daarboven zakt het vaartuig door een sinuswaarde van -0,003, tenzij de speler de neus optrekt.
  • Plafond: Elk vaartuig heeft een hard plafond. Boven dit plafond neemt de klimcapaciteit af tot het punt waar de stap nul is. De Dart stopt bij ALT 24.000; vaartuigen met de Poweramp (zoals de jet of de CHEESE) bereiken ALT 105.000.
  • Crash: Een crash vindt plaats wanneer de hoogteverandering in één pas 256 eenheden of meer is, of wanneer de neus meer dan 45 graden naar beneden wijst.

09. Vaartuigen en motion records

De handling van elk vaartuig is opgeslagen in records van 16 bytes op $9DAD. Deze gegevens worden gekopieerd naar $BEA0 bij het instappen.

De getallen zijn opgeslagen als 'floats' bestaande uit een mantisse-byte m en een exponent-byte, met de waarde (1 + m/256) × 2^e.

10. Topsnelheden

De topsnelheden in het spel komen exact overeen met de tabel die in mei 1986 in het blad Zzap!64 werd gepubliceerd. De snelheid wordt op het paneel weergegeven via routine $B5A8, waarbij het hele getal wordt getoond. Het indrukken van de + toets vermenigvuldigt de gasgave met 1,03 per pas, tot een maximum van 32.512.

11. De ondergrond

De ondergrond bestaat uit 174 kamers. Elke kamer is een record van enkele bytes: drie afmetingen, twee kleuren en vier bytes per deur. Kamers worden getekend als een draadmodel-box (wireframe) met deuropeningen op de muren.

Een kamerrecord bevat de X-breedte, hoogte en Y-diepte in eenheden van 256. De kleuren bepalen de vulling van de kamer en de kleur van de lijnen. Deuren bevatten informatie over het type deur, de muur waarin ze zich bevinden, de doelkamer en de positie op de muur.

12. Objecten

Alles in het spel dat geen stad of kamer is, is een van de 64 objecten. Dit omvat vaartuigen, draagbare items, meubels en borden.

Objecten worden gedefinieerd door een positie, een kamer, een model (bestaande uit vertices en edges) en een byte met flags. Flags bepalen of een object 'vast' is (vereist de Kitchen Sink om te verplaatsen) of 'zwaar' (vereist de Antigrav of de Sink). Objecten 0 tot 7 kunnen worden betreden; objecten 8 tot 15 worden door het spel zelf bewogen (zoals raketten).

13. Benson: De computer

Benson communiceert via een strip van 23 cellen onderaan het paneel. Tijdens het printen van tekst produceert Benson een geluid: een vierkantsgolf waarvan de frequentie elke frame wordt aangepast aan het karakter dat net is geprint.

Technische details van de stem:

  • De printer schrijft naar $D40F (de hoge byte van de frequentie).
  • De letters A tot Z produceren tonen over een bereik van ongeveer zeven halve tonen.
  • Spaties resulteren in een frequentie van 0, waardoor de oscillator stopt en het geluid verstomt.
  • Elke regel tekst duurt ongeveer 2,5 seconden (25 frames printen, gevolgd door 99 frames stilte).

14. Geluid en audio

Het spel bevat geen muziek, enkel 13 geluidseffecten van vier bytes per stuk.

Specifieke geluiden:

  • De lift: Produceert een bromgeluid waarbij de toonhoogte varieert naargelang de positie in de schacht (laag aan de uiteinden, hoog in het midden).
  • Deuren: Gebruiken een driehoeksgolf op voice 2, ring-gemoduleerd door voice 1. De toonhoogte verandert afhankelijk van of men door een deur naar binnen of naar buiten loopt.
  • De motor: Maakt gebruik van noise op voice 2. Het sustain-niveau (volume) is gekoppeld aan de snelheid: elke verdubbeling van de snelheid zorgt voor een stap in volume. Bij zeer lage snelheden (tussen -8 en -16 eenheden) valt de motor stil.

15. Opslag van berichten

Berichten zijn lijsten van tokens. De meeste tokens verwijzen naar woorden in een dictionary ($1249-$151B).

  • Tokens 1 tot 7 zijn uitgangen (zoals 'S' of 'ED') die aan het vorige woord worden geplakt.
  • Tokens van 8 of hoger zijn volledige woorden met een spatie ervoor.
  • $EF is een spatie, $F8-$FE printen tellers in decimaal, en $FF start letterlijke tekst.
  • Woorden 230 tot 238 zijn spaties van verschillende lengtes, gebruikt om tekst te centreren.

16. Event-scripts

De acties van Benson en de gebeurtenissen in het spel worden gestuurd door 51 scripts geschreven in een kleine byte-code. Er zijn in totaal 527 operaties.

Elke operatie wordt per pass van de main loop uitgevoerd. De interpreter wacht tot een bericht is klaar met printen voordat hij doorgaat. Triggers voor scripts komen uit kamerrecords, object-flags, de vierkant-tabel of specifieke code-aanroepen.

17. Geld in BCD

Credits worden opgeslagen als acht decimale cijfers in vier bytes (Binary Coded Decimal). Omdat de scripts geen aftrekkingsfunctie hebben, wordt een aankoop gedaan door het complement van tien van de prijs op te tellen.

Bijvoorbeeld: De startcredits zijn 9.000. De Dominion Dart kost 5.000. In plaats van 5.000 af te trekken, telt het spel een waarde op die, samen met de 9.000, resulteert in 4.000 (waarbij de overloop van het hoogste cijfer wordt genegeerd).

18. Getallen en wiskunde

Voor de 3D-view gebruikt het spel twee-byte floats (mantisse en macht van twee). Vermenigvuldiging en deling gebeuren niet direct, maar door het optellen of aftrekken van logaritmen uit een tabel van 256 bytes ($5800 en $5900).

19. Lijnen tekenen

Elke lijn in het beeld wordt getekend door een van acht routines, één per octant. De routine stapt langs de langste as en voegt een hellingswaarde (slope) toe aan een 8-bit teller; zodra deze teller overloopt, wordt er een stap in de zijwaartse richting gezet.

20. Bediening

Het spel scant het toetsenbord direct en zet elke toets om in een nummer (rij × 8 + kolom). De joystick is aangesloten op poort 2.

Belangrijkste toetsen:

  • T: Object oppakken (binnen 256 eenheden).
  • B: In een vaartuig stappen (binnen 512 eenheden).
  • D: Object laten vallen.
  • L: Vaartuig verlaten.
  • E: De lift gebruiken.
  • CTRL+Q: Alles dumpen en opnieuw starten in de Dart.

21. De opening

Het spel begint in de ruimte met een aftelling, gevolgd door een falende Novadrive en een crashlanding op Targ. De opening is geschreven in dezelfde byte-code als de event-scripts, maar bevindt zich in een geheugenlocatie die wordt overschreven door de tweede bitmap zodra het spel begint.

Op sommige versies is de tekst "NOVADRIVE COUNTDOWN" vervangen door "ABC UNLIMITED", de naam van een cracking-groep.

22. Kopieerbeveiliging

De originele disk van Novagen is zo geconfigureerd dat de reset-knop het spel niet terugbrengt naar BASIC, maar in een oneindige loop terechtkomt. Dit gebeurt doordat de KERNAL bij reset controleert op de letters CBM80 op adres $8004. Als deze aanwezig zijn, springt de machine naar een routine die het systeem effectief bevriest of het geheugen wist.

23. Diversen

  • Atari-restanten: In het geheugen ($BCB8-$BCFF) bevindt zich een stukje van een Atari DOS 2-menu. Dit wordt door het spel nooit gelezen.
  • Benson's ongeduld: Als de speler te lang niets doet na het aanbod van de Dart, vraagt Benson: "IS ANYBODY THERE?" of "ARE YOU STILL ALIVE?".
  • Regio-lock: Het spel crasht op Amerikaanse (NTSC) machines omdat routine $5024 specifiek controleert op de PAL-flag van de KERNAL.
  • Savefiles: Een savefile van 1.904 bytes bevat de hele wereldstatus, inclusief alle objectposities, script-states en de zero page.
  • Auteurs-easter egg: Als het reclamebord op 02-03 is vernietigd, weigert het schip te vertrekken met de melding: "THE AUTHOR WON'T LET YOU LEAVE UNTIL YOU FIX HIS ADVERT". Dit is een verwijzing naar het eerdere spel Encounter van de auteur.