BUGS DEVELOPMENT : INTRODUCTION (3.6.94 at 16:16) ================================================= These notes have been started a little into the game, so some of the initial work will be skipped. The idea currently is to have an OS friendly version of the scrolling and graphics demo written under SNASM. The tools used are the Devpac 2 assembler from HiSoft, CygnusEd 2.12 and blink version 6.7. The initial OS friendly work was done on an A600 (Kickstart version 37.350, Workbench version 38.35, AmigaDOS version 2.1), and should soon migrate onto an A1200 with a big hard disk and loadsa memory. File Breakdown -------------- For a breakdown of the modules, see 'bug_files' in this directory. The file 'bugmap' contains a linker map of Bugs. Header Files ------------ Each module has its own header file in the include directory off the Bugs source directory. The header for a module is named identically to its source, but with the prefix 'bugs_' and the suffix '.i' in place of '.s'. So a module called 'mainloop.s' would have a header 'bugs_mainloop.i' in the include directory. There are two exceptions - the header files 'generic.i' and 'main.i'. These must be included into each source file before any other includes. Needless to say, if you wish to access data or call routines in one module from another, you'll have to include the called module's header into the calling module's source. To make data and labels available from a module to any other, place a list of the labels after an XDEF directive, following any includes and before the source proper starts. Create a header file for the module (named as above) and copy the XDEF statements into this (open both files with CED and use cut and paste is quick). Change the XDEFs in the header file to XREFs, and you're there. e.g. In the fictional module 'mainloop.s', EntryPoint is to be exported. So, in 'mainloop.s', there is the following statement :- xdef EntryPoint,... and in the header file 'bugs_mainloop.i' there will be :- xref EntryPoint,... More than one label can be placed in an XREF or XDEF. NEVER INCLUDE A MODULE'S HEADER FILE IN ITS OWN SOURCE - THIS WON'T WORK, and you don't need to. If you have equates that are needed in the module and elsewhere, put them in a separate file, INCLUDE that file into the module's source and also into the module's header file. Advantages of the Modular, Linked Approach ------------------------------------------ The break up of the source into multiple modules may sound daft compared to the single source, single object approach of SNASM and PDS. In this case, it has advantages. On an A600 or A1200, the processor doesn't match up to the speed of the average PC used for SNASM/PDS. The modular approach means only the modules that have changed need to be reassembled, rather than the whole lot. For a slower machine, this saves time. It also helps to make the code more logical, by allowing you to break it up into separate source files for separate bits. Make good use of this (see 'bug_files' for Bugs' file breakdown). Disadvantages of it ------------------- The assembly can be more complex. A MAKE utility is used to track files and only reassemble those whose source file date is more recent than the corresponding object file's date. This means writing a makefile for the project, covering the executable file and all object and source files. Bugs' makefile is in the Bugs directory, called 'makefile'. See 'make.doc' for documentation on the MAKE utility. A linker is required to put together the resulting object files into an executable. This requires a statement in the makefile, and a command file for the linker describing which files to link and various options. Bugs' link file is called 'buglink' in the Bugs directory. See 'blink.doc' for documentation on the linker BLINK. It can sometimes be tricky to find a label or routine - you can't just go to it as in SNASM/PDS. However, if your module breakdown is logical, it shouldn't really be a problem to select the right source file. Source File Starting Statements ------------------------------- Because of using modular development, each source file has to have two lines as its FIRST TWO. These are :- opt l+ idnt The first sets the assembler to output a linkable object file. In the section, should be replaced by a name for the module. This is for the linking and map file. Sections -------- Bugs code is split into several sections, identified by the SECTION statement. This takes the form SECTION , . The following table identifies the sections used :- -------------------------------------------------------------------------- BugsCode CODE Where ALL program code goes. BugData DATA Where all initialised data goes that does not have to be in Chip RAM. BugChip DATA_C Where all initialised Chip RAM data goes. BugBSS BSS Where all uninitialised data goes that does not have to be in Chip RAM. BugBSSChip BSS_C Where all uninitialised Chip RAM data goes. Before starting source to go in an area, you have to put the right SECTION statment into the source. So, the first section statement for a file is always SECTION BugCode,CODE for code, or data for purely data. Put the first section statement after the compulsory first two lines and before any header includes. Screen Handling and Scrolling ----------------------------- Screens and scrolling is done in a naughty fashion. The routine SetupScreen in 'hardware.s' accesses the global graphics data to determine the address of the initial view and copper list addresses. Then two bitmaps are set up for the screen, a custom copperlist initialised with the necessary screen physical parameters, and the main view is turned off by calling LoadView with a NULL pointer. Two WaitTOFs are called, then bitplane DMA turned off by DMACON. The copper registers are loaded with the custom copper list address, and copper/sprite/blitter priority/DMA enable are set in DMACON. The routine RestoreGameView does the last bit of screen activation. The routine FreeScreen calles RestoreOSView which puts back the OS view and copper list. This reloads the old view found in SetupScreen via LoadView, and points the copper register to the old copper list. Screen writing via the blitter is done directly through the blitter registers rather than OS calls. So Bugs has to 'own' the blitter in entireity when this happens. For the demo, OwnBlitter then WaitBlit are called before the main loop and any blitting. Getting Input ------------- This is done via the input.device, and is developing at the moment. The module 'inputdev.s' handles this by setting up the input.device to have two handlers, one called before Intuition, one after. The BeforeIntuition handler traps RAWMOUSE and RAWKEY events. The mouse coordinates are stored in InputX and InputY, the RAWKEY events set and clear bit flags in the key matrix InputKeyMatrix. The logical input module 'input.s' accesses this information to control the players' pointers. At the moment it just uses the key information in InputKeyMatrix, and reads the gameport hardware directly for mouse and joystick input. In the near future, both of these will be read via Amiga devices. Gameport 0 via the input.device, gameport 1 via the gameport.device. Exiting Bugs ------------ The main exit point is ExitProgram in 'main.s'. This calls various memory freeing routines and OS closedown stuff. The code is written in such a way that a closedown/free routine will NOT close/free stuff that has not been opened/allocated - pointers and handles are initially zero, and skipped for closing/freeing if still zero. The module 'memory.s' has memory handling routines. The two allocation routines are GetBlock and GetBlock2. GetBlock allocates only Chip RAM and clears it, GetBlock2 tries Fast RAM and only tries Chip RAM if there is not enough or no Fast RAM. The macro free_it in 'generic.i' frees an allocated block if its pointer is non-zero. Two parameters are passed - the first is the address of the block's pointer, the second is the block size (the address of a variable holding the size OR an immediate value preceeded by #). Level Data ---------- At the moment, there is only one set of test level data in different files. This will develop as the game develops. The module 'level.s' contains level loading and unloading code, and will contain the final versions of those routines and the key data to the level data (file names, offsets, etc). ONGOING DEVELOPMENT NOTES ========================= 6.4.94 ====== Experimented some more with the input.device. First of all, used the AfterCode handler to trap DISKINSERTED and DISKREMOVED events. All this seemed to produce were DISKREMOVED events. Also tried to use the RAWMOUSE InputX and InputY as mouse coordinates rather than reading the hardware directly. This didn't work - the mouse just homed back to (0, 0) - obviously the events were returning deltas rather than absolute coordinates. To make this work, just added ie_X and ie_Y to original mouse coordinates in the mouse structure. To try and trap DISKINSERTED events and convert the RAWMOUSE relative coords to absolute, I added code to setup, open and close an Intuition window on the WorkBench screen (see 'intui.s' in the Obsolete directory). This had the necessary IDCMP flags for absolute mouse coordinates, disk insert and remove, etc. Unfortunately, this made no difference. The RAWMOUSE events reached my code BEFORE Intuition, so no relative to absolute conversion took place. No DISKINSERTED messages arrived either, despite the handler being AFTER Intuition. Maybe this was because I was reading the input.device and not the IDCMP port. Also the Intuition window also caused the mouse to lock if a button was pressed. Included mouse button trapping code in BeforeCode handler (returned as RAWKEY information) - had no effect. Either it was ineffectual, or the handler's priority was such it was called before mouse button presses were added as RAWKEY events. The problem seems to be caused by the fact that if the hidden mouse pointer on the Workbench screen was not on the Intuition window (as is probably likely when moved around), pressing the button would select another window/process - the CLI or Workbench. Thus all input messages (mouse and keyboard) were no longer sent to my code, causing the mouse to lock (no relative coordinates sent) and the ESCape key getout to fail (no RAWKEY events). So, I have gone back to reading the gameport hardware directly for mouse, and using the input.device for keyboard only. This seems robust at the mo. It also makes the switch from mouse to joystick much easier on BOTH ports (otherwise I'd have code for the gameport for port 2 for both mouse and joystick, and code for the input.device on port 1 for both mouse and joystick). Back on to DISKINSERTED and DISKREMOVED messages. Just disk removal messages are useless. Some means of detecting disk presence, removal and insertion is necessary. Enter...the trackdisk.device. This seems to have facilities for checking if a disk is in a drive (TD_CHANGESTATE) and for adding an interrupt called on disk insertion/removal (TD_REMOVE and TD_ADDCHANGEINT/REMCHANGEINT). So, the code in 'trackdisk.s' sets up the trackdisk.device for EVERY drive present, checks if a disk is in each one and adds a change interrupt for each drive that maintains disk in/out flags set in the initial disk-in check. The code is OpenTrackDisk, CloseTrackDisk and DiskInDrive. This works - a little reporting routine in CloseTrackDisk checks the flag state of connected drives and prints 'in' or 'out' accordingly. The problem is that once the program exits, the normal OS disk change stuff no longer works - it reports no disks in any drives whatsoever. Inserted disks aren't read for volume info. The click-check still happens. The Advanced System Programmers Guide gets confused about this. It gives the impression that using TD_REMOVE is okay, while TD_ADD/REMCHANGEINT can be problematic, leaving the interrupts around. It even gives a sample disk editor that uses TD_REMOVE to install interrupt and remove. It could be that having multiple trackdisk.devices and interrupts could be causing problems. Try just the one? Or is it something left behind? Just using an rts for the interrupt rather than a disk presence check still produces the same problem, suggesting something up with the interrupt method rather than the interrupt code. Checking Abacus's Amiga Disk Drives Inside and Out provides no extra info. It gives some clues as to what is wrong with TD_ADD/REMCHANGEINT - something to do with a bug in TD_ADDCHANGEINT in regard to using an IORequest in place of an Interrupt structure. So, no help there. As this is the end of the day, I'll try again tomorrow. TTFN. 7.6.94 ====== Further attempts at fixing the trackdisk.device remove/insert interrupt have failed. It seems that once the interrupt is installed for the unit, it stays. Using the TD_REMOVE message with an IO_DATA field of zero just disables the interrupt altogether - it does not remove the previously installed one. As a result, the OS disk remove/insert interrupt goes for good, and the user interrupt stands a good chance of crashing the machine if left active after the program returns to the OS. So, the trackdisk stuff has been left out for the mo. Further development work will include use of the DiskInDrive routine for file loading and volume detection in the floppy version of the game (in a non-interrupt volum identification system, polling available disk drives). Alternatively, all disk IO could be done while an Intuition/graphics.library view (screen) is active, allowing switching back to the DOS view. What did work, however, was the conversion of the vertical split, two player mode. This went over quite easily, with extra code for the screen setup and screen toggling. The scroll code just needed uncommenting, and the panel changing code a little fixing and a call in the main loop. All that needs to be added and checked is the button graphics routines. That to be done tomorrow. The 'arguments.s' module had two switches defined : '-1' for single player (the default) and '-2' for the vertical split screen two player mode, making access to different scroll modes easy. 8.6.94 ====== Simply reinstated the RunButtons code for handling 32 colour button graphics and it worked! One problem did crop up with this vertical split mode - 4080 bytes is lost each time the program is run. Obviously, something is being allocated and not freed at the end. I'm looking into it. Easy solution - InitPanel3 (for the vertical split mode) doesn't preserve the sizes for the button tables and mask area. Just added three lines, and it was fixed. 'patterns.s' has been added, converted from the PC version. This contains the code for sprite movement - homing to a point, moving around obstacles, etc. Not much in it yet - I only started it this afternoon. 9.6.94 ====== Basic homing now works. MoveSprites in 'patterns.s' is the entrypoint - performs a loop of 50 sprites each time called, and branches via a jump table to pattern code, based on the value in each alienstat field. The basic homing code is in HomerPat - this performs two kinds of home - to a single point and to multiple points, up to five. The routines InitMove and CloseMove allocate the arrays for homing and behaviour. avoid_list points to a list of data for homing and moving around obstacles. home_list points to a list of data for homing (directions, differences, etc as for a two axis Bresenham's linedraw), and home_points points to a list of data for multiple point homing (five points per sprite). The structure definitions are in the source file, and also in the header file bugs_patterns.i At the moment, homing can be set up by writing directly into the structures and calling LineSetup and MoveSprites. The control system for selecting sprites and specifying their moves is to be written. 10.6.94 ======= Started work on the sprite selection code. Studied the PC version - driven by a routine called DO_BOX, a complicated thing involving many flags to handle the state of the pointer (box drawing, panel clicking, indicating movement destination, etc) I decided to implement this on the Amiga using a 'state machine' - the pointer has various modes or 'states' depending on what action is being performed, and can change from state to state. The basic model is :- Normal State <------ (pointer click) : (changes to) :=============> Panel State (if click in panel) : :=============> Scroll State (if click in scroll area) Depending on the type of click and where it occurs within the panel or scoll areas, switches are made to other states. Coding wise, a state corresponds to an entry in a jump table that branches to the routine to implement the state. All that is done is to call the main routine that gets the state and jumps to the corresponding code. Related to the concept of a finite state machine/automaton, but more concrete. Also vaguely related to the concept of methods in object oriented stuff. In this case, the states are :- Normal : await a click Panel : handle panel click. Triggers buttons, etc. Scroll : handle scroll click. Deals w. drag box until click release RadarScroll : reached from Panel State. Handles small map scroll. MsgBox : not yet implemented. For text boxes Order : not yet implemented. For order selection LeftDrag : not used. Redundant? (done by Scroll) RightDrag : not used. Redundant? Point : assign home point(s) for movement FmtionSel : formation selection (NYI) FmtionSetup : formation setupp (NYI) The basic states were successfully implemented, derived from the old non-state code. These were Normal, Panel, RadarScroll and the drag box code in Scroll 13.6.94 ======= Further work was done on the homing system. It was decided to rationalise the 'alien' structure so that the separate tables (for homing) were merged into one big alien structure - each alien contains its own homing data rather than in a separate table. This is to save a little time, code and effort - all the data can be accessed off one address register, rather than up to four or five. There is only ONE increment needed for loops, and the other registers are free. And there's only one to remember. The sprite selection code was extended to specifying homing destination points. Only single points have been done so far. This has extended the Scroll state to switch to the Point state if more than one sprite is selected using the left button drag box. The Point state has been added, based on the PC code, to track the mouse pointer via a line connecting the drag box centre to the mouse pointer position. When a click is made, the routine AssignPoint is called (again derived from the PC code) for that point, assigning the points to each selected sprite. The first home is set up, and the sprites put into homing pattern. This code will be extended to allow the right button to be used, specifying up to five home points. A further sprite/alien structure change has been used. A field called 'alieninvis' has been added - if this is non zero, the sprite is not drawn. For all other intents and purposes, it is still active, moving, selectable, etc. This is to allow easy flashing of sprites once selected. The rest of the code has been modified to suit. Originally the field 'aliendef' was going to be used to mark an inactive sprite by the value -1. This does not match the PC code, and so the inactive mark is given by an 'alienx' value of -1. 'aliendef' holds the animation number of the sprite. A bug exists with homing at the mo. If a position on the bottom left corner of a sprite is clicked to select it, then clicked again, the sprite will shoot off to the top left corner (probably at 0,0). Something in point calculation I think. The actual trigger could well just be the destination click, rather than the selection. I'll test it. It seems to be when the home destination is the same as the home start, rather than any position in the sprite. Maybe all that is required is a special check in InitPoint or the control code to prevent this. In InitPoint, the values could be set up to stop the home immediately. Also, the selection box code appears to allow selection of sprites OUTSIDE the box when it reaches its maximum size (160 x 160 pixels). I shall also have to look into this. Fixed the 0,0 problem - it skips the home if xdiff = ydiff = 0. The home selection stuff needs two things - first, the right button multiple home point code and equivalent code for CHECK_POINTS on the PC, which determines if any of the sprites will arrive in an illegal block (e.g. water) and prevents the destination click. Fixed the selection of sprites outside the maximum box size. It was simply the fact that the box size was calculated BEFORE the box was limited, and the box collision code used the unlimited size. I just moved the size calculation to after the limit code, and it was fixed. Whoopee. :-) 14.6.94 ======= Multiple point homing control was easily implemented, based on the PC code. This simply stores points in the player's 'points_hold' part of structure. Once five points are stored, the routine branches to '.all_done' which loops AssignPoint until all selected sprites have their homing data set up. The home tracking line code was revised to draw a line for each home point, starting at the selection box centre, passing through all the points assigned and with the final segment tracking the pointer. This is easily done - starting with (box_x1, box_y1) it uses all the points in 'points_hold' that have been assigned (count = 'which_points' field). The previous line's endpoint becomes the new line's startpoint. When the counter reaches -1, the pointer position is used as the endpoint. This pointer position is passed into the right click code as the point to assign if a right click is made. The left click code has been modified to set 'which_point' to zero, meaning only one point will be homed to. This prevents the problem of starting to assign points using the right, then swapping to the left - the sprite will home to the last point, then try to home to any others specified by the right, (0, 0) if there's no points, etc. Some line clipping bugs have occurred. In some cases, when screen coordinates are negative, the clip goes haywire, generating clipped coordinates in wild places. It can also lock in the clip loop. Examination of the clip code revealed that all multiplications and divides were unsigned - these have been changed to signed equivalents. The signed mod has fixed the wild results. Another mod for speed was done, changing the 'move.b d5,d6/and.b #???,d6' for segment checking to a 'btst' instruction (12 cycles down to 10 - only really a save for lots of line clips. Max saving could possibly be only 4-8 cycles per call). Another clip bug has occurred (possibly because of the btst mod). Left and right clip leaves crap in the blank area of screen underneath the hardware sprite panel. This could also be the result of the signed modification... Further investigation leads to suggest it is only the right clip, and not caused by the btst modification. Left crap could be cleared by the MaskScroll routine. The problem could be caused by the right clip limit. Currently at 256, while the visible screen area is only 232. The write area is 256, but the line draw stuff is offset by the scroll position... Tried smaller clip right limits (232, 240) but none worked - all clipped too early. Restored it to 256, and made the comparison blt rather than ble - this locked (continuous clip!). Then subtracted one from right limit only while line clipping - solved! Now it appears that the left button 'locks' sometimes before performing point assignment, leaving only the right button working. A click problem somewhere...seemingly solved by modifying the left click point assign to recognise any left click (single, double or quick) rather than just the single click. A CheckPoint routine has been written, based on the PC version. This was found to be producing odd results, because of a mix of coordinate systems. The alien coords were in world coords (top left of map is 256,256) while the pointer and box positions were in map coords (top left of map is 0,0). The pointer coord system was modified to be in world coords, set at the start of DoMouse. Correspondingly, box dragging, object selection, point assigning and home tracking line code were modified. The CheckPoint code was corrected for this, making it similar to the PC code. A range of blocks was defined as invalid for testing purposes. The map maximum sizes used for this check were max_xsize/ysize, which are actually a screen less in width (used for limiting the scroll). Two new variables were introduced into 'scroll.s' containing the map size in pixels specifically for this check - map_pix_x and map_pix_y. The CheckPoints routine now works, but not properly. It doesn't seem to be recognising all the expected invalid blocks, and those it does seem to be 13 pix higher and 13 pix to the right of where they should be. Meanwhile the homing and home line coords appear to be correct on screen; these are also derived from the pointer's world coordinates. 15.6.94 ======= I did some exploration of the behaviour of CheckPoints. What seems to happen is that the coordinates in CheckPoints refer to the left edge of the sprites (X) and the bottom edge (Y). The end position is determined relative to the centre point of the selection box, so the sprite will not necessarily arrive on the point indicated by the cursor (this is to keep the relative spacings of sprites when moving). This arrival point is what is used to check for invalid blocks, and can easily be offset from the position of the cursor, leading to the inaccuracy mentioed above (it also isn't always 13 pix on both axes). Further consideration is needed to decide what to do on this issue. Something to try would be to draw a line from each selected sprite to its true destination point to check it out. A decent demo has been requested from Darren for the CES in America. So, to provide this some example bug sprites were acquired from Paul McKee, grabbed and put in place of the pond test sprite. The code GetFace and GetQuadrant have had calls installed as per PC to check out sprite facing shown by the proper sprites - this works. Animation code for movement has been added, in the routine Animate (patterns.s), again from the PC. This performs a walking animation. The animation tables for this have been written, and the extra data needed for the extra sprite frames in 'sprites.s' has also been added (x offset, y offset, frame no, x & y size). This works okay. Just as an experiment, a 'return to home' function has been included, triggered by the button on the panel marked with an 'H'. This is in the routine HomeButton (input.s). It loops through a player's sprites, calculating their home position (y = 80, x = 192 + n * 32) and setting each up to home to that point. If a sprite is already there, it doesn't home. And that works, too. 16.6.94 ======= Added code to draw each selected sprite's home track line when assigning the first point. This indicated the accuracy of CheckPoints - it was reading the block correctly for the coordinate point of the sprite (bottom left corner). Fixed the problem where a click on a non-clickable block would hang around and be triggered when the cursor moved off the block - just a case of moving the non-clickable check to after the click check and post of 'wait for release' to input handler. Discovered the problem with the lower half of the pond - the block numbers in two's complement are negative (> 127) and the comparisons used are signed, so of course it doesn't work - silly boy! :-( A routine called SelectPointer has been added to 'input.s' to allow changing pointers to indicate different results. The call to CheckPoints in DMPoint in 'player.s' modifies the pointer using this code based on whether the block is clickable or non clickable. The CheckPoints routine in 'player.s' has been modified to use a table based approach - each block has an entry in the table. If this entry is zero, the block is clickable. If it is non-zero, the block isn't clickable. CheckPoints finds the block under a sprite's destination, checks its flag and returns click/nonclick accordingly. A possible development involves producing a utility to build the clickable table based on a point-and-click approach, with the capability to load multiple block screens (LBM, PCX etc) to build one table. 17.6.94 to 26.6.94 ================== Quite a lot has been done during this period that I didn't get round to updating this diary. Most of the time was spent on coding and debugging the move-around system. This has involved :- - CheckPoints revision to look into collision map, and disallows clicks on blocks with the value 'noclick_ma' - CheckCollMap has been converted from the PC version to check for move-around collisions and to setup the move-around. - HugBlockPat has been converted from the PC code to perform the actual move-around - ResumeHomePat has also been converted as a part of this code. - HomerPat has acquired a 'noclick_ma' collision detection to prevent sprites accidentally moving into a solid area. The move-around system functions thus : Each obstacle is surrounded by a border of move around blocks interspersed with special m-a blocks and filled with noclick_ma blocks. The routine CheckCollMap (called in HomerPat) checks to see if a sprite has come into collision with this m-a block border. If not, it carries on with the home. If it has, the routine traces around the border, noting the positions of special m-a blocks. It then determines the special block closest to the home destination, and sets this as the target of the move-around. It then selects the direction around the obstacle which provides the shortest route to the target. The sprite then enters the HugBlockPat, which moves the sprite 16 pixels in the current direction, then looks around for the next adjacent m-a block and sets up a move to it. If the m-a block border is continuous, this results in a move to the m-a target. A bug in the drag box has also been fixed - when reaching the maximum size in either axis, that axis' position would stick at the maximum. Once at the m-a target, a home is set up from where the sprite currently is to the original destination, and the sprite enters ResumeHomePat. ResumeHomePat performs a home WITHOUT CheckCollMap calls for 'no_detect_del' pixels of move. This helps to prevent the sprite getting stuck in the current m-a border (it would move a pixel away from the current m-a target, then realise it was on a m-a border and go through the whole process again, getting stuck where it was). With checks and tweaks and corrections, this works. There are a few problems, however. Sometimes, a sprite can double back on itself, returning to the m-a target before rehoming properly to its destination. This is because the CheckCollMap 'grace' period expires before the sprite leaves the m-a border. This is a product of the distance calculation used to find the closest special m-a block, the sprite's position relative to the m-a block border, and the destination point. The effect has been reduced by increasing the collision grace period and improving the distance calculation. 27.6.94 - 29.6.94 ================= A test map has been concocted by the PC programmer, Finlay Munro. These two days were spent incorporating the map, blocks and overlays into the Amiga code. This involved. - Producing 32 colour tiles and overlays - Installing these into the tUME map - Modifying the tUME grabber to output word maps properly, and put out overlay layer as a word map also - Modifying the Amiga program to display a word map, and also to use a word map when initialising the overlays. - Overlay identification mod to Amiga code to identify and set up overlays from blocks in the overlay layer. The code was tried without altering the small panel maps - this caused a crash as the new map was larger, causing plotting off the edge of the bitmaps. A bug in the sprite/overlay sort was found. The tallest overlay (windmill, at 88 pixels) did not clip on the bottom properly - it would move so far off, then vanish at about 40 pixels up. This was found to be in the sort code in CopyToList. The height of the overlay was such that it put the overlay base off the bottom of the sort table, causing the overlay to vanish before it had moved off the bottom of the screen. The solution was to lengthen the sort table to accommodate this. The panel maps were created by using tUME to scale them down and export the rooms to LBMs. Four colour versions were created using colour reduction in BitEdit for Windows. These maps need to be grabbed and dropped into the code. But there is a problem - size. The 4 times smaller map is 320 x 320 pixels - a grand total of 64000 bytes for the Amiga data, and 102400 bytes for the PC data. GRABBER.EXE on PC doesn't handle source LBMs greater than 64K in size. Modifications to GRABBER.EXE were begun to split larger LBMs into up to four 64K segments. With the modified GRABBER.EXE, the panel maps were turned into bitmaps and easily integrated into the Amiga code. There was a big problem - not enough memory. The preshifted maps took up over 256K, leaving only 64K free once the editor and unnecessary drivers were removed. This needs sorting. The vertical split two player mode was tried with the 32 colour panel maps. This needed some adjusting in the scroll code to cope with the word map, but once tweaked worked fine. 30.6.94 ======= The memory shortage with the preshifted panel maps has been addresses by trying a non-shifted version. This means the panel map jumps in steps of 8 pixels. Saves a good deal of memory, but at the cost of some loss in smoothness. Other alternatives include a flip-scroll technique, scan-line doubling, software/blitter shift during plot, 4 preshifts (scroll in 2 pixel steps), only preshift current scale and store preshifts on disk and only load current scale. These have a tradeoff between processor time and memory saved - the more memory saved means greater processor time (e.g. in current scale preshifts and software/blitter shift during plot). The other alternative is to use a bottom or top of screen panel (like the v.split two player) in the screen bitmap and expand the size of the scroll area. The existing panel code could be adapted, preshifts disposed of altogether. The screen hardware could be adjusted to match the width of the side panel scroll, meaning no extra plot time for scroll and saving more RAM with a smaller screen bitmap. Two bugs with the new map and overlays have appeared. The first is a missing section of stem on a flower overlay at the bottom right, the second is a stray blue block beneath a pool with a blue gnome. Investigation of the first has proved fruitless. The map seems fine, the code fine. A little experimentation with the map (adding stems to left and right) seemed to fix the problem - on removing these additions, the missing stem stayed put. CASE FIXED! (Something wrong with the map?) The second proved to be simple - it was the last block in the set, and the block offset table ran only up to the last but one. This was because the code to determine the number of blocks was using the number of the last block for this, not no. of last block plus one. CASE SOLVED! 1.7.94 ====== Today, the text or message box code was written. This is contained in a new code module, 'messages.s', which consists of two routines and the text box data. The main routine is Messages, which is called from each player's BuildPlayer code. This handles display and animation of a message box - shrinking and expanding the box, drawing text, supplying coordinates for selection. The other routine is InitMessage, used to set up a message box. This is called with a0->message structure, and a5->current player. The player's message box variables are initialised for the message box, and his/her pointer is set to 'pm_msgbox' mode, after saving the original pointer mode in the mode_save field. The message box structure is as follows :- Byte 0 - Message box width in pixels Byte 1 - Message box height in pixels Byte 2 + Message box lines A message box line format is :- Byte 0 - Type flag. 0 = end of lines, 1 = centred line, 2 = left justified line Byte 1 - Select value. -1 = not selectable, otherwise number for command Byte 2 - Y coordinate relative to box top Byte 3 - Select flag. -1 if mouse over this, 0 if not Byte 4 + ASCIIZ string for line Bytes 2 is set by Messages during the plotting of the message box. Byte 3 is set by the pointer mode routine DMMsgBox when the pointer is over that line and the line is selectable (-1 < Byte 1 < 128). The rest of message box handling is in DMMsgBox ('player.s'). This stalls the mouse (ignores any clicks) while the message box is expanding up, determines which (if any) line the mouse is over, and responds to a left click (right clicks are ignored). If a left click is made, the field message_select contains a pointer to the selected message box line. The select value (Byte 1) can be extracted, and should be used as an index (*4) into a jump table to the corresponding routine. At the moment, select value 9 is for a normal exit back to the original pointer mode, which is the default for all selections. This would need to be different for the formation selection cancel - any selected sprites would need deselecting to stop them flashing (parse selected list). Message boxes appear centred on the play area. 4.7.94 ====== Finished off the message box code. This is now debugged, and linked into the code properly for testing. A left double click on a sprite brings up the identification box, a click on the disk button brings up the load/save box, a right drag over sprites brings up the formations box and a click on the next page button brings up a game stats box. The PC code for formations was studied prior to conversion. It was found that this code was based on squares rather than true circular rotations. As the player moves the mouse around, the tracking formation lines move around the square's boundary. As the mouse gets further from the source point, the square gets larger. The formations are based on lines - the formation set up code creates these lines under player control, then strings the selected sprite along the lines making up the formation. The message box selection commands have been rationalised into labels of the format MBX_[name], and a proper branch table installed in DMMsgBox code for the pointer's message box mode. 5.7.94 ====== Amiga formation coding begun. Routines to select formations were set up as command triggered routines from the message box code. These simply set the formation number, set up a few necessary variables and put the pointer into formation setup mode. The pointer formation setup mode has also been coded. This consists of the homing track line draw code (a line for each sprite) together with special routines converted from the PC code to draw the formation structure lines, and set up the line coordinates for the formations proper. This is done for the formations Wedge, Wall, Pincer and Decoy (DoWedge, DoWall, DoPincer and DoDecoy). Next to go in is the click recognition proper and formation point assigning. 6.7.94 ====== After studying the PC versions, the routines DoFormation and AssignLine were converted to the Amiga. These are the workhorse routines of the formation code, actually setting up the homing points for the formations. Bits of code in AssignPoint and HomerPat that had been left out were put (they are connected with formations). The click recognition code in formation point assigning was written, basically calling AssignPoint (which would fall through to DoFormation/AssignLine) with the users click point. Unfortunately, after all this, a mysterious crash occurred everytime when clicking to set up a formation (formation point assign mode). Various attempts to debug this only succeeded in ascertaining that the crash was in AssignLine. Probabilities included pointer corruption and running off the end of the selected sprite list. 7.7.94 ====== The crash was solved early in the morning. It was caused by two calls to AssignLine for four-line formations which weren't using the proper number of sprites assigned, leading to the routine running off the end of the selected sprite list and picking up garbage pointers. This let through various other bugs - Wall and Wedge formations didn't work properly, drawing the select box not from the top left led to the formation construction line positioning (and hence formation positioning) to be out of place and less than one sprite on a formation line segment would lead to a crash (fall off list end). In addition, later sprites in the formation would ignore their formation positions, and just home to the destination (selected sprite counter reaching zero before line assign counter). The construction line positioning bug was caused by the centre of the box being calculated before its coordinates were normalised to the top left (i.e. swapping x/y pairs so [box_x1,box_y1] is the top left, [box_x2,box_y2] the bottom right). The incorrect formation positions for Wall and Wedge are probably to do with the DoWall and DoWedge routines setting things up incorrectly - this is being looked into. And it proved to be the case - checking against the PC code and correcting discrepancies solved the problem. Tweaks to AssignLine and counter handling fixed the crash when there was fewer than one bug per formation line segment. The method used on the PC for determining the points along the formation line to place sprites involved iterating DoPoint several times through a loop (7 or 12 times in AssignLine, 40 times in DoPincer and 160 times in DoDecoy) - this is time consuming on the Amiga (best time for a DoPoint call is 130 cycles, plus looping overhead). An alternative macro was coded and debugged that performs the same function but by calculation using a multiply, a divide and a modulo in around 550 cycles. This is faster for four or more best case calls to DoPoint, and was put into DoPincer, DoDecoy and an adapted version in AssignLine. 8.7.94 ====== Another formation bug, that when a bug in formation or moving to formation hits a move-around border it may stop for good, has appeared. This has been isolated to code in the PC that actually performs a check for an m-a border and then stops the sprite. This is being looked into. Collision checking against the opponent player has been installed into HomerPat, from the PC code. This checks first in the X move to see if there has been a collision, then in the Y. If a collision happens in either, the move in that axis is stopped and any formation membership cancelled. Another bug was isolated, again to do with formations. Clicking on an unimplemented formation or the CANCEL option in the formation message box led to a strange effect on following movements. A sprite would not move when set up with a home point by mouse - it would stay flashing, and only move on selecting the next sprite by mouse. This was because the doing_formation file was not cleared by selecting these options - this has been corrected. To test the player vs player collision detection, it was switched so a sprite checks against its own side. This caused problems with the current start positions - they all seem to be in collision, and won't move at all from the start. This is under investigation. The size of sprites used in DoBoxCollide and CheckWhatOn has been modified to get the width and height from the sprite graphics data via the animation table where_anim and the animation data. This is to match the PC code, particularly for linked sprites and overlays. The size information stored in animation data has now been removed 11.7.94 to 13.7.94 ================== The collision checking bug has been fixed - each sprite did not skip checking against itself, so ALWAYS found a collision. Once this skip was in place, it worked fine. So, the checking has been switched back to check against the other side. Once this was fixed, the map handling strategy was decided. This involves merging multiple screens of tiles from the artist into one large 'metatileset' for a given level of twelve battles, and setting up the maps and their data so that only the tiles used are loaded. A PC utility, BIGMAP was written to handle building the metatileset and the map data, giving both PC and Amiga format output. This was completed on 13.7.94 14.7.94 ======= The Amiga code for reading map and tile data output from BIGMAP was written into 'LoadLevel' in level.s. This reads in the map and collision map and a translation table from BIGMAP which lists the tiles to load from the metatileset. These are loaded in consecutively to Chip RAM, and then the map addresses these. And it works! Futher development will involve the use of the translation table and the metatable (tUME tile number to metatile number) to facilitate identification of overlay base blocks and for animating and changing blocks. The overlay handling code has been revised to deal with overlay identification from the base layer map (background graphics). This involved setting up a table (overlay_base) identifying the metatile numbers of overlay base blocks, space for the corresponding map tile number and the number of the overlay link structure. This table is parsed and the translation table and metatable mentioned above is used to convert the metatile numbers into map numbers. The overlay list is then constructed as before, but searching for the map numbers put into 'overlay_base', inserting the corresponding overlay numbers and coordinates. Overlay size has been removed from the overlay structure. CopyToList has been modified to provide linked overlays - making one large overlay out of several different bitmaps offset from the base position. The table 'where_ovl' is a list of pointers to overlay link structures that define how the overlays are made up (in sprites.s). The overlay number put into the overlay list as described above is an index into 'where_ovl'. CopyToList locates the overlay link data via 'where_ovl', and loops for each linked bitmap, calculating its true X and Y position, sorting it into 'sprite_order' based on the ORIGINAL Y of the overlay (to ensure they are all plotted at the same time). This is similar to the PC COPY_TO_LISTS code, which performs this kind of link for both sprites and overlays (which are regarded as one). On the Amiga, they are separated for historical reasons, and also because at the mo sprites do not appear to need linking in the same fashion (though this might change with end of level bosses). Sprites will require linking for shadows, multi-segment vehicles and visible vehicle loads and crews, but this should be on the sprite level rather than the frame level (though for tanks with visible crew heads the overlay type of link could be used - one set of link info for empty tanks, one for player 1 bug in tank, and one for player 2 bug in tank - keeps them separate and easy to identify, while only needing bitmaps for the tank and heads for each side which are already required). 15.7.94 ======= A bug in CopyToList cropped up in the Y clipping - the windmill overlay clipped off the bottom too early. No amount of extending the size of 'sprite_order' affected this - unusually, because this kind of bug is often caused by a tall sprite's base Y being off the end of the sort table. It was actually dead simple - the code extracting width and height information from the overlay graphic data was putting them into the wrong registers, so swapping width and height for the clip code. CASE SOLVED! While considering what a change to an X centred sprite coordinate system, it was noticed that between CopyToList and PlotSprites the clipping was effectively being done twice. CopyToList extracts the size of images to be plotted and checks the image bounds against the screen clip region - any completely outside are excluded. PlotSprites performs the same check in a different way which also encompasses the necessary calculations for partially clipping an image on screen. The system has been revised (for both sprites and overlays) so that CopyToList does all the work - convert world coords to screen coords, apply axis offsets and animation offsets, calculate both complete off-screen clip and partial clipping, and put any fully or partially on screen images into the 'print_list' together with all the necessary values for plotting and clipping. After a little effort, this worked fine. So now all PlotSprites does is to parse 'print_list', extract the necessary variables, find the bitmaps and masks, feed this all into setting up the blitter, and trigger it off. 18.7.94 ======= A message box has been created to represent order selection in the same format as for the PC version (which uses the radar area on the panel). This has been worked into the point selection code AFTER selecting sprites by dragging with the left button, and between formation selection and formation setup. At the mo, the orders do nothing - the hooks are just there and working. The PC computer player code was printed out and studied, and the basics set up - 'computer.s' and its makefile entries. The top level entrypoints and header file entries have been set up. 19.7.94 ======= First stage of PC computer player code conversion done - extra fields for alien_list1, all the routines coded into 'computer.s', space for bullets in alien_list1 and other adjustments to code to accomodate these changes. Awaiting some sprite setup stuff to test and debug. 20.7.94 ======= Set up a few computer sprites in a parallel row to the player. Also set up each side to have 24 sprites, and noticed an immediate slowdown in sprite behaviour, but not in screen and panel update. This is because of the MoveSprites routine only doing fifty at a go. This has been modified to do the lot for now. The right most sprite also locked up the program when entering the move-around-block border surrounding a small puddle on the right hand side. This was traced to the move-around collision code, but nothing was apparently wrong. Checking the map revealed the problem - there were no special 'move-away' blocks in the border. Put some in, regrabbed the map and CASE SOLVED! The actual rough flow of the computer player code was studied - starts with a LogicType of Nothing (0), leading straight to HomeToShootDistance, then via OuterControl to various random stuff. Cut the number of computer player sprites to one, and ran with all the computer player code in place - the sprite did nothing! Attempted to force just random home - still did nowt. Forced the destination coords to (256,256). Still nothing. Gave up in disgust. 21.7.94 ======= Solved the stuck bug - the collision check code in HomerPat wasn't working to select the human players side - was just selecting the computer player, and of course finding a collision between a sprite and itself. Now that is fixed, the sprite happily homes to both the forced coords and random generated coords. It appeared that the random coords ALWAYS produced the same value when the program was first run - no wonder, as the seed was always zero. Code was added to load the seed from the VHPOSR hardware register early on, when it could be any value. Having removed all test stuff, the code was run again to check computer player behaviour. This time the sprite homed to the top left, kept going up a little when stuck against the map edge, then indulged in random moves a little after getting stuck. At this stage, any human player attempt to draw a drag box locked the program. With border-change investigation, this was found to be in DoBoxCollide. Much scratching of head later, no cause could be found - the lock up didn't seem possible in the normal code, suggesting some data or code corruption. Without a debugger, not easy to find. So, decided to change tack. Spent some time considering and making notes on performance improvement techniques - running the scroll and button down animations in interrupts. Returned to the lock up bug, but still no joy by 5.15 pm. 22.7.94 ======= Further investigation (by trying each LogicType on its own and disabling OuterControl) indicated that the problem occurred after running ClosestAwayHome. In fact, it turned out to be the call within this to CheckForClosest that caused the problem. Some shoring up by using 'alienenable' checks was added, but this didn't solve it. The distance calculation was checked and honed, but no change. Then a typo was spotted - the code stored a0 into start_of_1player instead of loading start_of_1player to a0 - thus corrupting the pointer used by other code and possibly corrupting data elsewhere. Once corrected, this worked fine. The sprite's behaviour seems a bit random, but is aiming for people, moving around obstacles, changing behaviour, etc. During the investigation, the separate logic types seemed to work (SingleHome homes to a tagged sprite, RandomHome all over the place, HomeToShootDistance to tagged sprite). Once corrected, ClosestAwayHome also worked, with the sprite moving away from the closest player sprite. Work was begun on studying and converting the sprite family code from the PC. This involves more detailed sprite loading and setup (via LoadSpriteList and FreeSpriteList), family structures, pointers to these stored in the animation info (what 'which_anim' entries point to), and modifications to CopyToList and PlotSprites. CopyToList accesses the family pointer from an animation entry, and gets the frame and mask table pointers for the family. This is stored in the plot list entry for PlotSprites to use. PlotSprites now extracts the frame and mask table pointers put into the plot list entries by CopyToList, rather than coding them into the loop. As a simple test of CopyToList and PlotSprites, an example family was hard coded to use the existing sprite and mask data - this worked. Next step was to implement LoadSpriteList and FreeSpriteList and test. 25.7.94 ======= By the morning, this family code was completed. With a little tweaking and a bug in FreeSpriteList, it works. The collision routines DoBoxCollide and CheckWhatOn needed altering to use the family pointer as they access sprite size from the graphic data via the frame table. Some work was done on looking into variable speeds of movement over different background blocks - currently the PC uses the block number a sprite is over to access a table of speeds. This is impracticable without some layer of translation on the Amiga, with its .TRT table defining only which blocks are used, and the map being numbered in those terms. Either translation needs doing, or speed blocks could be added to the collision layer (possible clashes with other blocks) or to their own map layer (requires extension to grabber). The latter two also need PC consultation. A new map was installed - the official first level so far. This required the necessary grabbing and reduced map generation and bolted in fairly painlessly. Except for the fact that with some clear blocks, tUME put in a null block IN THE TILESETS and renumbered accordingly - this didn't work for BIGMAP output. Also, null skip on BIGMAP output knackered the overlay block base detection - there is either a bug or a layer of translation (via. .TRT file) missing. For the mo, this has been disabled - it would only save disk space as the game only loads the blocks used in the current map. Collision detection has been extended by adding the CheckCollide2 routine - similar to CheckCollide, but for coordinates specified with Y being the top of the box, rather than the bottom. 26.7.94 ======= Work was begun on the conversion of the new PC computer player code, stage by stage. This was interrupted by the suggestion of working up a demo front end as per the script. This was studied and notes made, and the basic screen setup code installed. While doing this, it was noticed that the memory heap lost 8 bytes each time Bugs was run. Obviously, this needed to be sorted before continuing. Investigations began by eliminating the new front end screen setup code, and removing other bits (overlays, shrunk map and sprites). With no luck whatsoever. 27.7.94 - 30.7.94 ================= Began a systematic check of all possible allocations and deallocations with the debugger. Discovered that the overlay area size was two bytes on free than allocation - fixed this. No change. Discovered that the size of alien list allocation was 2 bytes more than deallocation - fixed this, and the 8 byte loss stopped! Back to the front end. The various sub-systems for the front end were designed and coded. First the pointer setup and interrupt stuff, then the 16x16 multi-colour character plot, then pointer display. Following this came the preshifted sprite parallax layer, initially just the basic four sprites with vertical repetition and preshift, then a copper list to repeat the sprites across the full width of the screen. The screen setup was revised to create a double height (512 lines) screen, and scrolling code installed to move this vertically (between the two visible half-areas) - the idea being to draw the next menu in the area off screen, and scroll this on. The copper list was revised so as to be constructed from the code head, tail and two templates for the sprite repetition row. The original took up around 25K when fully in source code - this was reduced to under 1K in the object, expanded to the full size when run, and freed once over. 1.8.94 ====== The screen and click structures were defined, and code to construct a screen from the data and then scroll it on was written. Click identification was added, with two bouncing arrows pointing to the current option under the pointer (if any), and using a click value as a jump table index when the pointer button was pressed. The current menus and clicks from the PC version were converted into the screen and click structures, and the code debugged. Voila, version 1 of the front end. There is a slight lag between clicking on an item and the next screen scrolling in. This is due to two factors :- - Eight frames taken to clear the draw screen - Between nine and twelve frames taken to draw text The first happens so as to keep the parallax running at 50 frames - the screen is just cleared in chunks. This was initially written as a 'move.l' clear, then revised to a 'movem.l' clear doing 32 bytes at a time. This was recoded to use the blitter (not actually much different to the movem), and improved to four frames, (exploiting the semi-parallel operation of the blitter, even in nasty mode). A minor improvement. Other possible improvements include ensuring a line IS drawn each time (i.e. keep looping on blanks until end of list or non-blank), or revising the system to clear and draw into the area just off screen while the scroll is happening (direction dependent; e.g. clear next 16 pixel strip in ahead of scroll, write in line there if there is one). 2.8.94 ====== The scroll and screen building system has been rewritten as suggested above - the scroll is set up to erase and print a new 16 pixel high line each frame in the area just about to be scrolled on next frame. This results in a much more immediate reaction to a player's click, while still keeping the parallax at 50 frames. There is no delay at all between a click and the scroll starting. This involves building a table with an entry for each character row (16 pixels) which either points to the text data for that row, or is null. Variables are set up to point to this table, the screen destination address and the character row to update (positions depend on direction of scroll). Each frame, the next row is cleared using the blitter, its entry from the table is read and the text pointed to is justified and plotted (if there is any). This was found to have speed problems - kept dropping into two frames. The screen, data and plotting were cut to four bitplanes (sixteen colours) - this still occurred. The problem was in a wait for vertical position - the comparison used was signed (blt) rather than unsigned (bls). Now it works within a frame, scrolling, selecting and updating. This is still in sixteen colours, and should remain so. Futher work was begun on finishing the computer player code upgrade - the routines 'UnTargetAll' (UNTAG_ALL) and 'StoreCollPoints' (STORE_COLL_POINTS) have been added. 3.8.94 ====== The remainder of the update to computer player code was completed during the course of the day, and testing begun. All possible changes were identified first, and then performed as one on the code. This highlighted several problems. Firstly, one sprite got stuck moving around a flower, which didn't happen on the PC. Careful study and comparison of the two move-around blocks of code (CheckCollMap, SetDir, SetDir2, CheckIfColl and HugBlockPat) revealed discrepancies and the Amiga code was adjusted to match the PC. This solved most of the problems with the move-around, but the two versions behaved slightly differently. It seemed the Amiga version more accurately picked the move-away block closer to the destination than the PC code, despite being seemingly identical. 4.8.94 ====== The level script was found not to match the PC properly - some delays were too short. This was corrected. The first computer player sprite got stuck after performing its first move to the top left of the map. This was identified to be a typo in ComputerLogic - the check for a circling sprite was comparing the aliendef field with #13, not the alienstat field with #13. This solved the problem. The Amiga sprites also seem to move around alot more than the PC once into their 'random' mode (i.e. no more script left). This could possibly be discrepancies in the logic code (which would require careful rechecking), or possibly the random number generator. This was found to have some differences from the PC version - the PC shifts are arithmetic (preserve sign) whereas logical shifts were used on the Amiga (ignore sign). This has been corrected, leading to...no difference. It could also be timing - with things happening slower and at slightly different times on the Amiga (e.g. caused by move-around differences), the random values got out could be different. Studying the PC code revealed that the sprites enter HomeToShootDistance once their script has run out - this expects a target in 'sprite_tagged' field, which will be zero. On the PC, this is an offset, so the target will be sprite zero (the mouse pointer). On the Amiga, this is a pointer, so the target will be taken as the data in a sprite structure at ADDRESS 0! Understandably, this is not likely to match the PC, and would mean different initial behaviour. This does not explain the more lively behaviour of the Amiga sprites. However, they do have a problem aiming at targets. As do the PC ones. Several bugs with bullets were discovered and fixed. The setup loop did not increase the pointer, which was then used to set the start address of the player sprites, not reserving the first forty for bullets. Therefore the code had difficulty finding free bullet sprites and interfered with player sprites. The bullet fire code, InitABullet (computer.s), was also bugged - it was putting the Y of the firing sprite into the bullet X, rather than its Y. Once these were fixed, bullets were seen. But it did seem that only one bug was doing the firing. The PC also seemed to show this, but later other sprites were seen to fire also. Further observation of the Amiga showed that more than one enemy bug did the firing. The map and radar routines were modified to exclude the bullet sprites and also any disabled bug sprites (alienenable field = 0). The sprite setup code in 'main.s' has been modified to set the X of the sprite after the last set up to -1, marking the list end before the true end in memory. The bullet pattern code calls DoPoint three times for a bullet move, yet only decrements home_length by one. This means the bullet goes three times further than the distance to the target. By modifying it to decrement home_length by 3, the bullets stop at the target. 5.8.94 to 11.8.94 ================= Not spent on Bugs 12.8.94 ======= A list of alterations to Bugs was provided by Darren, which has been used to improve the PC version. Some of these can be coded now on the Amiga. The screen box on the mini map has been removed. The click-on scroll for this map has been altered to make the whole area active, to freeze the mouse pointer and to make the map scroll at the rate of mouse movement (i.e. link scroll directly to the map). Another message box has been added, triggered by the previous page button. Message boxes have been altered to appear instantaneously, and to zoom out once clicked on. The Home button code has been revised to send the players sprites back to their original positions in the 'p1_pos' array, instead of calculating the positions along a line. A simple graphic for the circler object has been knocked up, and added to the grab list. Such a sprite has been added to each side, and the circular motion pattern has been coded as per PC. 15.8.94 ======= The front end has been more realistically linked into the game - you can properly exit to DOS and properly start the game. Only the one player game starts up, with the correct side selected. A revised memory allocation system has been introduced, to deal with out of memory errors properly. All allocations have been routed through GetBlock and GetBlock2 (memory.s), which maintain a list of the currently allocated blocks and their sizes. Deallocation is now done through FreeBlock (with the 'free_it' macro altered accordingly), which removes deallocated blocks from this list. A third routine, TidyMemory (memory.s) has been added, which goes through the list freeing any allocated blocks. This is called at the end of the program (after ExitProgram) to remove any left over allocated blocks. 18.8.94 ======= The new PC demo and code has arrived, so Bugs resumes its ever onward march towards the PC version... The scrolling control has been revised to match the Dune II style control on the PC. When the cursor has been moved to the edges of the display window, it changes into an arrow pointing in the direction of scroll at that edge or corner. When the left button is pressed, the display will scroll in that direction. This is done in a new routine 'DriveScroll' (player.s), a generic routine for either player that is called in 'DoMouse' (player.s) after checking for the pointer in the panel. Some of the pointer mode code has had to be modified to detect if the pointer is within the scroll zone (flag 'ptr_in_scroll.b' is non-zero). This includes DMNormal, DMPoint (point assigning), DMRadarScroll (scrolling by small map), DMScroll (box dragging) and DMFmtionSetup (formation line dragging). 19.8.94 ======= Variable speed blocks have been introduced. This has involved adding code to the map grabber BigMap on the PC, adding a TileAttributes section to the script file to build a table of speed values for the metatileset. The level loading code then builds a unique table of speeds for the metatiles the given level uses, which is utilised in the movement code to speed up or slow down sprites, depending on the background block they are over. This has brought to light two problems with the PC version - firstly, sprites moving faster than normal overshoot their target - they move more pixels, but their home_lengths only go down by one each time. Also, formations have to move at the speed of their SLOWEST members - this does not happen on home to single point, or on the first home of a multiple point move. Both seem to be present in the PC code too, though this cannot be tested - there is only one speed (normal) on the PC version. For the time being, the Amiga map used has been altered to only have one speed for ALL blocks. 20.8.94 to 2.9.94 ================= Over this period of time, not much has changed in Bugs - I've been waiting for an updated PC version. However, I have done some investigation into interrupt driven scrolling, in terms of the method to use and what modifications this would entail, and some experiments in timing for the extra blocks to plot and the memory consumed by extra screen RAM. It is practical, but would ideally require a couple of weeks to get working properly - is this worth it for a game of this type. 5.9.94 to 6.9.94 ================ At last - a new PC demo and source to work from. This has introduced a little more of the gameplay, and revised the player's interaction with the game. Firstly, the orders message box is no longer used - player movement is simply done by selecting a sprite or sprites, and just allocating one or more home points as before. The sprites set off straight away. This involved commenting out the dialogue calls in the relevant bits of the DoMouse routine (player.s). Secondly, the attacking system has been revised. This has meant adding some new sprite fields (see below), two behaviour patterns (attack and follow), and alterations to the computer player code. The new fields are :- NAME SIZE USE -------------------------------------------------------------------------- sprite_routine byte NZ (usually 2) indicates a highlighted sprite sprite_intensity byte Frame count for highlight alien_attacked long Pointer to sprite to attack alien_stamina word Hit points for this sprite follow_sprite long Pointer to sprite to follow which_follow_offset byte Offset for positioning with many attackers The attack pattern, AttackPat, is the new behaviour for performing an actual attack. This makes the attacker face its target, and then calls AttackSprite (patterns.s) to perform the action. AttackSprite makes sure the target is alive, then if close enough, will shoot bullets at the target at a semi-random rate. The bullets are fired by the InitABullet2 routine (patterns.s) - an extension of the old InitABullet (computer.s) which checks the side firing and allocates the bullet accordingly. The original InitABullet has been removed. Bullets now include collision detection with the corresponding enemy side (in BulletPat). If they hit, a call is made to DoHit, which decrements the target's alien_stamina field, and removes the target (making it dead) when its stamina goes negative. A dead sprite has an alienstat field of zero, and an alienenable field of zero. StillPat has acquired code to decrement the sprite's sprite_intensity field to handle flashing properly. It also contains some guarding code - if an enemy sprite comes within a certain distance, the current sprite will locate it and attack it via AttackPat. FollowPat is a pattern for human player sprites - once the human has selected an enemy target for one or more sprites, these sprites home to the target using FollowPat to track it until they reach attacking distance, whereupon they switch to AttackPat. If the target dies in the meantime, the attackers return to StillPat. The computer logic code has been updated to take account of the new attacking method. The ControlType table has been extended for AttackPat and FollowPat (both have NULL entries), BranchLogic has been changed to match the PC, and the random limit in the Nothing logic type has been set to 500 instead of 5. ProtectBase1 has been altered to return a computer sprite to StillPat once the danger to its base is passed (i.e. attackers all dead or run away). ProtectBase2 has a modified 'close' distance. SingleHome has been heavily modified. It properly handles lack of target, dead target, and switching to AttackPat when close to target. New target selection via GetClosestPl1 is correct, too. HomeToShootDistance has a check to skip out if no target, or if target has died. It has also lost its call to InitABullet. Finally, GetClosestPl1 has been rewritten properly - the distance estimation is more accurate, and selection of the smallest distance properly checked. A random element has been introduced to allow several sprites to select the same target. The other big modification has been in human player control. When assigning a home point with the left mouse button on top of an enemy, that enemy becomes a target, and the selected sprites home to it via FollowPat. This is handled via a routine called ClickOnEnemy (player.s), that performs a collision detect against all enemies with the mouse pointer. If one is found, it is briefly highlighted via sprite_routine/intensity, and each of the selected attacking sprites is given the target to follow (offset byte depending on number of attackers into which_follow_offset, address of target sprite in follow_sprite, alienstat set to FollowPat value). This provides the human player with an attack mechanism. Finally, the sundries. Sprite plotting has been altered to handle highlighted sprite (plotted using mask as image rather than bitmap, leading to all planes set). This involves CopyToList identifying a highlighted sprite, and setting up its plot list entry with the frame table pointer being set to point at the mask table instead of the frame table. The sprite width_in_words is now included in the plot list structure (spr_wiw), not read from the sprite structure. A routine called InitMenStart (level.s) has been added (from the PC version) to position player sprites in a circle around the base (rotating a radius via the sine/cosine tables). Stamina is temporarily given to sprites via TempGiveStam (sprites.s), again from the PC. This gives each sprite a stamina of 15. It is called in LoadLevel (level.s). The message box system has been modified to handle insertion of stamina into the sprite info box. Each message box has a code at the start indicating an initialisation routine to call, or zero for no initialisation. Initialisation routine 1 is the sprite stats setup - it pokes the sprite stamina into the text for the sprite stats message box.