Scripted attacks

Monday, 3rd October 2005

Attack patterns can now be simply scripted as a list of 4-byte chunks, covering which enemy to use, the delay between adding them, how many of them to add, the delay between them and a delay after adding the last one.
For example, this:
.db $04,16,8,100
...would add 8 enemies of type $04, adding one every 16 game ticks and then pausing for 100 game ticks after adding the last one then progressing to the next scripted enemy.
To support this, I've added some new per-level parameters, covering:

  • Attack type (random or 'scripted') with delay between enemies or a pointer to script to follow.
  • Speed of enemies.
  • Speed of landscape scrolling (used very little - bonus levels with no enemies/mines scroll past extra-quickly).
  • Maximum number of mines.

Using all the above, I can easily configure each level's attack patterns quite simply.
Doing this has identified a number of bugs (mostly where new enemies were being initialised without clearing out a particular byte, which means that certain sequences would start in odd places) which have now been ironed out.

I have also picked up work again on my music system for the game. I have a very bad 12-bar-blues demo running with it - I need to find a decent pitch-to-period table as the one I calculated in Excel sounds slightly wrong. There are also some minor-ish reset bugs (the first time in-game a note is played the instrument is full volume for one frame plus some minor synch issues). Looks like I'll have to write the music in Notepad, though - who'd have thought that getting low-level access to the sound card was so bloody difficult in anything other than C (and I'm damned if I'm going to have to write a GUI system for the Windows console, and Win32 is too mucky to deal with for such as simple application). This is great fun, as you can imagine - take, for example, this: (the 12-bar-blues demo for the testbed for the music system)

; Demo tune

demo_tune:

; Instrument table:

.db 2		; Number of instruments
.dw simple
.dw vib

; Sequence table:

.db 6		; Number of sequences
.dw run_c
.dw run_f
.dw run_g
.dw bass_c
.dw bass_f
.dw bass_g

; Tune!

.db %00000000, %00000000
.db %00000011, %00000001
.db %10000000, %10001000

.db %00000000, %00000000
.db %10000000, %10001000

.db %00000001, %00000000
.db %00000100, %00000001
.db %10000000, %10001000

.db %00000000, %00000000
.db %00000011, %00000001
.db %10000000, %10001000

.db %00000010, %00000000
.db %00000101, %00000001
.db %10000000, %10001000

.db %00000001, %00000000
.db %00000100, %00000001
.db %10000000, %10001000

.db %00000000, %00000000
.db %00000011, %00000001
.db %10000000, %10001000

.db %00000000, %00000000
.db %10000000, %10001000

.db %11111111

; Sequences:

run_c:
	.db 1

	.db (144>>8)+%01000000
	.db (144&%11111111)
	.db $10

	.db (112>>8)+%01000000
	.db (112&%11111111)
	.db $10

	.db (93>>8)+%01000000
	.db (93&%11111111)
	.db $10

	.db (82>>8)+%01000000
	.db (82&%11111111)
	.db $10

	.db (77>>8)+%01000000
	.db (77&%11111111)
	.db $10

	.db (82>>8)+%01000000
	.db (82&%11111111)
	.db $10

	.db (93>>8)+%01000000
	.db (93&%11111111)
	.db $10

	.db (112>>8)+%01000000
	.db (112&%11111111)
	.db $10

	.db %11000000

run_f:
	.db 1

	.db (105>>8)+%01000000
	.db (105&%11111111)
	.db $10

	.db (82>>8)+%01000000
	.db (82&%11111111)
	.db $10

	.db (68>>8)+%01000000
	.db (68&%11111111)
	.db $10

	.db (60>>8)+%01000000
	.db (60&%11111111)
	.db $10

	.db (56>>8)+%01000000
	.db (56&%11111111)
	.db $10

	.db (60>>8)+%01000000
	.db (60&%11111111)
	.db $10

	.db (68>>8)+%01000000
	.db (68&%11111111)
	.db $10

	.db (82>>8)+%01000000
	.db (82&%11111111)
	.db $10

	.db %11000000

run_g:

	.db 1

	.db (93>>8)+%01000000
	.db (93&%11111111)
	.db $10

	.db (72>>8)+%01000000
	.db (72&%11111111)
	.db $10

	.db (60>>8)+%01000000
	.db (60&%11111111)
	.db $10

	.db (53>>8)+%01000000
	.db (53&%11111111)
	.db $10

	.db (49>>8)+%01000000
	.db (49&%11111111)
	.db $10

	.db (53>>8)+%01000000
	.db (53&%11111111)
	.db $10

	.db (60>>8)+%01000000
	.db (60&%11111111)
	.db $10

	.db (72>>8)+%01000000
	.db (72&%11111111)
	.db $10

	.db %11000000


bass_c:
	.db 0
	.db (307>>8)+%01000000
	.db (307&%11111111)
	.db 8
	.db (144>>8)+%01000000
	.db (144&%11111111)
	.db 8
	.db %11111111

bass_f:
	.db 0
	.db (224>>8)+%01000000
	.db (224&%11111111)
	.db 8
	.db (105>>8)+%01000000
	.db (105&%11111111)
	.db 8
	.db %11111111

bass_g:
	.db 0
	.db (198>>8)+%01000000
	.db (198&%11111111)
	.db 8
	.db (93>>8)+%01000000
	.db (93&%11111111)
	.db 8
	.db %11111111

; Instruments:

simple:
.db 4	; Length
.db 255
.db -64

.db 8
.db 0
.db 32

.db 1
.db 255
.db 0

.db 0

vib:

.db 2
.db 128
.db 50
.db 2
.db 128
.db -50
.db 2
.db 128
.db 50
.db 1
.db 128
.db -50
.db 1
.db 128
.db 50
.db 3
.db 128
.db -50

.db 10
.db 128
.db 14
.db 0

Thankfully, the assembler can handle me sticking sums in rather than hard-coded values in places making things a lot simpler... but it's still a bit mucky. Ah well. There is no noise channel set up, either, so no krch-krch-krch style beats from the white-noise generator as such.

Enemies Galore

Friday, 30th September 2005

I completely rewrote every single attack pattern from scratch (pretty much - the precalculated paths were left intact) last night. The result of having the ability to start any enemy attack pattern at any time (within reason - I only provide 8 enemy slots!) results in nothing short of sheer mayhem. Yes, collision detection was disabled for the video. I'm looking at you, evolutional... razz.gif

video.jpg
Is that enough enemies, do you think? [AVI/MPEG-4/1.62MB]

The small blobs that drift towards me are the aforementioned mines. The attack frequency, number of enemies on-screen and number of mines is far in excess of anything that you'd encounter in the game - this was just a test to add as much to the game as possible.

Another plus-point of the rewrite is that the game now runs correctly inside MEKA, another widely-used Sega Master System emulator. It had issues with certain attacks keeping their sprites way off screen as they ran in, which worked fine on hardware and in Emukon, but not in Meka for some bizarre reason.

One particular running bug that has been very difficult to trace was an annoying flicker in the sprites. Every so often, some of the sprites would disappear for a single frame. Normally it would be a couple, but sometimes ALL the sprites would vanish.

What could it be? Video timing issues? No, Emukon (the emulator I'm using) pops up incorrectly timed VDP writes in a handy window. Enemy drawing code that was accessing another sprite's data, switching it off? In a similar vein, had I miscounted pointer increments in one particular chunk of code for handling enemies, so in certain conditions it would offset all further array writes by a byte, writing incorrect data into the "enemy disable" byte? After much painful analysis, it appears the routines were pretty watertight... Not PUSHing/POPping registers to the stack before calling a destructive routine?

Well, after much pulling out of hair I have found the problem.

The VDP (the graphics chip I'm controlling) has a certain amount of VRAM. One area in that VRAM is dedicated to a sprite table. First you have a list of Y-coordinates, then a list of X-coordinates followed by sprite index numbers. There is a "magic" Y coordinate, $D0. When the VDP hits this particular Y coordinate, it stops drawing sprites! You can (and I do) use this as a stop byte on the sprite table to tell the VDP when you've finished adding sprites (as each frame has a variable number of sprites on it - I'm trying to keep the game nice and dynamic).

So, what's the problem with that? It turns out that SOMETHING - star code, explosion code, bullet code, enemy attack code, I'm not sure which - is trying to draw sprites with a Y coordinate of $D0! Adding this block of code into my sprite drawing routines (I have two - one for 8x16 sprites, such as the stars, bullets and score digits and another that pairs them up for 16x16 sprites, the size of everything else) fixed the rare flicker bug.

	cp $D0
	jr nz,+
	inc a
+:

Nice and simple, but it does the trick. smile.gif

scr_1.png scr_2.png scr_3.png scr_4.png

ARGH!

Thursday, 29th September 2005

Fire Track (on the BBC Micro) is probably the fastest, hardest, most adrenaline-packed space shooter I've ever played!
I'm playing my way through the extended version to try and work out the game mechanics a bit more. I've been using an ancient "infinite lives" cheat disk with it, but even so... whew, this game is tough.
I have saved state images for Levels 1 to 22, though, at last. My nerves are shot to pieces, in any case!

It appears that I have to rethink the way enemies are handled. Currently, I store a list of 8 enemies and assume they all follow the same pattern. Wrong. For most of the game, you can have lots of enemies on-screen, each from a different pattern! Or the patterns can overlap, even. What I think I'll do instead is have a list of enemies with ID (attack type - I'll use the sprite number), (X,Y) coordinate (if it's (0,0) it means the slot is free, no enemy) then 5 bytes of extra storage that the enemy attack handler for that enemy can do whatever the Hell they like with. If I have a timer that decreases and fires off the next enemy whenever it underflows (either a predetermined one from a table of enemy attacks or just picking a random one - or, for some of the bonus levels, none at all). Plus, I can rewrite it without lots of use of the slow IX register.

I have, however, added mine support. There's a function to add a mine at a particular (x,y), where it gets set up correctly and will drift towards you (the DX and DY are set up when you add the mine). They aren't part of the collision detection routines yet (I'll add them with the enemy system rewrite) but already scare me wink.gif

mines_2.png mines_1.png mines_3.png

The above is the worst-case scenario - there are not usually more than 4-5 mines on screen at any one time.

As you can probably also see, there is still no black bar at the top of the display. I can't quite work out how to enable/handle line interrupts from the VDP, but have found a nice part of the VRAM that isn't being written to that is just the right size for use as an alternate name table. The way this'll work is that I switch the background layer to another location in VRAM for which tiles to use that is all blacked out, wait until I hit a scanline 8 pixels down then switch back to the name table which contains my real background layer. I don't have to deal with cutting out any sprites as I have 8 sprites dedicated to the score at the top, and as you probably know by now from my constant moaning about it there is an 8-sprite-per-scanline limit hence my score will stop anything else from being drawn in the sprite layer at the top.

Finally, here's a picture of the biggest pest I know - linkified for the spider-haters. These buggers are not very large (5-8cms, biggest approaching 10cms) but very annoying - they seem to like following set paths, and will run around back and forth on the edge of my vision. This particular one was very reluctant to be picked up and lobbed out of the window...

Fading

Wednesday, 28th September 2005

I spent a while last night on a reusable routine to fade between two different palettes.

fade_1.pngfade_2.pngfade_3.pngfade_4.png

It just happens to be one of the muckiest pieces of code written so far. You can see it in action in a video I've knocked together here (262KB). [I haven't put together a video for a while, so any old excuse, eh?]

I rejigged a few bits of the code, including neatening up the core sprite routines (so they are now much faster, huzzah!)

I ran a test on what it would look like if I added 8 "mines" (sprite limit and all that). The result? Sprite flicker is very very low! Looks like I'll be able to add the mines without issue...

These mines are rather evil. You get varying numbers of them, starting with very few in the early levels and going up to 8 in the later levels (well, as far as I've managed to get!). As enemies appear on screen they "lay" a trail of mines that drift towards you.

mines.gif
(Screenshot from BeebEm).

VGM Player now works!

Tuesday, 27th September 2005

Lots of fixes...
Download here! (New package includes loading music from Fire Track as a sample)

- Fixed reading of files. I'd used 'char' instead of 'unsigned char'. Files
  that played back as plain silence now play back fully, also play at correct
  speed. What a stupid mistake - it's amazing it worked at all!
  I ended up rewriting the entire PSG emulation thinking it was that that was
  to blame... evidently not!
- Halved frequency of noise channel by only switching output once on 2 clocks.
  It was an octave too high before!
- Fixed odd jumping/incorrect (after loop) seek bar.
- Changed [x] exit button to use 'x' character rather than the cross symbol -
  the cross appeared as a "Pt" sign under Windows 2000.
- Removed display of Japanese tags.
- VGM files that loop back to the exact start of the file are now looped rather
  than ignored.
- Added display of system name for noise mode and very stupid autodetection.
- Sound output is now averaged inside each 44100Hz sample to "antialias" the
  output. Sound output that relies on channels at 0 outputting fully now work.
  Sampled audio still sounds a bit noisy/weird. Sound is now output at 16-bit.
- Option to enable/disable sound channels individually.
- Accelerated seeking considerably.

Page 48 of 53 144 45 46 47 48 49 50 51 52 53

Older postsNewer postsLatest posts RSSSearchBrowse by dateIndexTags