An exciting survival game with random terrain by Jonne
Dependencies: PokittoLib
Fork of AnimationTest by
main.cpp
- Committer:
- Pokitto
- Date:
- 2018-05-02
- Revision:
- 9:e92847eb42bf
- Parent:
- 8:809b1982b4ae
File content as of revision 9:e92847eb42bf:
#include "Pokitto.h" #include "Pixonia.h" #include "Synth.h" Pokitto::Core gb; #define YOFF 4 #define XOFF 8 #define WORLDSIZE 50 #define TIMEINCREMENT 16 #define SUBDIVS 4 #define XSPEED 2<<4//2 #define YSPEED 1<<4//1 #define PILLARHEIGHT 2 #define GROUNDLIFT 1 #define MAXSTEP 2 #define MAXWOLFSTEP 3 #define WOLFENERGY 0x26F #define MONSTERMORNING 75 #define MONSTERNIGHT 130 //#define DEBUG #define MAXELEVATIONDIFF 1 #define DIGMAX 2 #define MAXHUMANS 10 #define MAXWOLVES 10 #define TREESNROCKS 1 #define HUTPROB 0x01 #define STONEPROB 0x24 #define TREEPROB 0x30 #define GOLDPROB 0x08 //was 7 #define MAXGOLD 50 #define GOLDMULT 3 #define WOLFMULT 1 #define MAPMULT 10 #define GLIMMERPROB 0x20 #define WOLFPROB 0x2000 #define DIR_NE 0 #define DIR_E 1 #define DIR_SE 2 #define DIR_S 3 #define DIR_SW 4 #define DIR_W 5 #define DIR_NW 6 #define DIR_N 7 #define TER_UNDEFINED 0 #define TER_WATER 31 #define TER_PLAIN 1 #define TER_HUT 2 #define TER_TREE 3 #define TER_STONE 4 #define TER_BUMP_NW 5 #define TER_BUMP_SE 6 #define TER_BUMP_NE 7 #define TER_BUMP_SW 8 #define TER_BUMP_N 9 #define TER_BUMP_S 10 #define TER_BUMP_E 11 #define TER_BUMP_W 12 #define TER_GOLD 13 #define TER_ROCK 14 #define TER_BEACHSW 29 #define TER_BEACHSE 30 enum walkDir { NE, SE, SW, NW }; enum humanTasks { IDLE, CHOPPING, RAISING, LOWERING, PLANTING, MOVING, HUTBUILDING }; enum AImodes { HOMING, INTERCEPT, CHASE, TURNCW, GOTO }; enum Gamestates { TITLE, NEXTLEVEL, INTRO, GAME, GAMEOVER, LEVELPASSED }; Gamestates gamestate = TITLE; int gamelevel=1; uint16_t worldsize=10; int32_t wx=-8,wy=0,cx=10,cy=10; uint16_t prevtile=0, playertile=0, focustile=0, centertile=0,oldcenter, tween_palette[16], golds=0, playergolds=0; uint16_t timeofday=0; //value>>8 0 is full daytime, 127 is full night uint8_t wave=0, oldtime=0,wolvestick=0,watertick=0; int8_t wading=1; bool focusing=false; bool inHut = false; int16_t tweenfactor=0,numwolves=0; /** function declarations **/ bool raiseTile(uint16_t); bool lowerTile(uint16_t); bool caught=false; int8_t getTileHeightToTile(uint16_t, uint16_t); uint8_t digCount=0, monsterdrain=1; uint16_t workingOnTile=0; struct coords { int16_t x; int16_t y; }; struct creature { int16_t energy; bool visible; walkDir facing; uint8_t animframe; uint16_t tile; coords position; coords goingto; AImodes ai; }; creature humans[MAXHUMANS]; creature werewolves[MAXWOLVES]; coords player,oldplayer,focus,goldnugget; uint8_t oldplayercount=0, goldnuggetcount; uint8_t world[WORLDSIZE*WORLDSIZE]; int getTileHeight(uint16_t i) { return (world[i]>>5); } int getTileType(uint16_t i) { return (world[i]&0x1F); } void setTileHeight(uint16_t i, int8_t h) { world[i] &= 0x1F; //save tile type, wipe height bits world[i] |= (h<<5); //store height in highest 3 bits } void setTileType(uint16_t i, uint8_t t) { world[i] &= 0xE0; // wipe bottom 5 bits (tile type) world[i] |= (t&0x1F); // set bottom 5 bits to type } uint16_t tileFromCoords (int16_t x,int16_t y) { if (x<0) x=0; if (y<0) y=0; uint16_t tile = (x/SUBDIVS)+(y/SUBDIVS)*gamelevel*MAPMULT; return tile; } coords tileToScreenXY (uint16_t tile) { coords s; uint16_t x = tile % worldsize; uint16_t y = tile / worldsize; s.y = y*YOFF+wy+(3+x)*YOFF+2+getTileHeight(tile); s.x = x*XOFF+wx+2*XOFF+2; return s; } uint16_t screenToTile (int16_t x, int16_t y) { /* tile 0 is at wx,wy in screen space */ int16_t distx = x-wx; int16_t disty = y-wy; uint16_t tilesx,tilesy,tx,ty; if (distx>0) { // point is to the right of 0 tile tilesx = distx/XOFF; //number of tiles moved right, XOFF = half width of tile tilesy = disty/YOFF; //num tiles downwards tx = tilesx + tilesy; // this actually gives on an isometric grid, the x row of tiles ! } else { // point is to the left of 0 tile distx = -distx; tilesx = distx/XOFF; //number of tiles moved right tilesy = disty/YOFF; //num tiles downwards } /* calculate how many tiles fit in between */ int32_t tilex = (x - wx - 2 - XOFF)/XOFF; int32_t tiley = (y-wy-2); tiley -=(3+tilex)*YOFF; tiley /= YOFF; return tilex+tiley*worldsize; } uint16_t worldToTile (uint16_t x, uint16_t y) { return (x/SUBDIVS)+(y/SUBDIVS)*worldsize; } coords worldToScreen(uint16_t x, uint16_t y) { uint16_t scry =(wy+y/SUBDIVS*4)+(x/SUBDIVS+1)*YOFF; uint16_t scrx = wx+(x/SUBDIVS+2)*XOFF-y/SUBDIVS*8; int16_t oy,ox; int16_t offsety,offsetx; offsety = y%SUBDIVS; offsetx = x%SUBDIVS; oy = -offsetx*YOFF/SUBDIVS - offsety*YOFF/SUBDIVS; ox = offsetx*XOFF/SUBDIVS - offsety*8/SUBDIVS; coords t; t.x = scrx+ox; t.y = scry-oy; return t; } bool onScreen(coords p) { coords t = worldToScreen(p.x,p.y); if (t.x>=0 && t.x<110 && t.y > 0 && t.y <88) return true; return false; } bool focusOnTile(uint16_t t) { if (!focusing || t!= focustile) { focusing = true; focustile = t; focus.x = t % worldsize; focus.y = t / worldsize; } uint16_t currentfocus = centertile;//screenToTile(55,44); if (currentfocus > focustile-3 && currentfocus <focustile+3) { focusing = false; return true; } int16_t x = currentfocus % worldsize; int16_t y = currentfocus / worldsize; int16_t dx = x - focus.x; int16_t dy = y - focus.y; if (dx<0) dx = -dx; if (dy<0) dy = -dy; if (dx+dy>20) dx = XSPEED*8; else if (dx+dy>5) dx = XSPEED*2; else dx=XSPEED; if (x<focus.x) wx-=dx; else if (x>focus.x) wx += dx; if (y<focus.y) wy-= dx; else if (y>focus.y) wy+= dx; return false; /*if (gb.buttons.upBtn()) { wy+=YSPEED;wx+=XSPEED;} if (gb.buttons.downBtn()) {wy-=YSPEED;wx-=XSPEED;} if (gb.buttons.leftBtn()) {wy-=YSPEED;wx+=XSPEED;} if (gb.buttons.rightBtn()) {wy+=YSPEED;wx-=XSPEED;}*/ } void drawToTile(uint16_t tile, const uint8_t* bitmap, int16_t offsetx, int16_t offsety, uint8_t flip) { uint16_t tilex,tiley; tiley = tile/worldsize; tilex = tile%worldsize; uint16_t scry=(wy+tiley*4)+(tilex+1)*YOFF; uint16_t scrx=wx+(tilex+2)*XOFF-tiley*8; int16_t oy,ox; oy = -offsetx*YOFF/SUBDIVS - offsety*YOFF/SUBDIVS+4; ox = offsetx*XOFF/SUBDIVS - offsety*8/SUBDIVS-3; int8_t t=0; if (!wading) t=-random(10); gb.display.drawBitmap(scrx+ox+t,scry-(getTileHeight(tile)<<1)-oy+t,bitmap,0,flip); } bool canMoveTo(uint16_t i) { if (getTileHeightToTile(i,prevtile)>MAXSTEP) return false; if (getTileType(i)==TER_HUT && humans[0].facing != NE ) return false; if (getTileType(prevtile)==TER_HUT && humans[0].facing != SW ) return false; if (getTileType(i)==TER_TREE) return false; //if (getTileType(i)==TER_WATER) return false; if (getTileType(i)==TER_STONE) return false; return true; } bool canWWMoveFromTo(uint16_t i,uint16_t j) { if (getTileHeightToTile(j,i)>MAXWOLFSTEP) return false; if (getTileType(j)==TER_HUT) return false; //if (getTileType(i)==TER_WATER) return false; //if (getTileType(i)==TER_STONE) return false; return true; } int8_t getTileDX(uint16_t i) { int8_t h_this = getTileHeight(i); uint16_t y = i / worldsize; uint16_t x = i % worldsize; int8_t h_prev = h_this, h_next=h_this ;// assume flat in case we are at the edge if (x>0) h_prev = getTileHeight(i-1); if (x<worldsize-1) h_next = getTileHeight(i+1); if (h_prev>h_next) return -1; //sloping down towards east else if (h_prev<h_next) return 1; // sloping down towards west return 0; // this axis is flat } int8_t getTileDY(uint16_t i) { int8_t h_this = getTileHeight(i); uint16_t y = i / worldsize; uint16_t x = i % worldsize; int8_t h_prev = h_this, h_next=h_this ;// assume flat in case we are at the edge if (y>0) h_next = getTileHeight(i-worldsize); if (y<worldsize-1) h_prev = getTileHeight(i+worldsize); if (h_prev<h_next) return 1; //rising up towards ne else if (h_prev>h_next) return -1; // sloping down towards ne (yes, this axis is mirrored) return 0; // this axis is flat } int8_t getTileHeightToTile(uint16_t a, uint16_t b) { int8_t c = getTileHeight(a); int8_t d = getTileHeight(b); return c-d; } uint8_t getTileSlope(uint16_t index) { int8_t dx=0,dy=0; dx=getTileDX(index); dy=getTileDY(index); switch (dy) { case 0: if (dx==0) return TER_PLAIN; else if (dx>0) return TER_BUMP_NW; return TER_BUMP_SE; break; case 1: if (dx==0) return TER_BUMP_SW; else if (dx>0) return TER_BUMP_W; return TER_BUMP_S; break; case -1: if (dx==0) return TER_BUMP_NE; else if (dx>0) return TER_BUMP_N; return TER_BUMP_E; break; } } void setSlopeAutomatic(uint16_t t) { uint8_t e = getTileType(t); // currently existing tile if (e<5 || e>12 && e != TER_PLAIN) return; // only change terrain formation tiles, not content uint8_t slope = getTileSlope(t); setTileType(t,slope); } bool recursiveGroundRaise(uint16_t tile) { uint16_t target=tile; if (tile>worldsize) { // Top row if (tile%worldsize) { target = target - worldsize - 1; //N tile if (getTileHeightToTile(target,tile)<-MAXELEVATIONDIFF) raiseTile(target); // recursive function, calls back to itself } target++; // NE tile if (getTileHeightToTile(target,tile)<-MAXELEVATIONDIFF) raiseTile(target); if (tile%worldsize<worldsize-1) { target++; // E tile if (getTileHeightToTile(target,tile)<-MAXELEVATIONDIFF) raiseTile(target); } } // Middle row if (tile%worldsize>0) { target = tile - 1; // NW tile if (getTileHeightToTile(target,tile)<-MAXELEVATIONDIFF) raiseTile(target); } if (tile%worldsize<worldsize-1) { target+=2; //SE tile if (getTileHeightToTile(target,tile)<-MAXELEVATIONDIFF) raiseTile(target); } // Bottom row if (tile<worldsize*worldsize-worldsize) { if (tile%worldsize>0) { target = tile + worldsize -1; // W tile if (getTileHeightToTile(target,tile)<-MAXELEVATIONDIFF) raiseTile(target); } target++; // SW tile if (getTileHeightToTile(target,tile)<-MAXELEVATIONDIFF) raiseTile(target); if (tile<worldsize*worldsize-1) { target++; //S tile if (getTileHeightToTile(target,tile)<-MAXELEVATIONDIFF) raiseTile(target); } } return false; } bool raiseTile(uint16_t t) { int8_t z = getTileHeight(t); if (z==0) setTileType(t,TER_PLAIN); z++; if (z>7) z=7; setTileHeight(t,z); recursiveGroundRaise(t); if (z==7) digCount = DIGMAX; return true; } uint16_t getFacingTile(uint16_t tile, walkDir facing) { switch (facing) { case NE: if (tile<worldsize) return -1; //out of bounds return tile-worldsize; break; case SE: if (tile%worldsize == worldsize-1) return -1; //out of bounds return tile+1; case SW: if (tile>worldsize*worldsize-worldsize) return -1; return tile+worldsize; case NW: if (tile%worldsize == 0) return -1; return tile-1; } return -1; } void spawnWolf() { for (uint8_t i = 0; i< (gamelevel-1) * WOLFMULT ; i++) { if (werewolves[i].energy <= 0) { uint16_t k; k=random(worldsize*worldsize-1); uint8_t a = (uint8_t)random(3)-1; switch (a) { case 0: werewolves[i].ai = HOMING; break; case 1: werewolves[i].ai = CHASE; break; case 2: werewolves[i].ai = INTERCEPT; break; } werewolves[i].energy = WOLFENERGY; werewolves[i].tile = k; k *= SUBDIVS; werewolves[i].position.x = k%worldsize; werewolves[i].position.y = k/worldsize; numwolves++; i=(gamelevel-1)*WOLFMULT; break; } } } void despawnWolf(uint8_t n) { werewolves[n].energy=0; werewolves[n].visible=false; numwolves--; } void despawnAllWolves() { for (uint8_t i = 0; i< (gamelevel-1)*WOLFMULT ; i++) { despawnWolf(i); } } void moveWolves() { for (uint8_t i = 0; i< (gamelevel-1)*WOLFMULT ; i++) { if (werewolves[i].energy>0) { if (wolvestick) { uint16_t fromtile = werewolves[i].tile; coords fromposition = werewolves[i].position; int16_t aix,aiy,bix,biy; switch (werewolves[i].ai) { case INTERCEPT: if (humans[i].facing==NE) {werewolves[i].position.y--; werewolves[i].animframe = 1 - werewolves[i].animframe; werewolves[i].facing = SE;} if (humans[i].facing==SE) {werewolves[i].position.x++; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = NW;} if (humans[i].facing==SW) {werewolves[i].position.y++; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = SW;} if (humans[i].facing==NW) {werewolves[i].position.x--; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = NE;} if (xorshift8()>0xf0) { uint8_t a = (uint8_t)random(3); switch (a) { case 0: werewolves[i].ai = HOMING; break; case 1: werewolves[i].ai = CHASE; break; case 2: werewolves[i].ai = INTERCEPT; break; case 3: werewolves[i].ai = TURNCW; break; } } break; case CHASE: if (werewolves[i].position.x<oldplayer.x) {werewolves[i].position.x++; werewolves[i].animframe = 1 - werewolves[i].animframe; werewolves[i].facing = SE;} if (werewolves[i].position.x>oldplayer.x) {werewolves[i].position.x--; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = NW;} if (werewolves[i].position.y<oldplayer.y) {werewolves[i].position.y++; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = SW;} if (werewolves[i].position.y>oldplayer.y) {werewolves[i].position.y--; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = NE;} aiy = werewolves[i].position.y - player.y; aix = werewolves[i].position.x - player.x; if (aix<0) aix = -aix; if (aiy<0) aiy = -aiy; if (aix<30 || aiy <30) werewolves[i].ai = HOMING; break; case TURNCW: werewolves[i].goingto.x = werewolves[i].position.x+random(48)-24; werewolves[i].goingto.y = werewolves[i].position.y+random(48)-24; while (worldToTile(werewolves[i].goingto.x,werewolves[i].goingto.y)>worldsize*worldsize-1) { werewolves[i].goingto.x = werewolves[i].position.x+random(48)-24; werewolves[i].goingto.y = werewolves[i].position.y+random(48)-24; } werewolves[i].ai = GOTO; break; case GOTO: if (werewolves[i].position.x<werewolves[i].goingto.x) {werewolves[i].position.x++; werewolves[i].animframe = 1 - werewolves[i].animframe; werewolves[i].facing = SE;} if (werewolves[i].position.x>werewolves[i].goingto.x) {werewolves[i].position.x--; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = NW;} if (werewolves[i].position.y<werewolves[i].goingto.y) {werewolves[i].position.y++; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = SW;} if (werewolves[i].position.y>werewolves[i].goingto.y) {werewolves[i].position.y--; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = NE;} if (werewolves[i].position.x==werewolves[i].goingto.x && werewolves[i].position.y==werewolves[i].goingto.y) werewolves[i].ai = HOMING; break; case HOMING: if (werewolves[i].position.x<player.x) {werewolves[i].position.x++; werewolves[i].animframe = 1 - werewolves[i].animframe; werewolves[i].facing = SE;} if (werewolves[i].position.x>player.x) {werewolves[i].position.x--; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = NW;} if (werewolves[i].position.y<player.y) {werewolves[i].position.y++; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = SW;} if (werewolves[i].position.y>player.y) {werewolves[i].position.y--; werewolves[i].animframe = 1 - werewolves[i].animframe;werewolves[i].facing = NE;} break; } werewolves[i].tile = worldToTile(werewolves[i].position.x,werewolves[i].position.y); if (canWWMoveFromTo(fromtile,werewolves[i].tile)==false) { werewolves[i].position=fromposition; werewolves[i].tile= fromtile; uint8_t a = (uint8_t)random(3); switch (a) { case 0: werewolves[i].ai = HOMING; break; case 1: werewolves[i].ai = CHASE; break; case 2: werewolves[i].ai = INTERCEPT; break; case 3: werewolves[i].ai = TURNCW; break; } } } if (werewolves[i].position.x>(worldsize-1)*SUBDIVS) werewolves[i].position.x=(worldsize-1)*SUBDIVS; if (werewolves[i].position.y>(worldsize-1)*SUBDIVS) werewolves[i].position.y=(worldsize-1)*SUBDIVS; if (werewolves[i].position.x<0) werewolves[i].position.x=1; if (werewolves[i].position.y<0) werewolves[i].position.y=1; if (onScreen(werewolves[i].position)) werewolves[i].visible = true; else werewolves[i].visible = false; werewolves[i].energy-= monsterdrain; if (werewolves[i].energy<=0) despawnWolf(i); } else werewolves[i].visible=false; } } void initworld() { timeofday=0; //value>>8 0 is full daytime, 127 is full night wave=0; oldtime=0; wolvestick=0;watertick=0; playergolds=0; wading=1; focusing=false; inHut = false; worldsize = 10+gamelevel*MAPMULT; caught=false; humans[0].energy=0xFFF;golds=0;playergolds=0; gb.display.load565Palette(pokulous_pal); timeofday=random(0x3FFF); tweenfactor=0; golds=0; player.x=5*SUBDIVS; player.y=0; uint16_t i = 0; /** Empty the world **/ for (i=0;i<worldsize*worldsize;i++) { setTileHeight(i,0); setTileType(i,TER_UNDEFINED); } #define NUMPEAKS worldsize/10 uint16_t bigpeaks = NUMPEAKS*random(2)+NUMPEAKS*3; uint16_t smallpeaks = NUMPEAKS*random(2)+NUMPEAKS*30; uint16_t cliffs = NUMPEAKS*random(2)+NUMPEAKS*3; uint16_t shards = NUMPEAKS*random(4)+NUMPEAKS*30; switch (random(3)) { case 0: //normal ground break; case 1: // lots of land bigpeaks += NUMPEAKS*10; shards /= 10; smallpeaks /= 10; break; case 2: // tiny islands bigpeaks =0; cliffs /=10; shards =0; smallpeaks /= 10; break; case 3: // very rugged shards += NUMPEAKS*50; bigpeaks = 0; smallpeaks /=10; } /** Generate big peaks **/ for (uint8_t r=0; r<bigpeaks;r++) { uint16_t rx = random(worldsize-16)+8; uint16_t ry = random(worldsize-16)+8; uint8_t sx = random(NUMPEAKS)+1; uint8_t sy = random(NUMPEAKS)+1; uint8_t he = random(5)+2; for (uint8_t ty = 0; ty < sy; ty++) { for (uint8_t tx = 0; tx < sx; tx++) { uint32_t index = rx+tx+(ry+ty) * worldsize; if (index<worldsize*worldsize) { setTileHeight(index,he); setTileType(index,TER_PLAIN); } } } } /** Generate small peaks **/ for (uint16_t r=0; r<smallpeaks;r++) { uint16_t rx = random(worldsize-2)+1; uint16_t ry = random(worldsize-2)+1; uint8_t sx = random(3)+1; uint8_t sy = random(3)+1; uint8_t he = random(3)+1; for (uint8_t ty = 0; ty < sy; ty++) { for (uint8_t tx = 0; tx < sx; tx++) { uint32_t index = rx+tx+(ry+ty) * worldsize; if (index<worldsize*worldsize) { setTileHeight(index,he); setTileType(index,TER_PLAIN); } } } } /** generate slopes **/ int8_t level=7; while (level>-1) { i =0; for (int16_t y = 0; y<worldsize; y++) { for (int16_t x = 0; x<worldsize; x++, i++) { uint8_t a = getTileHeight(i); if (a==level) { if (a==0) setTileType(i,TER_WATER); // don't leave undefined tiles else { // set tile that is northwest(previous on x-axis) of this tile if ((x>0) && getTileType(i-1)==TER_UNDEFINED) {setTileType((i-1),TER_PLAIN); setTileHeight((i-1),level-1);} // set tile that is northeast (previous on logical y-axis) of this tile if ((y>0) && getTileType(i-worldsize)==TER_UNDEFINED) {setTileType((i-worldsize),TER_PLAIN); setTileHeight((i-worldsize),level-1);} // set tile that is southeast(next on x-axis) of this tile if ((x<worldsize-1) && getTileType(i+1)==TER_UNDEFINED) {setTileType((i+1),TER_PLAIN); setTileHeight((i+1),level-1);} // set tile that is southwest (next on logical y-axis) of this tile if ((y<worldsize-1) && getTileType(i+worldsize)==TER_UNDEFINED) {setTileType((i+worldsize),TER_PLAIN); setTileHeight((i+worldsize),level-1);} } } } } level--; } /** Generate cliffs **/ for (uint8_t r=0; r<cliffs;r++) { uint16_t rx = random(worldsize-16)+8; uint16_t ry = random(worldsize-16)+8; uint8_t sx = random(NUMPEAKS)+1; uint8_t sy = random(NUMPEAKS)+1; uint8_t he = random(5)+2; for (uint8_t ty = 0; ty < sy; ty++) { for (uint8_t tx = 0; tx < sx; tx++) { uint32_t index = rx+tx+(ry+ty) * worldsize; if (index<worldsize*worldsize) { setTileHeight(index,he); setTileType(index,TER_PLAIN); } } } } /** soften cliffs **/ level=7; int8_t edge = random(6)+1; while (level>edge) { i =0; for (int16_t y = 0; y<worldsize; y++) { for (int16_t x = 0; x<worldsize; x++, i++) { uint8_t a = getTileHeight(i); if (a==level) { if (a==0) setTileType(i,TER_WATER); // don't leave undefined tiles else { // set tile that is northwest(previous on x-axis) of this tile if ((x>0) && getTileType(i-1)==TER_UNDEFINED) {setTileType((i-1),TER_PLAIN); setTileHeight((i-1),level-1);} // set tile that is northeast (previous on logical y-axis) of this tile if ((y>0) && getTileType(i-worldsize)==TER_UNDEFINED) {setTileType((i-worldsize),TER_PLAIN); setTileHeight((i-worldsize),level-1);} // set tile that is southeast(next on x-axis) of this tile if ((x<worldsize-1) && getTileType(i+1)==TER_UNDEFINED) {setTileType((i+1),TER_PLAIN); setTileHeight((i+1),level-1);} // set tile that is southwest (next on logical y-axis) of this tile if ((y<worldsize-1) && getTileType(i+worldsize)==TER_UNDEFINED) {setTileType((i+worldsize),TER_PLAIN); setTileHeight((i+worldsize),level-1);} } } } } level--; } /** Generate small cliffs **/ for (uint16_t r=0; r<shards;r++) { uint16_t rx = random(worldsize-2)+1; uint16_t ry = random(worldsize-2)+1; uint8_t sx = random(1)+1; uint8_t sy = random(1)+1; uint8_t he = random(5)+2; for (uint8_t ty = 0; ty < sy; ty++) { for (uint8_t tx = 0; tx < sx; tx++) { uint32_t index = rx+tx+(ry+ty) * worldsize; if (index<worldsize*worldsize) { setTileHeight(index,he); setTileType(index,TER_PLAIN); } } } } /** Check the world **/ for (i=0;i<worldsize*worldsize;i++) { if (getTileType(i)==TER_UNDEFINED) { setTileHeight(i,0); setTileType(i,TER_WATER); } } /** SET TILE SLOPE TYPES **/ for (uint16_t j=0; j<worldsize*worldsize;j++) { if (getTileHeight(j)) setTileType(j,getTileSlope(j)); #if TREESNROCKS if (getTileType(j)!=TER_WATER) { uint8_t r=xorshift8(); if (r>0xff-HUTPROB) {setTileType(j,TER_HUT);setTileHeight(j,7);} else if (r>0xff-GOLDPROB && golds<MAXGOLD) { setTileType(j,TER_GOLD); //golds++; } else if (r>0xff-STONEPROB) setTileType(j,TER_STONE); else if (r>0xff-TREEPROB) setTileType(j,TER_TREE); } #endif } i=0; uint16_t huts[100],numhuts=0; /** BEACHES **/ for (uint16_t j = 0; j<worldsize*worldsize; j++) { if (world[j]==TER_WATER) { uint16_t y = j/worldsize+1; uint16_t x = j % worldsize; if ((j%worldsize)&&(world[j-1]!=TER_WATER)&&(world[j+1]==TER_WATER)&&x>0) world[j-1]=TER_BEACHSE; if (j>worldsize&&(world[j-worldsize]!= TER_WATER)&&(world[j+worldsize]==TER_WATER)&&y<worldsize-1) world[j-worldsize]=TER_BEACHSW; } } //setTileType(0,TER_HUT); //setTileType(5,TER_HUT); /** CLEAR FRONT PORCHES OF HUTS, count golds **/ for (uint16_t j = 0; j<worldsize*worldsize; j++) { //if (getTileType(j)==TER_GOLD) golds++; if (getTileType(j)==TER_HUT) { if (j < (worldsize-1)*worldsize) { setTileType(j+worldsize, TER_PLAIN);//clear porch huts[numhuts++]=j; } else {setTileType(j, TER_PLAIN);} // invalid dwelling } } /** MAKE SURE AT LEAST 1 HUT **/ if (numhuts==0) { uint16_t ut = worldsize*worldsize/2+worldsize/2; setTileType(ut,TER_HUT); setTileHeight(ut,4); setTileType(ut+worldsize,TER_PLAIN); } /** PUT GUY ON MAP **/ uint16_t t = random(numhuts); //if (numhuts<1) playertile = (uint16_t)random(worldsize*worldsize); //else playertile = huts[t]+2*worldsize;//110;//worldsize/2+worldsize/2*worldsize;//huts[t]; //playertile=202; //setTileHeight(102,7); //setTileType(102,TER_PLAIN); //if (playertile > worldsize*worldsize) playertile = random(worldsize); player.x = (playertile%worldsize)*SUBDIVS; player.y = playertile/worldsize*SUBDIVS; //focusOnTile(playertile); /** Count gold on map **/ golds=0; for (uint16_t i=0;i<worldsize*worldsize;i++) { if (getTileType(i)==TER_GOLD) golds++; } /** Make sure enough gold on the map **/ while (golds<gamelevel*GOLDMULT) { setTileType(random(worldsize*worldsize-1),TER_GOLD); golds++; } } void drawtile(int32_t x, int32_t y, const uint8_t* bmp) { gb.display.drawBitmap(x+cx, y+cy, bmp); } void drawhuman(uint8_t n) { switch (humans[n].facing) { case NE: if (!humans[n].animframe) drawToTile(playertile,pixelman_nw_1,player.x%SUBDIVS,player.y%SUBDIVS,1); else drawToTile(playertile,pixelman_nw_2,player.x%SUBDIVS,player.y%SUBDIVS,1); break; case SE: if (!humans[n].animframe) drawToTile(playertile,pixelman_se_1,player.x%SUBDIVS,player.y%SUBDIVS,0); else drawToTile(playertile,pixelman_se_2,player.x%SUBDIVS,player.y%SUBDIVS,0); break; case SW: if (!humans[n].animframe) drawToTile(playertile,pixelman_se_1,player.x%SUBDIVS,player.y%SUBDIVS,1); else drawToTile(playertile,pixelman_se_2,player.x%SUBDIVS,player.y%SUBDIVS,1); break; case NW: if (!humans[n].animframe) drawToTile(playertile,pixelman_nw_1,player.x%SUBDIVS,player.y%SUBDIVS,0); else drawToTile(playertile,pixelman_nw_2,player.x%SUBDIVS,player.y%SUBDIVS,0); break; default: while(1) { if(gb.update()) gb.display.print("ERROR!!!"); } } } void spawnGold(uint16_t t) { } void drawwolf(uint8_t n) { switch (werewolves[n].facing) { case NE: if (!werewolves[n].animframe) drawToTile(werewolves[n].tile,werewolf_nw_1,werewolves[n].position.x%SUBDIVS,werewolves[n].position.y%SUBDIVS,1); else drawToTile(werewolves[n].tile,werewolf_nw_2,werewolves[n].position.x%SUBDIVS,werewolves[n].position.y%SUBDIVS,1); break; case SE: if (!werewolves[n].animframe) drawToTile(werewolves[n].tile,werewolf_se_1,werewolves[n].position.x%SUBDIVS,werewolves[n].position.y%SUBDIVS,0); else drawToTile(werewolves[n].tile,werewolf_se_2,werewolves[n].position.x%SUBDIVS,werewolves[n].position.y%SUBDIVS,0); break; case SW: if (!werewolves[n].animframe) drawToTile(werewolves[n].tile,werewolf_se_1,werewolves[n].position.x%SUBDIVS,werewolves[n].position.y%SUBDIVS,1); else drawToTile(werewolves[n].tile,werewolf_se_2,werewolves[n].position.x%SUBDIVS,werewolves[n].position.y%SUBDIVS,1); break; case NW: if (!werewolves[n].animframe) drawToTile(werewolves[n].tile,werewolf_nw_1,werewolves[n].position.x%SUBDIVS,werewolves[n].position.y%SUBDIVS,0); else drawToTile(werewolves[n].tile,werewolf_nw_2,werewolves[n].position.x%SUBDIVS,werewolves[n].position.y%SUBDIVS,0); break; } } void drawworld(int32_t x, int32_t y) { uint16_t i=0; uint8_t tiletype; int8_t tileheight; int32_t scrx=x, scry=y; wave+=6; centertile =-1; int16_t rowx = 0; inHut = false; bool hdrawn=false; for (uint8_t iy=0;iy<worldsize;iy++,rowx-=8) { scry=y+iy*4; scrx=x; for (uint8_t ix=0;ix<worldsize;ix++, i++, scrx+=XOFF, scry+=YOFF) { if (scrx+rowx>-5*XOFF && scry>-5*YOFF && scrx+rowx < 110+XOFF && scry < 88+ YOFF ) { tiletype = getTileType(i); tileheight = getTileHeight(i); bool pillar=false; if (tileheight>PILLARHEIGHT) pillar=true; tileheight <<= GROUNDLIFT; switch (tiletype) { case TER_WATER: //wave=xorshift8(); if ((wave>0x7F)) { if (ix&1) drawtile(scrx+rowx,scry-tileheight,ter_water1); else drawtile(scrx+rowx,scry-tileheight,ter_water2); } else { if (ix&1) drawtile(scrx+rowx,scry-tileheight,ter_water2); else drawtile(scrx+rowx,scry-tileheight,ter_water1); } break; case TER_PLAIN: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_plain); break; case TER_GOLD: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_gold); break; case TER_HUT: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-10-tileheight,ter_hut); if (i==playertile) { drawToTile(i,anim_blue_flag1,2,0,0); inHut=true; } break; case TER_BEACHSE: drawtile(scrx+rowx,scry-tileheight-1,ter_beach_se); break; case TER_BEACHSW: drawtile(scrx+rowx,scry-tileheight-1,ter_beach_sw); break; case TER_TREE: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-10-tileheight,ter_tree); break; case TER_STONE: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_stone); break; case TER_BUMP_NW: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_bump_nw); break; case TER_BUMP_NE: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_bump_ne); break; case TER_BUMP_SE: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_bump_se); break; case TER_BUMP_SW: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_bump_sw); break; case TER_BUMP_W: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_bump_w); break; case TER_BUMP_E: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_bump_e); break; case TER_BUMP_S: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight-2,ter_bump_s); break; case TER_BUMP_N: if (pillar) drawtile(scrx+rowx,scry-tileheight,dirt_pillar); drawtile(scrx+rowx,scry-tileheight,ter_bump_n); break; default: break; } if (scrx+rowx<45 && scrx+rowx+2*XOFF>45) { if (scry-tileheight<40 && scry+tileheight+8>40) centertile=i; } if (i==playertile+wading && getTileType(i-wading) != TER_HUT) {drawhuman(0); hdrawn=true;} else if (i==playertile && getTileType(i) != TER_HUT && hdrawn == false) drawhuman(0); for (uint8_t r=0;r<(gamelevel-1)*WOLFMULT;r++) { if (werewolves[r].visible) { if (i==werewolves[r].tile) drawwolf(r); if (werewolves[r].tile == playertile) { caught=true; } } } if (caught) { if (xorshift8()>0xFD) drawToTile(playertile,splatter,random(3)-1,random(3)+1,random(1)); humans[0].energy--; if (humans[0].energy<0) gamestate = GAMEOVER; } } } } } int main () { gb.sound.playMusicStream("ZOMBIE.SND"); gb.begin(); gb.display.load565Palette(pokulous_pal); //gb.display.load565Palette(night_palette); //gb.display.bgcolor=10; gb.display.clear(); gb.display.setColorDepth(4); gb.display.bgcolor = 13; gb.display.invisiblecolor = 15; gb.sound.ampEnable(true); gb.sound.playMusicStream(); uint8_t timeout=0xFF; /** veriables needed in gameloop (can't initialize inside a switch case) **/ coords prev; bool walking; uint8_t newtime; int tgold=0; gb.display.bgcolor = 13; while (gb.isRunning()) { if (gb.update()) { switch (gamestate) { case TITLE: while(!gb.buttons.pressed(BTN_A)&&gb.isRunning()) { if (gb.update()) { gb.display.drawBitmap(0,0,pixonia); gb.display.setFont(fontRunes); gb.display.color=9; gb.display.bgcolor = gb.display.invisiblecolor; gb.display.setCursor(9,74); if (timeout>127) gb.display.print("Copyright 2017 Pokitto ltd"); else gb.display.print(" Press 'A' to Start"); timeout-=2; srand(gb.getTime()); } } gamestate = NEXTLEVEL; initworld(); break; case NEXTLEVEL: gb.display.setColor(9,3); timeout = 0xf; while (timeout--) gb.update(); while(!gb.buttons.pressed(BTN_A)&&gb.isRunning()) { if (gb.update()) { gb.display.setFont(fontRunes); gb.display.setCursor(0,30); gb.display.print(" Level: "); gb.display.palette[6]=65312; gb.display.setColor(6,3); gb.display.println(gamelevel); gb.display.setColor(9,3); gb.display.println(" "); gb.display.print(" Find "); gb.display.setColor(6,3); gb.display.print(gamelevel*GOLDMULT); gb.display.setColor(9,3); gb.display.print(" Gold"); } } gamestate=GAME; break; case INTRO: gb.display.setColor(9,3); timeout = 0xf; while (timeout--) gb.update(); while(!gb.buttons.pressed(BTN_A)&&gb.isRunning()) { if (gb.update()) { gb.display.setFont(fontRunes); gb.display.setCursor(0,30); gb.display.print(" \"There's "); gb.display.palette[6]=65312; gb.display.setColor(6,3); gb.display.println("gold"); gb.display.setColor(9,3); gb.display.println(" on the Islands"); gb.display.println(" of Pixonia!\""); } } gamestate=GAME; break; case LEVELPASSED: gb.display.setColor(9,3); timeout = 0xf; while (timeout--) gb.update(); while(!gb.buttons.pressed(BTN_A)&&gb.isRunning()) { if (gb.update()) { gb.display.setFont(fontRunes); gb.display.setCursor(0,30); gb.display.print(" You made it! "); gb.display.palette[6]=65312; gb.display.setColor(6,3); //gb.display.println(gamelevel); gb.display.setColor(9,3); gb.display.println(" "); gb.display.print(" Found "); gb.display.setColor(6,3); gb.display.print(gamelevel*GOLDMULT); gb.display.setColor(9,3); gb.display.print(" Gold"); } } gamelevel++; gamestate=NEXTLEVEL; initworld(); break; case GAME: wolvestick = 1 - wolvestick; watertick = 1 - watertick; newtime = timeofday>>8; if (oldtime > newtime) oldtime=0; // prevent "flash" when timer spins around if (oldtime < newtime) { oldtime = newtime; if (oldtime<127) tweenfactor +=2; else { tweenfactor -= 2; } if (oldtime>150) { monsterdrain =4; } else monsterdrain =1; if (tweenfactor>253) tweenfactor =253; if (tweenfactor<2) tweenfactor = 2; gb.display.tweenPalette(gb.display.palette,pokulous_pal,night_palette,tweenfactor); if (oldtime>MONSTERMORNING && oldtime<MONSTERNIGHT && xorshift16()>0xFFFF-WOLFPROB) { spawnWolf(); gb.display.palette[6]=gb.display.palette[6]<<1; // make gold brighter during night if (xorshift8()>0xff-GLIMMERPROB) gb.display.palette[6]=65312; //gold is shining } #ifndef POK_SIM //Pokitto::setBacklight(POK_BACKLIGHT_INITIALVALUE*tweenfactor/255); #endif } if (focusing) focusOnTile(focustile); walking=false; prev = player; prevtile = playertile; uint8_t inc; if (wading!=1) inc=watertick; else inc=1; if (caught) inc=0; // we got caught, can't move anymore if (gb.buttons.downBtn() && !gb.buttons.aBtn()) {if (player.x < (worldsize-1)*SUBDIVS) player.x+=inc;humans[0].animframe = 1 - humans[0].animframe;humans[0].facing = SE;} if (gb.buttons.rightBtn() && !gb.buttons.aBtn()) {if (player.y>0) player.y-=inc;humans[0].animframe = 1 - humans[0].animframe;humans[0].facing = NE;} if (gb.buttons.leftBtn() && !gb.buttons.aBtn()) {if (player.y < (worldsize-1)*SUBDIVS) player.y+=inc;humans[0].animframe = 1 - humans[0].animframe;humans[0].facing = SW;} if (gb.buttons.upBtn() && !gb.buttons.aBtn()) {if (player.x>0) player.x-=inc; humans[0].animframe = 1 - humans[0].animframe; humans[0].facing = NW;} /** scroll world **/ coords t; t = worldToScreen(player.x,player.y); if (!focusing) { int16_t owx=wx, owy=wy; uint8_t slower=0; if (t.x>0 && t.x<110 && t.y>0 && t.y<88) { slower = 4; //if (t.x<20 || t.x>90 || t.y<15 || t.y>65) slower =3; } if (t.x<40) {wy-=0;wx+=XSPEED>>slower;} if (t.y<40) {wy+=YSPEED>>slower;wx+=0;} if (t.x>70) {wy+=0;wx-=XSPEED>>slower;} if (t.y>50) {wy-=YSPEED>>slower;wx-=0;} if (centertile > worldsize*worldsize) {centertile=oldcenter; wx=owx; wy=owy;} } playertile = worldToTile(player.x,player.y); if (getTileType(playertile)==TER_WATER) wading=-1; else wading = 1; if (playertile != prevtile && canMoveTo(playertile)==false) { player=prev; playertile= prevtile; } else { oldplayercount++; if (oldplayercount==6) { /*for creature chase ai */ oldplayer=player; oldplayercount=0; } } //if (gb.buttons.pressed(BTN_C)) {initworld();} if (gb.buttons.pressed(BTN_A)) { uint16_t tile = getFacingTile(playertile, humans[0].facing); int8_t z = getTileHeight(tile); if (z==0) setTileType(tile,TER_PLAIN); z++; if (z>7) z=7; setTileHeight(tile,z); setSlopeAutomatic(tile); } if (gb.buttons.pressed(BTN_B)) { uint16_t t = getFacingTile(playertile, humans[0].facing); int8_t z = getTileHeight(t); uint8_t k = getTileType(t); if (getTileType(t)!=TER_HUT) z--; if (z<0) z=0; if (z<getTileHeight(playertile)-1 || z==0) { if (k==TER_GOLD) { playergolds++; if (playergolds==gamelevel*GOLDMULT) { gamestate=LEVELPASSED; } spawnGold(t); } if (k < 5 || k > 12) setTileType(t,TER_PLAIN); } if (z==0) setTileType(t,TER_WATER); setTileHeight(t,z); setSlopeAutomatic(t); } moveWolves(); drawworld(wx,wy); oldcenter = centertile; gb.display.drawBitmap(1,1,gold); gb.display.setCursor(10,0); gb.display.setColor(9,gb.display.invisiblecolor); timeofday += TIMEINCREMENT; if (inHut) timeofday += 7*TIMEINCREMENT; gb.display.print(playergolds); gb.display.print("/"); gb.display.println(gamelevel*GOLDMULT); gb.display.bgcolor = 13; #ifdef DEBUG gb.display.bgcolor = 9; gb.display.println(numwolves); gb.display.print(werewolves[0].position.x);gb.display.print(",");gb.display.println(werewolves[0].position.y); gb.display.print(werewolves[0].tile); switch (werewolves[0].ai) { case HOMING: gb.display.println("HOMING");break; case CHASE: gb.display.println("CHASE");break; case INTERCEPT: gb.display.println("ITERC");break; case GOTO: gb.display.println("GOTO");break; case TURNCW: gb.display.println("TURNCW");break; } gb.display.print(player.x);gb.display.print(",");gb.display.println(player.y); gb.display.println(timeofday>>8); #endif // DEBUG break; case GAMEOVER: timeout = 0xf; while (timeout--) gb.update(); while(!gb.buttons.pressed(BTN_A)&&gb.isRunning()) { if (gb.update()) { gb.display.setFont(fontRunes); gb.display.setCursor(0,20); gb.display.setColor(14,0); gb.display.println(" GAME OVER ");gb.display.println(""); gb.display.setColor(9); gb.display.println(" Player got eaten "); gb.display.println(" by the Beast! "); gb.display.println(""); gb.display.setColor(6); gb.display.palette[6]=65312; gb.display.print(" Gold collected: "); gb.display.print((uint16_t)float(playergolds*100/(gamelevel*GOLDMULT))); gb.display.println("%"); } } despawnAllWolves(); wx=-8,wy=0,cx=10,cy=10; prevtile=0, playertile=0, focustile=0, centertile=0,oldcenter, tween_palette[16], golds=0, playergolds=0; timeofday=0; //value>>8 0 is full daytime, 127 is full nightwave=0, oldtime=0,wolvestick=0,watertick=0; wading=1; focusing=false; inHut = false; tweenfactor=0,numwolves=0; gamelevel=1; initworld(); gamestate=TITLE; break; } } } }