Because a blank bitmap value must exist on either end of sprite objects, this can also make byte-sharing a bit more difficult to do (such as the portcullis object...I had to made a seperate sprite for each animation frame). Because sprite colors are read directly from the sprite bitmap image, it's also not possible to flash the sprite color (i.e. the chalise), or share bitmap graphics for something like the 3 dragons.
However, "simulated flash" can be done by defining multiple states for an object...and using unique color values for each sprite definition.
Other than that, any sprite can be recolored mid-screen. Color zero alerts the kernel that the sprite has ended...so if you want to use black, use color value 1 (bit0 is ignored for sprite colors). Just as before, use zero bitmap values if you want vertical spacing within any given object definition. The delimiter is reached from a zero in color data, so all 256 bitmap patterns and 128 colors are available. CTRLPF also still can be used mid-screen to select reverse/mirror and sprite priority of any band of graphics and enable either panel, and the last byte of the 4-byte defintion sets the number of 2lk scanlines to use for that band.
Besides making bitmap sprites take twice as much romspace (and unsharable...if a differently-colored sprite needs the same shape), no user ram was sacrificed The kernel still occupies less than a page, and all room graphics can still be shared among lines or entire screens (line counting is done with a seperate variable...screen definitions need not use an exact count).
Previous sprite recoloring glitches have all been corrected...tho a slight skew may still be visible on the extreme left edge if a bat wraps an object to the border in a multicolored room (sprite recolor of object1 hits at cycle 26...which is just a tad too late).
I wanted to illustrate how objects can be set to act as "invisible", so I also moved the castle portcullis objects' data up above the surround sprite (you can walk behind the gates). If you wanted to walk in FRONT of the gates, playfield priority must be set in the castle definition...at the band where the gates appear. Note however, that setting priority in this manner will HIDE any sprite object that is pushed into playfield walls in that band.
Also to better illustrate sprite recoloring, I made a bunch of color-shifts to the objects (particularly the surround, bridge, and signature objects).
Multicolored playfield data
Individual band colors can be done by using the multicolor playfield kernel. They can also be recolored (instead of using a full definition line) by including additional color values with bit0 set. The number of times you can recolor following scanlines is limited to #LINES - 2 (because the initial color is set in the data line, and the cache must execute at least once). When used, playfield recoloring begins at the next 2lk scanline, and continues for each successive one until the byte ahead no longer has bit0 set.
Dealing with page breaks (256-byte boundries)
By adding an additional table to display the ball, I saved enough cycles to allow jumping over page breaks (however, this is limited to recolor data in the multicolor kernel). Because the next playfield data line is cached in memory, each "band" of playfield data must be set to display at least two 2lk scanlines each - so the kernel has a chance to update the cache before it's needed. However...when updating the cache, the kernel does NOT have the spare time to correct a page break...so just use those 5 bytes as recolor values if you get stuck on what to do.
In the monocolor playfield kernel, data for screens can extend right over page breaks IF a fuill data line goes right up to it (i.e. the scanline count byte at $xxFF). If less than 4 bytes remain before a page break, the pointer will automatically SKIP those leftover bytes and begin using data at the start of the next following page.
The assembly can be instructed to produce a 16k or 32k binary, by setting BANKS = ~n up top (where ~n is 0, 1, or 2 to generate an F8, F6, or F4 banked ROM). The assembly will use the applicable banks only to produce the binary and ignores any invalid bankswitch info in the room table (invalid bank calls will be treated as the first bank). Just as in the previous thread, objects that can move from screen-to-screen must have bitmaps present in every bank (at identical addresses), but those confined to certian screens only need to exist in the same bank that it's room definition(s) do. So you shouldn't experience problems if you keep movable objects in the sprite macro - so they are automatically placed at identical addresses in each bank.
In the assembly, the monocolor playfield kernel is set by default...but you can swap it for the multicolor kernel in any bank you choose. Just be sure to include color data in room definitions that exist (in that entire bank) if you use the multicolor kernel. Leading into and out of the banks uses identical timing either way, so you can use both of them in differing banks in a single game (unless it's 8k...where you can only use one or the other). At the start of each bank, I put the names of both macros and commented out the multicolored one. Switch which one is commented out if you want to use the other.
Other options like dragons that face the ball when in pursuit, rotating sword, etc...can be toggled on or off before assembly. So can cheats to ignore collisions - which makes playtesting room links a lot quicker/easier.
Regarding the rotating sword specifically, tables CarryXtbl and CarryYtbl may require their values to be changed if you alter the appearance of the sword. I put the description of which direction each value applies to make this a bit easier (it would still mean a bit of experimentation, tho). If it isn't carried enough pixels away from the ball, you'll stop dead in your tracks.
You lose 1 byte of user ram to implement a rotating sword (to hold it's current state).
Custom Game Select Screen
"Room zero" has been eliminated from the list, that the room # is repurposed into the actual map instead of just eating away at one of the 128. The sample kernel is nothing spectacular...but the current advantage is that number tokens no longer need to be sprite objects (occupying 1 of the 256 you get). You could make the game selection screen as detailed as you wanted to...there's loads of free time leading into it. And because the macro is totally relocateable, you can place it in any bank that has enough free space for it Take note that side panels (missiles) are only set upon powerup originally...so this would need to be part of your return code if you want to use those sprites as part of the game select screen. Otherwise, anything goes!
Custom Game Map Screen
Kingdoms can be broken up into smaller areas joined from a "map screen" (this screen does not use a definition in the tables...but is activated by setting bit1 of the attract mode timer ON). The advantage is that enemy NPC's can be made to have a much smaller area to seek you...rather than roaming in a lot of empty rooms that the player is nowhere near. The display and collision routines between the 16x16 icons on this screen are done via subroutine, so additional icons can be added if you need more than 6.
To move into the map screen, find and touch the "swirl" object in the main game screens. When you touch an icon to enter a new area, the swirl object will follow you there...and enemy NPC's will be moved around (unless you are moving back to the area you just left).
The areas selected for each icon can be as specific as you want for each game selection...and the enemy NPC's can also be moved/revived as specific as you want, too.
Objects can be carried between the areas...however, carried items cannot be dropped on the map screen. If you reset out of the screen, the object will be at it's last valiid location (i.e. the screen that featured the swirl you entered). The bat automatically loses it's carried object between the areas...so if you had carried a bat between areas, it's item will exist at said location as well.
Game lost & game won screens
Between the title display and map display, I was left with an extra screen state. Use this option to create a display for winning and/or losing the game (a check for inactive game is done if both options are used to facilitate using both). Bitmap tables for these can cross page breaks...and bitmap image data for both PF0's are expected to be mixed (High nybble = left side, low nybble = center of screen). These screens (if used) will be located in the same bank that the stage select screen exists. They are nothing very advanced in the sample...but can be made as detailed as you'd want (you have loads of VBLANK time leading into them).
Single-bit castle portal states
By moving all three portal states to a single byte of ram (and using another to determine if a portal is currently opening or closing), I saved another byte of ram...those 2 bytes vs. the original method of using a seperate byte for each portal Also, because the castle state byte currently has 5 bits unused, you can add that many more castles @ NO COST of ram (tho you'd need to spend 3 bytes per key if you want to add more unique keys...otherwise, you could have the existing keys open new gates in other screens). The portals will operate pretty much the same as the originals...except that it won't allow you to lock a key in it's own castle anymore - the gate will swing back open if you try it!
VBLANK time required to deal with the gates (as a group) has been shortened considerably...so having more than a few castles should no longer be a problem. Rather than checking every gate for collisions, etc...the routine first checks to see if a gate IS on screen in a shorter loop (and breaks out of that loop if so...skipping everything if no castle screen is displayed).
Adding additional portal screens is easy...just bump up the GATES constant, and tack on additional screen and key data in the 3 data tables. You can place new gates on any screen -except- those where a gate already exists (like the original, you can't have 2 gates on a single screen).
Alternate (16k/32k) version moves sprites to a seperate bank to eliminate redundancy (so you get an entire bank for sprites, and other banks can be fully used for room gfx only). A couple of other surprises in there too. However, recoloring lines can only happen AFTER the playfield has been updated...so it doesn't yet completely replace the original multicolor playfield version.
In this newer version, NPC's all use 1 less byte of ram each (that makes a total savings of 42 from the original game) by merging their state and direction variables. The extra 5 keys are scattered around, but currently unused.
Current assembly + 8k sample binary, and alternate 16k version:
Edited by Nukey Shay, Fri Apr 1, 2011 5:53 AM.