/****************************************************************************\
* *
* Copyright by Casimo, 2013 *
* *
* This file is part of fxMaze. *
* *
* fxMaze is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* fxMaze is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with fxMaze. If not, see . *
* *
\****************************************************************************/
// Thanks to PierrotLL for MonochromeLib! I took some functions and modified them a bit.
#include "global.h"
#include "draw.h"
#include "sprites.h"
#include "hardware.h"
#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;
if(y&~63 || (x1<0 && x2<0) || (x1>127 && x2>127)) return;
if(x1 < 0) x1 = 0;
if(x2 > 127) x2 = 127;
if(x1>>3 != x2>>3)
{
vram[(y<<4)+(x1>>3)] |= 255 >> (x1&7);
vram[(y<<4)+(x2>>3)] |= 255 << 7-(x2&7);
for(i=(x1>>3)+1 ; i>3 ; i++)
vram[(y<<4) + i] = 255;
}
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;
if(x1 > x2)
{
i = x1;
x1 = x2;
x2 = i;
}
if(y1 > y2)
{
i = y1;
y1 = y2;
y2 = i;
}
for(i=y1 ; i<=y2 ; i++)
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;
for(x = 0; x < MAPSIZE; x++)
{
for(y = 0; y < MAPSIZE; y++)
{
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; // 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; // factor for zooming
while(windowx + zoom * 2 >= MAPSIZE)
{
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])
{
case WALL: break;
case DOOR:
PrintMini((x - windowx) * skew, (y - windowy) * skew, "I", MINI_OVER);
break;
}
}
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)
{
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)
{
Sleep(500);
}
else if(lastkey == thiskey)
{
Sleep(125);
}
lastkey = thiskey;
if(keydown(KEY_CTRL_EXIT)) exit = TRUE; // back to the game
// move the window
if(keydown(KEY_CTRL_UP) && windowy > 0)
{
windowy--;
thiskey = KEY_CTRL_UP;
}
if(keydown(KEY_CTRL_DOWN) && windowy + zoom < MAPSIZE)
{
windowy++;
thiskey = KEY_CTRL_DOWN;
}
if(keydown(KEY_CTRL_LEFT) && windowx > 0)
{
windowx--;
thiskey = KEY_CTRL_LEFT;
}
if(keydown(KEY_CTRL_RIGHT) && windowx + zoom * 2 < MAPSIZE)
{
windowx++;
thiskey = KEY_CTRL_RIGHT;
}
// zoom in and out
if(keydown(KEY_CHAR_PLUS) && zoom > 1)
{
zoom--;
thiskey = KEY_CHAR_PLUS;
}
if(keydown(KEY_CHAR_MINUS) && zoom < MAPSIZE / 2)
{
zoom++;
thiskey = KEY_CHAR_MINUS;
}
}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:
if(gun[u][i] == 1)
{
(*(vram + ((y + u) << 4) + ((54 + i) >> 3))) |= (128 >> ((54 + i) & 7));
}
else
{
if(gun[u][i] == 2)
{
(*(vram + ((y + u) << 4) + ((54 + i) >> 3))) &= ( ~ (128 >> ((54 + i) & 7)));
}
}
break;
case KNIFE:
if(knife[u][i] == 1)
{
(*(vram + ((y + u) << 4) + ((54 + i) >> 3))) |= (128 >> ((54 + i) & 7));
}
else
{
if(knife[u][i] == 2)
{
(*(vram + ((y + u) << 4) + ((54 + i) >> 3))) &= ( ~ (128 >> ((54 + i) & 7)));
}
}
break;
}
}
}
}
}
// 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)
{
int tmp = start;
start = end;
end = tmp;
}
if(start < 0) start = 0;
if(end > 63) end = 63;
for(;start < end; start++)
pixel(x,start);
}
// swap the end and start to draw from top down
if(start > end)
{
int tmp = start;
start = end;
end = tmp;
}
// for every type of sprite use different textures
switch(type)
{
case WALL:
// bitshifts are _lots_ faster than floats!
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 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))) |= ((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)] == 1)
{
(*(buffpos + (y << 4))) |= shiftbyte;
}
else
{
if(pack[pos >> 8][(int)(tex >> 3)] == 2)
{
(*(buffpos + (y << 4))) &= ( ~shiftbyte);
}
}
}
break;
}
}