From 5d4a70f81d1896ede119e0dfe42392c4506a2a34 Mon Sep 17 00:00:00 2001 From: schneefux Date: Fri, 15 Nov 2013 19:59:19 +0100 Subject: added comments --- Wolf3D.c | 47 +++++++++++++++++++--- calc.c | 4 ++ draw.c | 134 +++++++++++++++++++++++++++++++++++++++---------------------- engine.c | 86 ++++++++++++++++++++++++++++++--------- global.c | 13 ++++-- hardware.c | 12 ++++++ key.c | 6 +++ ki.c | 15 +++++++ mapgen.c | 28 ++++++++++++- menu.c | 2 + sprites.c | 4 ++ 11 files changed, 273 insertions(+), 78 deletions(-) diff --git a/Wolf3D.c b/Wolf3D.c index 22f790f..cf2b00f 100644 --- a/Wolf3D.c +++ b/Wolf3D.c @@ -15,17 +15,22 @@ void main(void) { + // strings for display char FPS[9]; char LIVE[13]; + // fps counter static int oldtime; static int maintimer = 0; + // every 100 ms, change contrast if(RTC_Elapsed_ms(maintimer, 100)) { + // this is a workaround, so that no extra timer is needed maintimer = RTC_GetTicks(); if(player.health <= 50) { + // health is low, warn player if(contrast > 10 || contrast < -10) { contradd *= -1; @@ -34,32 +39,37 @@ void main(void) set_contrast(168 + contrast); } + // remove status every 100 * 100 ms = 10 sec, IIRC if(statustimer++ == 100) { statustimer = 0; status = NULL; } + // a hit is shown with a backlight flash if(BacklightIsOn() && statustimer % 5 == 0) { + // turn backlight off after 100 ms * 5 = 500 ms BacklightOff(); } } + // check keyboard input move(); - if(output != 0) + if(output != 0) // output of move() { unsigned int time; - oldtime = RTC_GetTicks(); - clear_vram(); - cast(); + oldtime = RTC_GetTicks(); // init FPS counter + clear_vram(); // clear display + cast(); // render image - drawgun(); + drawgun(); // show gun - if(output == 2) + if(output == 2) // if the player moved fw/bw, the gun has to move { if(player.gunpos > 3 || player.gunpos < -3) { + // move gun from top to bottom and vice-versa if(player.gunpos > 3) player.gunpos = 3; @@ -68,21 +78,28 @@ void main(void) player.gunpos += gundir; } + // print FPS sprintf(&FPS, "fps:%2.2f", 1 / fps); PrintMini(0, 0, &FPS, MINI_OR); + // print health sprintf(&LIVE, "health:%4d", player.health); PrintMini(80, 0, &LIVE, MINI_OR); + // and a status message, if available if(status != NULL)PrintMini(0, 58, status, MINI_OR); + // update screen display_vram(); if(player.health <= 0) { + // game over exit = TRUE; } + // set kind of move (output from move()) to 0 again output = 0; + // re-calculate FPS fps = (((RTC_GetTicks() * 15.625 - oldtime * 15.625)) / 1000); } } @@ -90,8 +107,10 @@ void main(void) int AddIn_main(int isAppli, unsigned short OptionNum) { int c; + // get the pointer to vram vram = Disp_GetVRAMPtr(); + // if we ever got a new calc model, this would save us (hopefully) if(getCalc() == UNKNOWN) { clear_vram(); @@ -112,19 +131,26 @@ int AddIn_main(int isAppli, unsigned short OptionNum) GetKey(&c); } + // make it possible to start the game again after [Menu] APP_EnableRestart(); + // generate some tables for speed table(); + // seed rand() seedrandom(); + // if we want to have enemies, allocate and create them if(ENEMYCNT) { sprites = (struct st_sprite *) malloc(ENEMYCNT * sizeof(struct st_sprite)); + // these are debug checks; there should be enough memory if(sprites == NULL)error(); } + // spritecnt holds the number of all sprites; enemies, items and whatever else will come spritecnt = ENEMYCNT; + // set every enemy into the map for(c = 0; c < spritecnt; c++) { kisetpos(&sprites[c].x, &sprites[c].y); @@ -135,8 +161,10 @@ int AddIn_main(int isAppli, unsigned short OptionNum) sprites[c].effect = 50; } + // create a random maze maze(); + // init the player's values player.x = 1.5; player.y = 1.5; player.dirX = -1; @@ -148,20 +176,25 @@ int AddIn_main(int isAppli, unsigned short OptionNum) player.health = 500; contrast = 0; + // this timer handles the enemie's movement. KI is AI in German, I didn't want to rewrite everything :) Timer_Install(8, &timer, KISPEED); Timer_Start(8); exit = FALSE; + // main loop while(exit == FALSE) { main(); + // if player won if((int)player.x == MAPSIZE - 1 && (int)player.y == MAPSIZE - 1)break; } + // kill all timers, set contrast to default Timer_Uninstall(8); set_contrast(168); + // did he/she loose if(player.health > 0 && exit == FALSE) { clear_vram(); @@ -172,8 +205,10 @@ int AddIn_main(int isAppli, unsigned short OptionNum) display_vram(); Sleep(1000); } + // free memory to avoid system errors free(sprites); + // clear keyboard buffer, otherwise you could see the cursor move after exit Keyboard_ClrBuffer(); } diff --git a/calc.c b/calc.c index 51ef6e2..4b5be28 100644 --- a/calc.c +++ b/calc.c @@ -2,8 +2,10 @@ #include "calc.h" #include "syscalls.h" +// table that holds precalculated values for the floor and ceiling int TDist[64]; +// random number generator; could be improved static uint lastrandom = 0x123456; void seedrandom(void) @@ -17,6 +19,7 @@ unsigned int random() return (lastrandom >> 16); } +// inits constants for floor etc void table() { int x; @@ -26,6 +29,7 @@ void table() } } +// fills an array void fill(uint *ptr, uint element, uint arraysize) { for(;arraysize > 0; arraysize--, ptr++) diff --git a/draw.c b/draw.c index 0235165..0a0802b 100644 --- a/draw.c +++ b/draw.c @@ -1,3 +1,5 @@ +// Thanks to PierrotLL for MonochromeLib! I took some functions and modified them a bit. + #include "global.h" #include "draw.h" #include "sprites.h" @@ -5,8 +7,10 @@ #include "key.h" #include "syscalls.h" +// options, this can speed up the rendering int drawfloor = FALSE, drawheight = TRUE, drawtex = TRUE; +// fast drawing function for horizontal lines void horizontal(int y, int x1, int x2) { int checker, i; @@ -23,6 +27,7 @@ void horizontal(int y, int x1, int x2) else vram[(y<<4)+(x1>>3)] |= (255>>(x1%8 + 7-x2%8))<<(7-(x2&7)); } +// fills a box using horizontal void fillbox(int x1, int y1, int x2, int y2) { int i; @@ -42,11 +47,13 @@ void fillbox(int x1, int y1, int x2, int y2) horizontal(i, x1, x2); } +// a printmini in locate-like lines (1 to 7, but small chars) void locatePrintMini(int x, int y, const uchar *text) { PrintMini((x - 2) * 6, (y - 2) * 8, text, 0); } +// draws a generated map, only used in generation before the main game void drawgenmap() { int x, y; @@ -57,35 +64,42 @@ void drawgenmap() { if(map[x][y] == WALL || map[x][y] == CHECKED) { + // draws a filled box wherever a wall is or could be fillbox(x * sizex, y * sizey, (x + 1) * sizex, (y + 1) * sizey); } } } } +// draws the map in the main game, including items void showmap() { int x, y, exit = FALSE; - int windowx = player.x, windowy = player.x, zoom = 8; - const char plsprite = 0xA9; - int lastkey, thiskey = 0; + int windowx = player.x, windowy = player.x, zoom = 8; // variables for scrolling + const char plsprite = 0xA9; // player's icon + int lastkey, thiskey = 0; // hold the pressed keys for a better movement + do { - int skew = 64 / zoom; + int skew = 64 / zoom; // factor for zooming while(windowx + zoom * 2 >= MAPSIZE) { - windowx--; + windowx--; // if the window is outside of the map } + // clear display clear_vram(); + // draw all static blocks for(x = windowx; x < windowx + zoom * 2; x++) { for(y = windowy; y < windowy + zoom; y++) { + // draw every square that is in the bounds of the viewer if(map[x][y] != SPACE) { + // if there is something, draw it fillbox((x - windowx) * skew, (y - windowy) * skew, (x + 1 - windowx) * skew, (y + 1 - windowy) * skew); switch(map[x][y]) { @@ -97,11 +111,13 @@ void showmap() } else if(x == (int)player.x && y == (int)player.y) { + // the player gets a nice icon PrintMini((player.x - windowx) * skew + 1, (player.y - windowy) * skew, &plsprite, MINI_OVER); } } } + // draw sprites for(x = 0; x < spritecnt; x++) { if(sprites[x].x >= windowx && sprites[x].x < windowx + zoom * 2 && sprites[x].y >= windowy && sprites[x].y < windowy + zoom) @@ -109,17 +125,21 @@ void showmap() switch(sprites[x].type) { case TYPE_ENEMY: + // it's an enemy PrintMini((sprites[x].x - windowx) * skew, (sprites[x].y - windowy) * skew, "!", MINI_OVER); break; case TYPE_PACK: + // health pack PrintMini((sprites[x].x - windowx) * skew, (sprites[x].y - windowy) * skew, "+", MINI_OVER); break; } } } + // refresh display_vram(); + // emulate a GetKey-like speeding up on hold keyupdate(); if(lastkey != thiskey) @@ -133,7 +153,9 @@ void showmap() lastkey = thiskey; - if(keydown(KEY_CTRL_EXIT))exit = TRUE; + if(keydown(KEY_CTRL_EXIT)) exit = TRUE; // back to the game + + // move the window if(keydown(KEY_CTRL_UP) && windowy > 0) { windowy--; @@ -154,6 +176,8 @@ void showmap() windowx++; thiskey = KEY_CTRL_RIGHT; } + + // zoom in and out if(keydown(KEY_CHAR_PLUS) && zoom > 1) { zoom--; @@ -167,18 +191,22 @@ void showmap() }while(exit == FALSE); } +// draws the gun on the bottom of the screen void drawgun() { int i,u; const int y = 47 + player.gunpos; + // depending on the weapon, but both are 21 x 22 + // this could be improved, but it is ok like this for(i = 0; i < 21; i++) { for(u = 0; u < 22; u++) { if(y + u <= 64) { + // 0 = transparent, 1 = black, 2 = white switch(player.weapon) { case GUN: @@ -214,15 +242,20 @@ void drawgun() } } +// draw a vertical stripe using textures if wanted +// args: x coord, x in texture, lower side's y, upper side's y, type of sprite, color (inversed or not) +// if steps are given, use them; otherwise we get problems with the floor or ceiling void vertical(int x, int tex, int start, int end, int type, int color, float steps) { int y = start; int pos = 1 << 7, step; - + + // this fastens the progress uchar xbyte = x & 7; uchar shiftbyte = (128 >> xbyte); uchar *buffpos = (unsigned char*)(vram + (x >> 3)); - + + // do we need to draw textures? if(drawtex == FALSE && type == 1) { if(start > end) @@ -238,6 +271,7 @@ void vertical(int x, int tex, int start, int end, int type, int color, float ste pixel(x,start); } + // swap the end and start to draw from top down if(start > end) { int tmp = start; @@ -245,55 +279,59 @@ void vertical(int x, int tex, int start, int end, int type, int color, float ste end = tmp; } + // for every type of sprite use different textures switch(type) { - case 1 : - if(steps == 0) - step = (16 << 8) / (end - start); - else - step = (16.0 / steps) * 128.0; - - for(; y < end;pos += step, y++) - { - if(wall[color][pos >> 8][(int)(tex >> 2)] == 1) - (*(buffpos + (y << 4))) |= ((1 << 7) >> xbyte); - /*else - (*(buffpos + (y << 4))) &= ~((1 << 7) >> xbyte);*/ - } - break; + case WALL: + // bitshifts are _lots_ faster than floats! + if(steps == 0) + step = (16 << 8) / (end - start); + else + step = (16.0 / steps) * 128.0; - case 2 : - if(steps == 0) - step = (16 << 8) / (end - start); - else - step = (16.0 / steps) * 128.0; - - for(; y < end;pos += step, y ++) - { - (*(buffpos + (y << 4))) |= ((door[pos >> 8][(int)(tex >> 2)] << 7) >> xbyte); - } - break; + for(; y < end;pos += step, y++) + { + if(wall[color][pos >> 8][(int)(tex >> 2)] == 1) + (*(buffpos + (y << 4))) |= ((1 << 7) >> xbyte); + + /*else + (*(buffpos + (y << 4))) &= ~((1 << 7) >> xbyte);*/ + } + break; - case 3 : - if(steps == 0) - step = (8 << 8) / (end - start); - else - step = (8.0 / steps) * 128.0; - - for(; y < end;pos += step, y ++) - { - if(pack[pos >> 8][(int)(tex >> 3)] == 1) + case DOOR: + if(steps == 0) + step = (16 << 8) / (end - start); + else + step = (16.0 / steps) * 128.0; + + for(; y < end;pos += step, y ++) { - (*(buffpos + (y << 4))) |= shiftbyte; + (*(buffpos + (y << 4))) |= ((door[pos >> 8][(int)(tex >> 2)] << 7) >> xbyte); } + break; + + case 3 : + // this is a health packet + if(steps == 0) + step = (8 << 8) / (end - start); else + step = (8.0 / steps) * 128.0; + + for(; y < end;pos += step, y ++) { - if(pack[pos >> 8][(int)(tex >> 3)] == 2) + if(pack[pos >> 8][(int)(tex >> 3)] == 1) + { + (*(buffpos + (y << 4))) |= shiftbyte; + } + else { - (*(buffpos + (y << 4))) &= ( ~shiftbyte); - } + if(pack[pos >> 8][(int)(tex >> 3)] == 2) + { + (*(buffpos + (y << 4))) &= ( ~shiftbyte); + } + } } - } - break; + break; } } diff --git a/engine.c b/engine.c index 19a7cf9..8acd11a 100644 --- a/engine.c +++ b/engine.c @@ -11,6 +11,7 @@ float fps; +// swap two floats void swap(float *a, float *b) { float tmp = *a; @@ -18,6 +19,7 @@ void swap(float *a, float *b) *b = tmp; } +// sort algorithm for sprites void combSort(int* order, float* dist, int amount) { int gap = amount, i; @@ -43,17 +45,21 @@ void combSort(int* order, float* dist, int amount) #define PI 3.141592653589793238464 +// perform a shoot static void pshoot() { float xadd, yadd, x, y; int c; + // check for every sprite whether it is hit for(c = 0; c < spritecnt; c++) { + // but just enemies, packs shouldn't die if(sprites[c].type == TYPE_ENEMY) { - x = player.x; - y = player.y; + x = player.x; + y = player.y; + if(Abs(x - sprites[c].x) > Abs(y - sprites[c].y)) { xadd = sgn(sprites[c].x - x); @@ -65,8 +71,9 @@ static void pshoot() yadd = sgn(sprites[c].y - y); } - if(1/*TODOTODOTODOTODO*/) + if(1/*TODOTODOTODOTODO*/) // todo: implement something to check whether the player shoots in the right direction { + // very simple raycasting while(x < MAPSIZE && y < MAPSIZE && x >= 0 && y >= 0) { x += xadd; @@ -74,6 +81,7 @@ static void pshoot() if((int)y == (int)sprites[c].y && (int)x == (int)sprites[c].x) { + // if hit, reduce enemie's health or let it die sprites[c].effect -= 5; if(sprites[c].effect <= 0) { @@ -81,9 +89,11 @@ static void pshoot() sprites = (struct st_sprite *) realloc(sprites, spritecnt-- * sizeof(struct st_sprite)); if(sprites == NULL)error(); } + // we hit an enemy, go back to the game return; } + // if there is a wall, no chance, try again if(solids[(int)(x + 0.5)][(int)(y + 0.5)] == SOLID) { break; @@ -94,17 +104,22 @@ static void pshoot() } } +// this moves the player in the world void move() { float oldDirX, oldPlaneX, moveSpeed = fps * 1.25, rotSpeed = fps / 1.25; float newx = 0, newy = 0; + // update the key buffer keyupdate(); + + // I hope this is self-explaining if(keydown(KEY_CTRL_DOWN) || keydown(KEY_CTRL_UP) || keydown(KEY_CTRL_LEFT) || keydown(KEY_CTRL_RIGHT)) { if(keydown(KEY_CTRL_DOWN)) { newy = player.y - (player.dirY * moveSpeed); newx = player.x - (player.dirX * moveSpeed); + if(newx >= 0 && newx < MAPSIZE) if(solids[(int)newx][(int)player.y] != SOLID) { @@ -116,7 +131,7 @@ void move() { player.y = newy; } - output = 2; + output = 2; // 2 means the player moved, so the gun has to move } if(keydown(KEY_CTRL_UP)) { @@ -136,12 +151,15 @@ void move() } if(keydown(KEY_CTRL_RIGHT)) { + // rotate the plane oldDirX = player.dirX; player.dirX = player.dirX * cosf(-rotSpeed) - player.dirY * sinf(-rotSpeed); player.dirY = oldDirX * sinf(-rotSpeed) + player.dirY * cosf(-rotSpeed); oldPlaneX = player.planeX; player.planeX = player.planeX * cosf(-rotSpeed) - player.planeY * sinf(-rotSpeed); player.planeY = oldPlaneX * sinf(-rotSpeed) + player.planeY * cosf(-rotSpeed); + + // if the output is 2 (move gun), let it; ortherwise set to 1 (just update) output = (output < 2)?1:2; } if(keydown(KEY_CTRL_LEFT)) @@ -152,8 +170,11 @@ void move() oldPlaneX = player.planeX; player.planeX = player.planeX * cosf(rotSpeed) - player.planeY * sinf(rotSpeed); player.planeY = oldPlaneX * sinf(rotSpeed) + player.planeY * cosf(rotSpeed); + output = (output < 2)?1:2; } + + // if we hit a sprite if(solids[(int)newx][(int)newy] == SPRITE) { int c; @@ -161,14 +182,17 @@ void move() { if(sprites[c].type == TYPE_PACK && (int)sprites[c].x == (int)newx && (int)sprites[c].y == (int)newy) { + // cool, it is a pack solids[(int)newx][(int)newy] = UNSOLID; player.health += sprites[c].effect; + // delete it sprites[c] = sprites[spritecnt]; sprites = (struct st_sprite *) realloc(sprites, spritecnt-- * sizeof(struct st_sprite)); if(sprites == NULL)error(); output = 2; + // got it status = packmsg; statustimer = 0; break; @@ -180,6 +204,7 @@ void move() { if(keydown(KEY_CTRL_MENU)) { + // open game menu openmenu(); output = (output < 2)?1:2; return; @@ -188,24 +213,27 @@ void move() if(keydown(KEY_CTRL_SHIFT)) { - switch(player.weapon) - { - case GUN: - pshoot(); - break; - /*case KNIFE: - newy = player.y + player.dirY; - newx = player.x + player.dirX; - if(newx >= 0 && newx < MAPSIZE) - if(map[(int)(newx)][(int)(newy)] >= 10) - {enemies[map[(int)(newx)][(int)(newy)] - 10].health -= 15;} - break;*/ - } - - output = 2; + // fire! + switch(player.weapon) + { + case GUN: + // perhaps an enemy was hit? + pshoot(); + break; + /*case KNIFE: // todo: fix this for dynamical enemies + newy = player.y + player.dirY; + newx = player.x + player.dirX; + if(newx >= 0 && newx < MAPSIZE) + if(map[(int)(newx)][(int)(newy)] >= 10) + {enemies[map[(int)(newx)][(int)(newy)] - 10].health -= 15;} + break;*/ + } + + output = 2; } if(keydown(KEY_CTRL_ALPHA)) { + // alpha opens a door newy = player.y + player.dirY; newx = player.x + player.dirX; if(newx >= 0 && newx < MAPSIZE) @@ -213,6 +241,7 @@ void move() if(map[(int)(newx)][(int)(newy)] == DOOR) { map[(int)(newx)][(int)(newy)] = SPACE; + // now there is no wall any more, we can walk through solids[(int)newx][(int)newy] = UNSOLID; } } @@ -220,14 +249,18 @@ void move() } if(keydown(KEY_CTRL_OPTN)) { + // optn, change weapon player.weapon += 1; if(player.weapon == WEAPON_OVERFLOW) player.weapon = GUN; } } +// this is the "core", most important part +// rendering is done here void cast() { + // see Lode Vandevenne's tutorial for details float cameraX,rayDirX, rayDirY, sideDistX, sideDistY, deltaDistX, deltaDistY, perpWallDist, wallX, floorXWall, floorYWall, distWall; int mapX, mapY, lineHeight, hit, side, x, tex, y, black, floorTexX, floorTexY, actualheight, heightdiff; int stepX, drawStart, drawEnd, stepY; @@ -254,6 +287,7 @@ void cast() for(x = 0; x < 128; x++) { + // create a ray from player mapX = player.x; mapY = player.y; @@ -315,10 +349,12 @@ void cast() { if(heights[mapX][mapY] == 0 || drawheight == FALSE) { + // it is a normal wall or something hit = TRUE; } else { + // now it's going to be complicated, let's draw a wall with a different height than the others \o/ if (side == 0) perpWallDist = Abs((mapX - player.x + (1 - stepX) / 2) / rayDirX); else @@ -336,9 +372,11 @@ void cast() if(drawStart < 0) drawStart = 0; drawEnd = (actualheight == 0)?32 + (Abs((int)(64 / perpWallDist)) >> 1):actualheight; if(drawEnd >= 64) drawEnd = 63; - + + // draw the wall vertical(x, tex , drawStart, drawEnd, map[mapX][mapY], side, Abs((32 + (Abs((int)(64 / perpWallDist)) >> 1)) - (32 - (Abs((int)(64 / perpWallDist)) >> 1)))); + // now, the floor and the ceiling if(side == 0 && rayDirX > 0) { floorXWall = mapX; @@ -380,6 +418,7 @@ void cast() (*(vram + (y << 4) + (x >> 3))) |= (128 >> (x & 7)); } } + // continue casting, but draw it 'behind' the current wall actualheight = drawStart; } } @@ -387,6 +426,7 @@ void cast() if(hit == TRUE) { + // if we hit a wall or something, draw it if (side == 0) perpWallDist = Abs((mapX - player.x + (1 - stepX) / 2) / rayDirX); else @@ -407,8 +447,10 @@ void cast() drawEnd = (actualheight == 0)?(lineHeight >> 1) + 32:actualheight; if(drawEnd >= 64) drawEnd = 63; + // draw it to the display vertical(x, tex , drawStart, drawEnd, map[mapX][mapY], side, (actualheight > 0)?((lineHeight >> 1) + 32) - (32 - (lineHeight >> 1)):0); + // draw floor & ceiling if(drawfloor == TRUE) { if(side == 0 && rayDirX > 0) @@ -468,6 +510,7 @@ void cast() } } + // here something wants to be fixed... The sprites appear strange when there is a wall lower than the others #define uDiv 1 #define vDiv 1 #define vMove 0.0 @@ -524,6 +567,9 @@ void cast() free(spriteOrder); } + +// old casting algo, this is just a backup +// there is nothing else below, you can skip this /*void cast() { float cameraX,rayDirX, rayDirY, sideDistX, sideDistY, deltaDistX, deltaDistY, perpWallDist, wallX, floorXWall, floorYWall, distWall; diff --git a/global.c b/global.c index 4f9e618..ae06c9e 100644 --- a/global.c +++ b/global.c @@ -1,7 +1,9 @@ #include "global.h" #include "hardware.h" +// constants for the map overview const uint sizex = 128 / MAPSIZE, sizey = 64 / MAPSIZE; +// output by move() int output = 1; int contrast = 0; @@ -10,16 +12,19 @@ int contradd = 5; int gundir = 1; int exit = FALSE; +// demo mode for future use int demo = FALSE; +// holds the sprites struct st_sprite *sprites = NULL; +// the player's values struct st_player player; uint spritecnt = 0; const char *status = NULL; unsigned int statustimer = 0; -uint map[MAPSIZE][MAPSIZE] = {0};/* +uint map[MAPSIZE][MAPSIZE] = {0}; // this is now generated automatically/* { { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, { 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 0 , 1 }, @@ -43,7 +48,7 @@ uint map[MAPSIZE][MAPSIZE] = {0};/* { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, };*/ -int heights[MAPSIZE][MAPSIZE] = {0};/* +int heights[MAPSIZE][MAPSIZE] = {0}; // this, too. 0 means normal height, 32 is about half of the normal/* { { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 32 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, @@ -67,8 +72,10 @@ int heights[MAPSIZE][MAPSIZE] = {0};/* { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, };*/ -uint solids[MAPSIZE][MAPSIZE] = {0}; +uint solids[MAPSIZE][MAPSIZE] = {0}; // here you can check whether you can walk through something +// nice idea would be a hidden wall you can walk through to access a secret room... hmmm +// something happened that should not happen void error(void) { clear_vram(); diff --git a/hardware.c b/hardware.c index 846a390..9f56847 100644 --- a/hardware.c +++ b/hardware.c @@ -1,8 +1,15 @@ +// Thanks to SimonLothar, cfxm and all the other hackers! + #include "global.h" #include "hardware.h" +// here are some functions for direct hardware access +// they are splitted to support different calculators + char *vram, *vram2; +// backlight funcions: on, off, switch, check +// if it's unknown hardware we should do nothing void BacklightOn() { if(!IsEmulator) @@ -59,6 +66,7 @@ int BacklightIsOn() } } +// change contrast only for known calcs void set_contrast(int contrast) { if(!getCalc() == UNKNOWN && !IsEmulator) @@ -69,6 +77,7 @@ void set_contrast(int contrast) } } +// update the display, if secure; otherwise use syscalls (sloooow!) void display_vram() { if(getCalc() == UNKNOWN && !IsEmulator) @@ -92,6 +101,7 @@ void display_vram() } } +// clear video ram void clear_vram() { int i, end; @@ -108,6 +118,7 @@ void clear_vram() for(i=0 ; i> 4); } +// do I have to explain this? static void delay() { unsigned int i; for(i=0 ; i<5 ; i++); } +// fast function for SH3 static unsigned char CheckKeyRow(int code) { unsigned int result=0; @@ -64,6 +68,7 @@ static unsigned char CheckKeyRow(int code) return result; } +// update key buffer void keyupdate() { if(getCalc() == fx9860GII_2) @@ -72,6 +77,7 @@ void keyupdate() } } +// check for keypress, depending on the calculator int keydown(int code) { if(getCalc() != UNKNOWN) diff --git a/ki.c b/ki.c index 717ce98..fb89bf4 100644 --- a/ki.c +++ b/ki.c @@ -5,6 +5,10 @@ #include "mathf.h" +// here are the ai's functions +// todo: change the function's names + +// check if the player can be seen by the enemy static int kshoot(float x, float y) { float xadd, yadd; @@ -20,6 +24,7 @@ static int kshoot(float x, float y) yadd =sgn(player.y - y); } + // this is raycasting again while(x < MAPSIZE && y < MAPSIZE && x >= 0 && y >= 0) { if((int)y == (int)player.y && (int)x == (int)player.x) @@ -36,6 +41,7 @@ static int kshoot(float x, float y) return FALSE; } +// move them in a random direction static void kimove() { int c; @@ -45,14 +51,17 @@ static void kimove() { int fail[4] = {0}, success = FALSE; + // it _will_ move if(sprites[c].type == TYPE_ENEMY) { + // try until there is no possible direction left while(!(fail[0] == TRUE && fail[1] == TRUE && fail[2] == TRUE && fail[3] == TRUE) && success == FALSE) { float newx, newy; if(kshoot(sprites[c].x, sprites[c].y) == TRUE) { + // if the player is in sight (< 3 fields), go to him/her if(Abs((player.x) - sprites[c].x) > 3) { dirx = (player.x > sprites[c].x)?1:(player.x == sprites[c].x)?0:-1; @@ -74,6 +83,7 @@ static void kimove() } else { + // there is no player, move randomly uint num; do @@ -107,6 +117,7 @@ static void kimove() newx = sprites[c].x + dirx; newy = sprites[c].y + diry; + // move that stupid sprite if(newx < MAPSIZE && newx >= 0 && newy < MAPSIZE && newy >= 0) { if(solids[(int)newx][(int)newy] == UNSOLID) @@ -123,6 +134,8 @@ static void kimove() } } +// this is a kind of high-level kshoot +// it subtracts the health static void kishoot(void) { int c; @@ -143,6 +156,7 @@ static void kishoot(void) } } +// this is the timer that moves the ai void timer(void) { static int ki = 0; @@ -155,6 +169,7 @@ void timer(void) kishoot(); } +// set the new position in the map void kisetpos(float *x, float *y) { do diff --git a/mapgen.c b/mapgen.c index f18df4d..6b169c4 100644 --- a/mapgen.c +++ b/mapgen.c @@ -4,6 +4,9 @@ #include "hardware.h" #include "sprites.h" +// this code is a random map generator based on the kill and hunt algorithm + +// this counts unempty neighbours static int cntunvisit(union st_field cnt) { int c = 0; @@ -15,6 +18,7 @@ static int cntunvisit(union st_field cnt) return (c > 1)?c:0; } +// count empty ones, including ones that are outside which are counted as wall static int cntempty(int x, int y) { union st_field c; @@ -35,6 +39,7 @@ static int cntempty(int x, int y) return cnt; } +// count walls static int cntwall(int x, int y) { union st_field c; @@ -55,6 +60,7 @@ static int cntwall(int x, int y) return cnt; } +// return as st_field from map point static union st_field get(int x, int y) { union st_field c; @@ -69,6 +75,7 @@ static union st_field get(int x, int y) return c; } +// try to find a wall with unvisited neighbours static int hunt(int *x, int *y) { for(*x = 1; *x < MAPSIZE - 1; *x+=2) @@ -84,6 +91,7 @@ static int hunt(int *x, int *y) } } } + // if there is none, we can start the main game return FALSE; } @@ -94,6 +102,7 @@ static int kill(int *x, int *y, union st_field this) { if(cntunvisit(this) == 0)fail1 = fail2 = fail3 = fail4 = TRUE; + // try to 'digg' in random directions switch(random() % 4) { case 0: @@ -179,12 +188,15 @@ static int kill(int *x, int *y, union st_field this) if(fail1 == TRUE && fail2 == TRUE && fail3 == TRUE && fail4 == TRUE) { + // dead end, try to find a new starting point return hunt(x, y); } } + // no possible move left, let's go and kill some robots return FALSE; } +// see if we can walk through that maze static int solve() { int priotable[4]; @@ -193,6 +205,7 @@ static int solve() int deltax = 1, deltay = 0; int dir, dirx, diry; start: + // that's dirty, I know, but it works for(curx = 0; curx < MAPSIZE; curx++) { for(cury = 0; cury < MAPSIZE; cury++) @@ -236,6 +249,7 @@ start: dir = WEST; } + // this is called the right-hand method, I think switch(dir) { case NORTH: @@ -263,6 +277,7 @@ start: priotable[3] = EAST; } + // try again with left-hand :D for(dir = 0; dir < 4; dir++) { switch(priotable[dir]) @@ -294,12 +309,15 @@ start: } } + // we are at the start again? if(curx == 1 && cury == 1) { + // this maze has no exit, make another one return FALSE; } - if(IsEmulator()) + // debug only + if(IsEmulator) { clear_vram(); drawgenmap(); @@ -308,6 +326,7 @@ start: } } + // make changes permanent for(curx = 0; curx < MAPSIZE; curx++) { for(cury = 0; cury < MAPSIZE; cury++) @@ -325,6 +344,7 @@ start: } } + // create packs in dead-ends for(curx = 0; curx < MAPSIZE; curx++) { for(cury = 0; cury < MAPSIZE; cury++) @@ -348,6 +368,7 @@ start: } else if(map[curx][cury] == WALL) { + // reduce the height of low walls, this gives a nice effect if(cntwall(curx, cury) == 2) { heights[curx][cury] = 32; @@ -362,6 +383,7 @@ start: { if(map[curx][cury] == SPACE && cntwall(curx, cury) < 2) { + // it is easier with some doors that connect two floors int dx, dy, fail1, fail2, fail3, fail4; fail1 = fail2 = fail3 = fail4 = FALSE; @@ -395,13 +417,17 @@ start: return TRUE; } +// main loop void maze() { do { int x = 1, y = 1, exit = TRUE; + // create an empty map fill(&map, WALL, MAPSIZE * MAPSIZE); + + // render it until it is solvable while(exit == TRUE) { map[x][y] = SPACE; diff --git a/menu.c b/menu.c index a86fbdd..072ecb5 100644 --- a/menu.c +++ b/menu.c @@ -7,6 +7,8 @@ #include "stdio.h" +// in-game menu + void openmenu() { uchar text[30]; diff --git a/sprites.c b/sprites.c index 7baca5b..4b283b2 100644 --- a/sprites.c +++ b/sprites.c @@ -1,6 +1,10 @@ #include "global.h" #include "sprites.h" +// these are sprite constants +// 0 = white, 1 = black +// and for sprites, 0 is transparent and 2 white + const int wall[2][16][16] = { { { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, -- cgit v1.3.1