one month without an update – also one month on my side with very little Vectrex impact.
I finished Fallout IV (and played on for quite some time), started Skyrim VR, God of War, Wipout (VR) – and played Hearthstone.
Now I am starting to get back into Vectrex – slowly – before in two weeks I’ll be away for two weeks – holiday! Yeah!
Since I received some positive feedback, a couple of music/sound pieces and a success story of someone reaching continously boss 1 in Vectorblade…
– I have been thinking about Vectorblade again –
and my memory problems.
I started to shift data and functions from my main bank (bank 1) to my “support” bank (bank 0).
One particular problem I encountered is my use of memory addresses as part of the decision-making-data.
What I mean by that is e.g. (made up example – but internally similar things are coded):
If I spawn a shot – I must know if I have scoopies on my sides. If I had memory overflow I would have a flag somewhere which would indicate yes/no. As it is I check the behaviour function of the scoopy object. If it is 0x0000 than there is no scoopy if it is “enemyPlayerControlledRightBehaviour” – than it is a right scoopy.
In that case is logically the address of the corresponding behaviour function.
Now – if I move the “enemyPlayerControlledRightBehaviour” to the other bank I have no way of knowing what I have to compare to.
The address-space of bank 0 is completly seperate from the address-space of bank 1.
Using clever includes you can:
- use the same RAM
- have some space reserved that is in both banks exactly the same
But otherwise each bank is completely seperate from the other.
What makes things worse is – that the problem exists in both ways.
From bank 0 I sometimes need to access address information from bank 1, and sometimes I have to access address information in bank 0 from bank 1.
You might say that is bad coding – and you are probably right. I should have considered my memory layout from the beginning – or do a complete redesign so that it fits.
Well sadly that is not the way I work. I am lazy and I don’t like to do the same things over and over again. Thats probably why my products are not as polished as Thomas’ or Kristofs.
My style of work is more trial and error in combination with evolving code rather than design and redesign…
Anyway I could not figure out how to build a complete 2-bank binary with assembler access only. Since one way or the other you always have to compile one bank first and than you are missing data you need from the other.
If you have some clever way how to do that with “includes” and “if else endif” – you are more than welcome to tell me.
My last “escape” was Vide.
I have implemented a mechanism, with which I can translate (assemble that is) both banks without errors and than injecting the needed address information in the final binary.
I’ll describe that in the following. Actually it is quite easy – but probably hard to explain (and to read).
- I have two main files – one main file for each bank. They are called:
- “mainBank0.asm” contains as the first line:
; #genVarlist# varFrom0″
mainBank1.asm” contains as the first line:
; #genVarlist# varFrom1
- This tells the assembler to generate an output file called “varFrom0” (“varFrom1” respectivly) in which all variable/value pairs are listed
- At the place where I need information from the other bank I insert a special label, like:REPLACE_2_2_enemyPlayerControlledLeftBehaviour_varFrom1_0
cmpu #0 ; “0” will be replaced
- After the compilation of all banks a replacement mechanism is triggered that uses information gathered with above information to replace “banked” information dummies with real addresses.
That label contains all information needed for a post compile replacement:
- “REPLACE” indicates this lable contains REPLACE information
- “2” indicates replacement must occure two bytes after the label (cmpu is a second page opcode)
- “2” the replacement must be done for a 16 bit value (“1” would be an eight bit value)
- “enemyPlayerControlledLeftBehaviour” is the name of the variable that is used for the value in the other bank
- “varFrom1” is the filename from which the name/value pair is read
- “0” is a unique additional identifier (since the label parts before might be the same for several replacements)
Using the stuff above and some other optmizations I have about:
– 2500 bytes left in bank 0
– 5500 bytes left in bank 1
If I stick with my goal I have to magically pop some more memory out of the bins.
Per level – definition (including patterns, enemy definitions, behaviours…) I need about 100 bytes.
Implemented at the moment are 28 levels. Pure dumb calculation means I need about 7000 more bytes for the 100 levels I plan to do.
Also – level information must reside in the “main” bank.
Not done (STILL! not done):
– game over
– proper high scores
– some “extra enemies”
– warp fail/asteroid storm
– boss 2,3,4
– achievement system
You see – there are still SOME challenges left.
Only “visible” things I added since last alpha:
- super shot
a shot that does at once 5 damage to an opponent (but also does not “reduce”)
- lazer shot
(a shot that does 2 damage to all enemies that are directly “above” the player – per game round, lasts 10 rounds, with autofire – lasts indefenitly!)
Yes that one realy blasts enemies away – you’ll need it!
- autofire implemented
(but not collectible yet)
Both types also implemented for scoopies – which espcially for the lazer is quite devastating