/*
BOBOLI main game executable
By Mike Hommel
CSC 404
compile with DJGPP v2
*/
#include "mgraph.h"
#include "umk.h"
#include "timer.h"
#include "mkey.h"
#include "mfont.h"
#include "boboli.h"
#include "guys.h"
#include <stdio.h>
#include "com.h"
projectile prj[maxprjctls];
displayrec disp[maxdisplay];
genrec gen[maxgen];
umkset stuff,guypix[numtypes],prjpix,objpix;
scrntype scrn,scrn2;
byte *backgd[2];
byte curpage=0;
byte anim=0;
tileset tiles;
paltype gamepal;
colmat dark;
maprec map;
byte quit=0;
short scrx,scry;
creature guy[maxguys];
playerrec player[numplayers];
centerray guyctr[numtypes],prjctr,objctr;
word randseed1=20; /* for my not-quite-random number generator */
word randseed2=75;
word randnum,randrange;
rect validscreen={0,0,199,199};
byte player_num; /* which of the players is on this computer */
byte twoplayer=1;
byte numcreatures=0;
void titles(void)
{
paltype p;
memset(p,0,768);
setpal(p);
loadPCX("pcx\\title.pcx",p,screen);
fade_in(0,0,0,p);
print(318-14*6,192,244,0,"PRESS A KEY...",screen);
while((keystate(_Q)!=pressed)&&(keystate(_A)!=pressed)&&
(keystate(_S)!=pressed)&&(keystate(_W)!=pressed));
clear(0,screen);
}
byte intersect(rect s,rect d)
{
return ((s.x<=d.x2)&&(s.x2>=d.x)&&(s.y<=d.y2)&&
(s.y2>=d.y)&&(s.x!=s.x2)&&(s.y!=s.y2)&&
(d.x!=d.x2)&&(d.y!=d.y2));
}
word random(word range)
{
randrange=range;
asm volatile ("pusha
movw _randseed2,%ax
movw _randseed1,%bx
movw %ax,%si
movw %bx,%di
movb %ah,%dl
movb %al,%ah
movb %bh,%al
movb %bl,%bh
xorb %bl,%bl
rcrb $1,%dl
rcrw $1,%ax
rcrw $1,%bx
addw %di,%bx
adcw %si,%ax
addw $0x62e9,%bx
adcw $0x3619,%ax
movw %bx,_randseed2
movw %ax,_randseed1
xorw %dx,%dx
movw _randrange,%cx
divw %cx
movw %dx,_randnum
popa");
return randnum;
}
void gamedelay(void)
{
asm volatile ("pushw %ax
1:
movb _timetick,%al
cmpb $0,%al
jz 1b
popw %ax
");
timetick=0;
waitretrace();
}
void loadctr(char *name,centerray c)
{
FILE *f;
f=fopen(name,"rb");
fread(c,1,sizeof(centerray),f);
fclose(f);
}
void loadtiles(char *name,tileset t)
{
short i,j,k,x,y;
paltype p;
loadPCX(name,p,scrn);
x=0; y=0;
for(i=0;i<128;i++) {
for(j=0;j<16;j++)
for(k=0;k<16;k++)
t[i][j+k*16]=scrn[x+j+(y+k)*320];
x+=16;
if(x>319) {
x=0;
y+=16;
}
}
}
void loadmap(void)
{
FILE *f;
f=fopen("temp.map","rb");
fread(map,sizeof(maprec),1,f);
fread(gen,sizeof(genrec)*maxgen,1,f);
fclose(f);
}
void get_input(byte wh)
{
if(guy[player[wh].who].hp>0) {
player[wh].command=((keystate(Up)==pressed)||(keystate(Up)==held))*cmd_up+
((keystate(Down)==pressed)||(keystate(Down)==held))*cmd_dn+
((keystate(Left)==pressed)||(keystate(Left)==held))*cmd_lf+
((keystate(Right)==pressed)||(keystate(Right)==held))*cmd_rt+
((keystate(_Q)==pressed)||(keystate(_Q)==held))*cmd_at+
(keystate(_A)==pressed)*cmd_drop+
(keystate(_S)==pressed)*cmd_next+
(keystate(_W)==pressed)*cmd_use;
} else player[wh].command=0;
}
byte addcreature(byte kind,short x,short y,byte dir,byte control)
{
byte i=0;
while((i<maxguys)&&(guy[i].kind!=nobody)) i++;
if(i==maxguys) return 255;
numcreatures++;
guy[i].kind=kind;
guy[i].hp=cd[kind].maxhp;
guy[i].x=x;
guy[i].y=y;
guy[i].z=0;
guy[i].dz=0;
guy[i].dir=dir;
guy[i].timer=0;
guy[i].doing=do_stand;
guy[i].frame=0;
guy[i].control=control;
guy[i].nearfoe=255;
guy[i].friend=255;
guy[i].state=0;
return i;
}
byte addprjctl(byte kind,short x,short y,byte z,byte dir,byte launcher,byte lguy)
{
byte i=0;
while((i<maxprjctls)&&(prj[i].kind!=pr_none)) i++;
if(i==maxprjctls) return 255;
prj[i].kind=kind;
prj[i].x=x;
prj[i].y=y;
prj[i].z=z;
prj[i].dir=dir%4;
prj[i].launchguy=lguy;
switch(kind) {
case pr_spark: prj[i].timer=6;
prj[i].dx=2-random(5);
prj[i].dy=2-random(5);
prj[i].dz=0;
if(dir==1) prj[i].dz=1;
break;
case pr_golem: prj[i].timer=14;
prj[i].dx=0;
prj[i].dy=0;
prj[i].dz=0;
break;
case pr_flower: prj[i].timer=26;
prj[i].dx=0;
prj[i].dy=0;
prj[i].dz=0;
break;
case pr_shield: prj[i].timer=1;
prj[i].dx=0;
prj[i].dy=0;
prj[i].dz=0;
break;
case pr_smoke: prj[i].timer=12;
prj[i].dx=0;
prj[i].dy=0;
prj[i].dz=2;
break;
case pr_splash: prj[i].timer=35;
prj[i].dx=0;
prj[i].dy=0;
prj[i].dz=0;
break;
case pr_tornado: prj[i].timer=50;
prj[i].dx=2*(dir==0)-2*(dir==2);
prj[i].dy=2*(dir==1)-2*(dir==3);
prj[i].dz=0;
break;
case pr_hsprk: prj[i].timer=6;
prj[i].dx=2-random(5);
prj[i].dy=2-random(5);
prj[i].dz=0;
if(dir==1) prj[i].dz=1;
break;
case pr_arrow: prj[i].timer=0;
prj[i].dx=7*(prj[i].dir==0)-7*(prj[i].dir==2);
prj[i].dy=7*(prj[i].dir==1)-7*(prj[i].dir==3);
prj[i].dz=0;
if((dir>3)&&(dir<8)) {
prj[i].dx+=3*(prj[i].dir==3)-3*(prj[i].dir==1);
prj[i].dy+=3*(prj[i].dir==0)-3*(prj[i].dir==2);
}
if(dir>7) {
prj[i].dx+=3*(prj[i].dir==1)-3*(prj[i].dir==3);
prj[i].dy+=3*(prj[i].dir==2)-3*(prj[i].dir==0);
}
break;
case pr_fball: prj[i].timer=5;
prj[i].dx=5*(dir==0)-5*(dir==2);
prj[i].dy=5*(dir==1)-5*(dir==3);
prj[i].dz=0;
break;
case pr_burst: prj[i].timer=8;
prj[i].dx=0;
prj[i].dy=0;
prj[i].dz=0;
break;
case pr_homing: prj[i].timer=35*5;
prj[i].dx=0;
prj[i].dy=0;
prj[i].dz=0;
break;
case pr_skull: prj[i].timer=70;
prj[i].dx=(dir==0)-(dir==2);
prj[i].dy=(dir==1)-(dir==3);
prj[i].dz=0;
break;
case pr_brightspot: prj[i].timer=10+(z>0)*4;
prj[i].dx=0;
prj[i].dy=0;
prj[i].dz=0;
prj[i].z=0;
break;
case pr_slime: prj[i].timer=0;
prj[i].dx=4*(dir==0)-4*(dir==2);
prj[i].dy=4*(dir==1)-4*(dir==3);
prj[i].dz=3;
break;
case pr_splat: prj[i].timer=6;
prj[i].dx=0;
prj[i].dy=0;
prj[i].dz=0;
break;
}
prj[i].launcher=launcher;
return i;
}
void init_player(byte wh)
{
byte i;
strcpy(player[wh].name,"JAMUL");
player[wh].color=19+wh*16;
player[wh].command=0;
player[wh].who=addcreature(boboli,32+wh*48+8,32,1,wh);
player[wh].homex=(32+wh*48)/16;
player[wh].homey=2;
map[player[wh].homex+player[wh].homey*mapwidth].object=ob_genrtr;
for(i=0;i<maxgen;i++) if(gen[i].kind==gn_none) {
gen[i].kind=gn_boboli;
gen[i].x=player[wh].homex;
gen[i].y=player[wh].homey;
gen[i].hp=1;
gen[i].frame=1;
i=maxgen;
}
guy[player[wh].who].state|=st_invis;
guy[player[wh].who].state|=st_invinc;
guy[player[wh].who].hp=0;
guy[player[wh].who].friend=wh;
player[wh].victimkind=255;
player[wh].strength=1;
player[wh].speed=1;
player[wh].intellect=1;
player[wh].armor=1;
player[wh].skill=0;
player[wh].magictimer=1;
player[wh].selfhptimer=1;
player[wh].magic=0;
player[wh].selfhp=0;
player[wh].realmagic=0;
player[wh].realselfhp=0;
player[wh].using=0;
player[wh].messtimer=0;
strcpy(player[wh].message,player[wh].name);
player[wh].inv[0]=it_xbow;
player[wh].invistimer=0;
player[wh].invinctimer=0;
for(i=1;i<6;i++)
player[wh].inv[i]=0;
}
void init_boboli(void)
{
byte i;
__djgpp_nearptr_enable();
initmg();
timer_init(FRAMERATE);
kb_init();
font_init("misc\\little.fnt");
gmode(0x13);
scrn=(scrntype)malloc(64000);
scrn2=(scrntype)malloc(64000);
backgd[0]=(byte *)malloc(backgdwidth*backgdheight);
backgd[1]=(byte *)malloc(backgdwidth*backgdheight);
mat_load("misc\\dark.mat",dark);
umk_load("umks\\stuff.umk",stuff);
umk_load("umks\\boboli.umk",guypix[0]);
umk_load("umks\\bonehead.umk",guypix[1]);
umk_load("umks\\glob.umk",guypix[2]);
umk_load("umks\\golem.umk",guypix[3]);
umk_load("umks\\orc.umk",guypix[4]);
umk_load("umks\\mage.umk",guypix[5]);
umk_load("umks\\prjctls.umk",prjpix);
umk_load("umks\\objects.umk",objpix);
loadctr("ctr\\boboli.ctr",guyctr[0]);
loadctr("ctr\\bonehead.ctr",guyctr[1]);
loadctr("ctr\\glob.ctr",guyctr[2]);
loadctr("ctr\\golem.ctr",guyctr[3]);
loadctr("ctr\\orc.ctr",guyctr[4]);
loadctr("ctr\\mage.ctr",guyctr[5]);
loadctr("ctr\\prjctls.ctr",prjctr);
loadctr("ctr\\objects.ctr",objctr);
loadtiles("pcx\\tiles.pcx",tiles);
loadPCX("pcx\\main.pcx",gamepal,scrn2);
titles();
setpal(gamepal);
for(i=0;i<maxguys;i++) guy[i].kind=nobody;
for(i=0;i<maxprjctls;i++) prj[i].kind=pr_none;
loadmap();
init_player(0);
if(twoplayer) init_player(1);
addcreature(mage,60*16,54*16,1,255);
}
void exit_boboli(void)
{
kb_exit();
timer_exit();
gmode(0x3);
umk_free(stuff);
umk_free(prjpix);
umk_free(objpix);
umk_free(guypix[0]);
umk_free(guypix[1]);
umk_free(guypix[2]);
free(scrn);
free(scrn2);
free(backgd[0]);
free(backgd[1]);
while(kbhit()) getch();
__djgpp_nearptr_disable();
}
byte calc_shadows(byte x,byte y)
{
byte v;
if(map[x+y*mapwidth].floor>63) return 0; /* no shadows on walls */
if((map[x+y*mapwidth].floor==1)||(map[x+y*mapwidth].floor==2))
return 0; /* no shadows on doors */
if(x==0) {
if(y==0) return 6;
else if(map[x+(y-1)*mapwidth].floor>63) return 6;
else return 2;
}
if(y==0) {
if(map[x-1+y*mapwidth].floor>63) return 6;
else return 4;
}
if(map[x-1+y*mapwidth].floor>63) {
if(map[x+(y-1)*mapwidth].floor>63) return 6;
if(map[x-1+(y-1)*mapwidth].floor>63) return 2;
else return 1;
}
if(map[x+(y-1)*mapwidth].floor>63) {
if(map[x-1+(y-1)*mapwidth].floor>63) return 4;
else return 5;
}
if(map[x-1+(y-1)*mapwidth].floor>63) return 3;
return 0;
}
long tilesrc,tiledst,tilecaddr;
void tile_shadow(byte x,byte y,colmat c,umkrec u,byte *scr)
{
tilesrc=(long)u.img;
tiledst=(long)(scr+x+y*backgdwidth);
tilecaddr=(long)c;
asm("pusha
push %ds
pop %es
movl _tilesrc,%esi
movl _tiledst,%edi
movb $16,%dl
movb $16,%dh
xorl %eax,%eax
movl _tilecaddr,%ebx
tshloop1:
movb %ds:(%esi),%al
incl %esi
cmpb $0,%al
jnz tshnonzero
movb %ds:(%esi),%al
incl %esi
addl %eax,%edi
subb %al,%dl
jnz tshloop1
jmp tshlinedone
tshnonzero:
movb %es:(%edi),%al
movb %ds:(%ebx,%eax),%al
movb %al,%es:(%edi)
incl %edi
decb %dl
jnz tshloop1
tshlinedone:
decb %dh
jz tshdone
addl $240,%edi
movb $16,%dl
jmp tshloop1
tshdone:
popa");
}
void draw_tile(byte x,byte y,tilerec t,byte *scr)
{
register byte i;
for(i=0;i<16;i++) {
memcpy(&(scr[x+y*backgdwidth]),&(tiles[t.floor][i*16]),16);
y++;
}
y-=16;
if(t.shadow>0)
tile_shadow(x,y,dark,stuff[t.shadow-1],scr);
}
void draw_map(short x,short y)
{
byte i,j;
byte sx,sy;
sy=16-(y%16);
for(j=(byte)(y/16);j<(byte)(y/16+14);j++) {
sx=16-(x%16);
for(i=(byte)(x/16);i<(byte)(x/16+14);i++) {
draw_tile(sx,sy,map[i+j*mapwidth],backgd[0]);
sx+=16;
}
sy+=16;
}
for(i=16;i<216;i++)
memcpy(&(scrn[(i-16)*320]),&(backgd[0][16+i*backgdwidth]),200);
curpage=0;
}
void scrollscr(short dx,short dy,scrntype src,scrntype dst)
{
long sofs,dofs,amt;
amt=((256-abs(dx))>>2)+(255-abs(dy))*64+1;
sofs=(long)src+(dy>0)*(dy*256);
dofs=(long)dst+(dy<0)*(-dy*256);
sofs+=(dx>0)*dx;
dofs+=(dx<0)*(-dx);
asm("pusha
pushw %%ds
popw %%es
movl %0,%%esi
movl %1,%%edi
movl %2,%%ecx
rep; movsl
popa"::"m" (sofs),"m" (dofs),"m" (amt));
}
void update_inv(void)
{
short i,x=212,y=61;
xfer(211,60,278+32+1,94+32+1,scrn2,scrn);
for(i=0;i<6;i++) {
if(player[player_num].inv[i]>it_none)
umk_draw(x,y,stuff[7+player[player_num].inv[i]],scrn);
if(player[player_num].using==i) umk_draw(x-1,y-1,stuff[8],scrn);
x+=33;
if(x>278) {
x=212;
y+=33;
}
}
}
void update_stats(void)
{
xfer(208,130,208+49,154+2,scrn2,scrn);
box(208,130,207+player[player_num].strength,132,54,scrn);
box(208,136,207+player[player_num].speed,138,54,scrn);
box(208,142,207+player[player_num].intellect,144,54,scrn);
box(208,148,207+player[player_num].armor,150,54,scrn);
if(player[player_num].skill>0)
box(208,154,207+(player[player_num].skill*50)/player[player_num].skillmax,156,54,scrn);
}
void data_display(void)
{
xfer(211,28,211+99,28+11,scrn2,scrn);
xfer(211,45,211+99,45+11,scrn2,scrn);
if(player[player_num].selfhp>player[player_num].realselfhp)
player[player_num].selfhp--;
if(player[player_num].selfhp<player[player_num].realselfhp)
player[player_num].selfhp++;
if(player[player_num].selfhp>0) {
box(211,28,210+player[player_num].selfhp,28,42,scrn);
box(211,29,210+player[player_num].selfhp,29,43,scrn);
box(211,30,210+player[player_num].selfhp,37,39,scrn);
box(211,38,210+player[player_num].selfhp,38,37,scrn);
box(211,39,210+player[player_num].selfhp,39,36,scrn);
}
if(player[player_num].magic>player[player_num].realmagic)
player[player_num].magic--;
if(player[player_num].magic<player[player_num].realmagic)
player[player_num].magic++;
if(player[player_num].magic>0) {
box(211,45,210+player[player_num].magic,45,24,scrn);
box(211,46,210+player[player_num].magic,46,26,scrn);
box(211,47,210+player[player_num].magic,54,23,scrn);
box(211,55,210+player[player_num].magic,55,21,scrn);
box(211,56,210+player[player_num].magic,56,20,scrn);
}
xfer(205,190,315,196,scrn2,scrn);
if(player[player_num].messtimer==0) {
print(206,191,15,8,player[player_num].message,scrn);
} else {
player[player_num].messtimer--;
print(206,191,32+15-abs(15-player[player_num].messtimer/2),0,
player[player_num].message,scrn);
if(--player[player_num].messtimer==0) {
strcpy(player[player_num].message,player[player_num].name);
}
}
}
void scrollmap(char dx,char dy)
{
byte i,j;
byte sx,sy;
short osx,osy;
osx=scrx; osy=scry;
scrx+=dx; scry+=dy;
if(scrx<0) scrx=0;
if(scrx>mapwidth*16-200-16) scrx=mapwidth*16-200-16;
if(scry<0) scry=0;
if(scry>mapheight*16-200-16) scry=mapheight*16-200-16;
dx=scrx-osx; dy=scry-osy;
scrollscr(dx,dy,backgd[curpage],backgd[1-curpage