Jump to content
IGNORED

Adventure w/multicolor sprites


Nukey Shay

Recommended Posts

Multicolored sprite data

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.

 

 

Rom options

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:

Adventure(sprite_recolor).zip

Adventure(16-32).zip

Edited by Nukey Shay
Link to comment
Share on other sites

A little closer...

 

Either multicolor sprite kernel can be used now (or both in a single 16k binary)...but with another restriction:

 

Data is cached one band ahead of time...and the program never checks if a boundry is near. For that reason, any playfield definition must end at least 4 bytes before a page boundry for monocolor playfields, and at least 5 bytes before a page boundry for multicolor playfields. Sorry about this little catch...might be able to correct it later. It goes without saying, but ALL band definitions must be at least 2 double scanlines (so the cache has at least one chance to run)...and band recoloring is not permitted (you need a full set of 5 bytes here to change the color).

 

I fixed the sprite color problem on the left...but now it sometimes ripples on the right :( At least the ball is corrected. Panels are fixed too (they can be enabled or disabled on any band).

Link to comment
Share on other sites

File updated...crossing page boundries is now allowed for playfield data in both kernels - only between FULL data lines (4 bytes for monocolor, 5 bytes for multicolor). When using the monocolor kernel, just skip the 1-3 remaining bytes in a page (if present) using ALIGN and continue with the screen definition. Skipping boundries in the multicolor kernel is only allowed in "recolor" data (a recolor data byte is allowed to be at $xxFF...any other data byte, including LINES, is not). So if you are not recoloring the line per se, just add recolor data to fill leftover bytes between full bands. In addition, 1 chance of recoloring has been lost per band...since the kernel MUST be given at least 1 opportunity to cache the next data line. This restriction does not necessarily apply to the very last displayed band, however (since caching a "next" line is irrelevant at the end of the display).

 

Ex:

Multicolor data format is this:

COLOR,PF0,PF1,PF2,LINES {,recolor1, recolor2, etc)

 

COLOR must be an even value (bit0 not set). If (for example) LINES is equal to 8, you can include up to 6 recolor values (the initial color for the first 2lk scanline is set by the first byte in the band definition, and the cache must be allowed to run at least once - taking the last 2lk scanline. 8 - 2 = 6). Recoloring begins right at the start of the next 2lk scanline, and every 2lk scanline that follows. If you don't like the "missed chance" where it exists in one band, add more full definition lines ;)

 

Like the old "monocolor sprites" version, the multicolor kernel is alerted to recolor data by such values having bit0 set. Any non-playfield data that follows a screen definition must also begin using an even value...so the kernel does not mistake unrelated data as recolor instructions. This is not much of an issue, since all playfields would be initially starting out with an even value...unless you happen to be sharing definition lines among screens (which is difficult in multicolor anyway).

Edited by Nukey Shay
Link to comment
Share on other sites

By request...

32k (F4) banking added to the assembly. ROM16K directive has been removed and replaced with BANKS instead. Ignoring bit4 in the room MSB table allowed this to be added with no increase of table size.

 

Also...

RoomDiffs format has been slightly changed to allow up to 128 map changes per game level. If additional levels are added, the program will require additional branch(es) to read from their own specific table.

 

Moving left has been altered to end at co-ordinate #2 instead of #3 (this should solve the problem of getting hung up on walls occasionally when moving vertically).

 

An option to simulate the flashing chalise is added...done by making multiple chalise frames with altered colors.

 

DoVSYNC routine has been altered to free additional cycles per frame. This works fine in emulation, but needs confirmation with real hardware.

Link to comment
Share on other sites

Custom game select screen added (see note in first post). It can be made pretty much as complex as you want (in any bank you want)...rather than having to use a standard Adventure room :)

 

Object width table has been eliminated...I merged this info with Object_Data_MSB, and it's looking good.

Link to comment
Share on other sites

I owe it to you guys for providing the ideas and challenges to get the game to conform to. The difficult part is keeping this one generic (because there's a definate goal in every case).

 

The current problem from making the game world bigger is that the enemies are spread too thin. By expanding the map difference tables and eliminating room zero, it may become possible to expand the game to do "miniquests"...relocating NPC's to whatever portion of the game the player is currently exploring rather than having them search the entire game world to get at you.

Link to comment
Share on other sites

I owe it to you guys for providing the ideas and challenges to get the game to conform to. The difficult part is keeping this one generic (because there's a definate goal in every case).

I've had some good ideas in the past, but I think all the new ones are coming from the young guns. ;) They are also the ones with the creativity (never my strong suit) to make some awesome new hacks.

 

The current problem from making the game world bigger is that the enemies are spread too thin. By expanding the map difference tables and eliminating room zero, it may become possible to expand the game to do "miniquests"...relocating NPC's to whatever portion of the game the player is currently exploring rather than having them search the entire game world to get at you.

About room zero, I was wondering if it would be a good idea to make it into the secret room. That way when someone adds rooms they would not have to worry about objects being put in the secret room randomly which messes things up. It's a bit of a nuisance for a new hacker to deal with since there are quite a few details that go into the secret room setup (the dot, dragons can't go in, etc.) Just a thought.

Link to comment
Share on other sites

All rooms and map directions are labelled...so adding new ones does not need to happen solely at the end of the list. Just put 'em in wherever you want.

 

For example, if you wanted a room to exist between the two lower panel rooms, just add a new data line at any spot in the list. The existing directions will automatically be adjusted and need no editing...just need to alter the move left and right from those two panel screens to point at the new one.

 

The FIX_RANDOM directive does this too...by shuffling castle interiors to the top of the list so that keys can't all be locked up.

Edited by Nukey Shay
Link to comment
Share on other sites

Use of the seperate display now kills room zero and number token data out of the binary :) All the listed rooms go up a notch.

No ram spent...I just used the low bit of the attract mode timer to carry the state. Since the attract mode timer currently has a dozen or so minutes to tick off before colors shift, it's possible to add more states for additional non-game screens too. For that matter, the timer is not really needed at all...since playfield in the multicolor kernel can't use it (and neither can multicolored sprites). But it's still in place to shift colors for the background and monocolor kernel's walls when it times-out.

 

When displaying the alternate screen, the framecounter will be bumped to help reseed randomization a bit better.

 

 

I also added a couple of directives...RANDOM_XY which places objects anywhere on the screen in random games (instead of just at their preset game #2 X/Y locations), and MERGE_STICKS which allows you to use either stick to control the game (I thought I had done this already...must have forgotten about it).

Link to comment
Share on other sites

New directives added:

This is still very early (and not fully bugfixed)...but here's a sample of using miniquests.

 

I added new directives to display a game map that displays 6 icons (16*16 bitmaps). There's a swirl-shaped "portal" that sends you to this "map room" (NOTE: this does not use an actual room in the data tables). When you step into an icon with the small dot, you'll be sent to a part of the kingdom. The swirl will follow you to this area.

 

When you move from the map to an area, the program will revive any dragons and send all of them and the bat to that area at random rooms.

 

Currently, the room links are still unchanged...you don't need to use the swirl at all to finish the game. But the upshot is that room links can be altered so that there are a number of "mini-kingdoms" that do not link to each other...but require the map to move between them. In this way, the enemies don't have to plod though a huge number of rooms to be able to get at you...just the range that is selected for that area. Each one of these areas also uses it's own data tables instructing which enemies to revive and move, where the icon sends you, etc...and can even use seperate data for each of the game variations. It's possible to alter the routines slightly so that each area features it's own castles, etc. And since castle gates aren't changing states between visits to the map room, it follows that such gates do not need to be stored conventionally...but can be packed into a single byte of ram - unpacked when you visit that specific area. With packed castle gates that do not need checking in the main game, you could put a LOT of them in :D Now if there was only a way to save space with the keys :(

 

The number of icons is currently 6, but it can be pretty much however many you want (a subroutine is used to display each set). So the entire game can be broken down into smaller areas - with the dragons always nearby :)

You can carry objects from area to area...but you can't drop anything in the map room (because it's not really a room at all). If you reset out of the map room, objects (and the swirl) will be left at your last location in the game world, so be careful.

 

After using an additional bit to dictate when the map room is used, I was left with a spare game state...which can be used to display a seperate screen (such as after winning or being eaten).

 

The subroutine that scrambles NPC locations features a shortcut in the randomization routine that is so simple I'm kicking myself for not thinking of it before...just ADD the lower bounds (saving loads of VBLANK time). The routine that scrambles objects on startup is still using the old routine in the last bank...but this will be moved to the other kernel instead - that will free even more space to add additional enemy routines and data for rooms.

 

Anyway...to implement the NPC scramble, I had to reorganize the room layout in those tables (so that NPC's for game 1 won't be sent to a game #2/3-only screen). An unwinnable game #3 is still a possiblity in this test version. The swirl and destinations currently use the same values between game variations. Also, I burned 3 bytes of ram for the added swirl object...but it could be coded as a static object instead to save those 3 bytes.

Edited by Nukey Shay
Link to comment
Share on other sites

Castle gate states reduced to a single bit each. A seperate byte tracks which gate is opening or closing. That saved another byte of ram...and there's room to add up to 5 more castles without needing ram for gates themselves (tho you'll need to spend 3 bytes of ram for each new key added - just like any other movable object).

 

What this (currently) translates to is that the assembly could have 3 dragons and 5 keys added (in addition to the swirl object and everything else already in place)...and STILL have 4 bytes of ram to spare.

 

Because the "gate motion" variable only needs to keep track of a single gate at a time, this saved additional VBLANK time as well. I'm trying to figure out an easy means for the game to keep track of more than 8 castles without losing the motion state ability...if doors were to just "pop" open, it would be simple :(

 

The randomization loop has been moved to the game select kernel (using the speedier method mentioned earlier). There's a lotta free space in the last bank now for custom object & room data to be added.

 

New file up top.

Edited by Nukey Shay
Link to comment
Share on other sites

Yeah...but it would be nice to have the ability. Keys are kinda unnecessary after you've unlocked the single castle they belong to, but if each area had another castle of the same color...the quest could become pretty large (think generic keys & master keys).

 

 

Bad version posted - random games and continuing after being eaten didn't work...fixed up top.

Link to comment
Share on other sites

  • 2 weeks later...

Alternate version posted up top is intended for 16k or 32k. The modifications to that version saves an additional byte per NPC, throws in 3 more dragons and 5 more keys, and there's STILL 11 bytes of ram unused.

Sprites and room gfx in this alternate version exist in completely seperate banks to eliminate redundancy.

The extra keys don't belong to anything...I just activated them so they can be seen (to make them unavailable, just alter their starting room # to be invalid).

 

Monocolor playfields in this alternate work the same as they did in the 8k version. However, a seperate kernel to recolor lines is no longer required. Unfortunately, recoloring playfield lines cannot happen on lines that update gfx (yet)...and 1 scanline must also be used to cache the next playfield definition. For example, if your definition line counts off 8 2lk scanlines, you can recolor the line a maximum of 6 times.

 

To recolor the playfield scanlines, room data has been reorganized to set the scanline count first. Because this value is always 96 or less, the high bit is now used to signify that the byte value is to be used as the COLOR instead of a new definition line. So this is the format of room definitions:

      .byte LINES,PF0|RP|HIDE|LF|REV,PF1,PF2 ; 4 bytes of playfield gfx definition
     .byte (COLOR/2)|$80 ; following scanline recolor value(s) {optional}

 

The flash color is also available on recolored lines. To use it, enter $FF as the data byte instead of the above.

 

In this alternate version, page-crossing of playfield data is allowed if the definition line ends evenly on a page break. If there is an uneven number of bytes you want to skip, use recolor data bytes instead. In both cases, the gfx pointer will be adjusted automatically should a page be crossed :)

Link to comment
Share on other sites

New 16/32 version posted up top.

 

Some timer issues corrected, and an option to flicker decorative objects added. When this is used, items are no longer part of the game engine cache...but use a seperate one that only displays 1 frame out of 3 (see W.R.'s signature for an example). The advantage is that flickered objects do not interfere with existing collisions (so adding a couple of decorative objects will not make a dragon any more difficult to kill than it would be had the objects not have been there).

 

I also expanded the game a bit by adding an additional bat, a balloon (pick it up from the top to carry, from the side or bottom to ride), the large dot to pass left panels, and the 5 missing castles. Aside from the balloon and the map portal (which I still haven't implemented), the added stuff will not appear in levels 1-3. The castles are pretty much unused (this is still just a demo). The dragon revive code is also active for these higher levels...that's a pretty mean game.

Link to comment
Share on other sites

BTW the "wind" that blows the balloon around is controllable only a small amount. It's based on which direction the sword is facing. I was trying to figure out a limited means of control (such as what is present in Ultima, for example)...but came up short on how to accomplish that. I also need to figure out a means of carrying objects along with you when riding the balloon. Otherwise, it's just a novelty (tho might prove useful in certian situations...such as getting to the blue castle).

 

Recoloring playfields isn't all I'd hoped...banking to and from pretty much consumes all the cycle time available :( Still working on that, too (I really don't want to go back and have redundant sprite definitions in all banks again...it's just too wasteful and leaves little space for rooms).

Link to comment
Share on other sites

  • 1 year later...
  • 7 months later...

This game seriously ROCKS! I would like to see the difficulty setting where the bats don't resurrect the dragons tho, but quite honestly it's one of the best conversions I've seen!!!

 

Indeed! Sadly, it's been over a year since this topic was active. Nukey Shay has since sworn off Atari 2600 development and now works exclusively with Cracker Joe to complete the NES Game Maker.

Link to comment
Share on other sites

This isn't a game...it's a demo. The main problem of expanding Adventure is that it leads to far too much ground to cover (for both the player and the opposition), and can become tedious. Having "mini kingdoms" is my attempt at a solution. The portal object is only there to show it in action...but different methods could be used instead to jump between the separate "worlds". Each castle interior (for example) could be it's own individual sub-game - complete with enemies, doors to open, and an end goal. I guess the point was to illustrate that you don't need additional ram to accomplish such a task.

 

The demo hasn't been updated because I'm out of ideas for it.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...