/* GEM Worm
* Copyright (C) 2009 Jeffrey Armstrong
* http://jeff.rainbow-100.com
*
* This program 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.
*
* This program 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 this program. If not, see .
*
* A full version of the license terms is available in LICENSE.txt.
*/
#include
/*#include */
#ifdef __GNUC__
#include
#define HIWORD(x) ((int16_t)((uint32_t)x >> 16))
#define LOWORD(x) ((int16_t)((uint32_t)x & 0xFFFF))
#else
#include
#include
#include
#endif /* __GNUC__ */
/* The proper resource header is dependent upon system */
#ifdef PCGEM
#include "wormpc.h"
#else
#include "wormst.h"
#endif
#include "field.h"
#include "player.h"
/* Sometimes you may need to compile in some missing global
* arrays used within the gem libraries
*/
#ifdef PCGEM
#ifdef NEEDGSX
GLOBAL WORD contrl[11]; /* control inputs */
GLOBAL WORD intin[80]; /* max string length */
GLOBAL WORD ptsin[256]; /* polygon fill points */
GLOBAL WORD intout[45]; /* open workstation output */
GLOBAL WORD ptsout[12];
#endif
#else
#define FAR
#endif
WORD app_wflags = NAME | CLOSER | MOVER | SIZER;
WORD app_accid;
WORD app_appid;
WORD app_wh = -1; /* Border window handle */
WORD app_vh; /* VDI handle */
char *app_title = "Worm";
GRECT app_wdw; /* xywh of working area */
OBJECT FAR *app_menu;
OBJECT FAR *about_box;
#ifndef WF_WXYWH
#ifdef WF_WORKXYWH
#define WF_WXYWH WF_WORKXYWH
#endif
#endif
#ifndef WF_CXYWH
#ifdef WF_CURRXYWH
#define WF_CXYWH WF_CURRXYWH
#endif
#endif
#define max(x,y) x>y ? x : y
#define min(x,y) xg_x+one->g_w,two->g_x+two->g_w);
th = min(one->g_y+one->g_h,two->g_y+two->g_h);
tx = max(one->g_x,two->g_x);
ty = max(one->g_y,two->g_y);
two->g_x = tx;
two->g_y = ty;
two->g_w = tw-tx;
two->g_h = th-ty;
return ( (tw > tx) && (th > ty) );
}
#endif
void hndl_about()
{
GRECT box,origin;
/* ob_xywh(app_menu, MDESK, &origin); */
form_center(about_box, &box.g_x, &box.g_y, &box.g_w, &box.g_h);
objc_draw(about_box,0,2,box.g_x, box.g_y, box.g_w, box.g_h);
form_do(about_box,0);
form_dial(FMD_FINISH,0,0,0,0,box.g_x, box.g_y, box.g_w, box.g_h);
return;
}
int open_window(int new)
{
graf_mouse(M_OFF,NULL);
wind_update(BEG_UPDATE);
app_wh = wind_create(app_wflags, 0, 0, 200, 200);
if(app_wh<=0)
return -1;
#ifdef PCGEM
wind_set(app_wh, WF_NAME, FPOFF(app_title), FPSEG(app_title), 0, 0);
#else
#ifdef MGEMLIB
wind_set(app_wh, WF_NAME, HIWORD(app_title), LOWORD(app_title), 0, 0);
#else
wind_set(app_wh, WF_NAME, app_title);
#endif
#endif
if(new == 1) {
/* Get the desktop */
wind_get(0, WF_WXYWH, &app_wdw.g_x,
&app_wdw.g_y,
&app_wdw.g_w,
&app_wdw.g_h);
app_wdw.g_w = min(STARTWIDTH,app_wdw.g_w);
app_wdw.g_h = min(STARTHEIGHT,app_wdw.g_h);
}
wind_open(app_wh, app_wdw.g_x, app_wdw.g_y, app_wdw.g_w, app_wdw.g_h);
wind_get(app_wh, WF_WXYWH, &app_wdw.g_x,
&app_wdw.g_y,
&app_wdw.g_w,
&app_wdw.g_h);
wind_update(END_UPDATE);
graf_mouse(M_ON,NULL);
return 1;
}
int init_app()
{
WORD work_in[11];
WORD work_out[57];
WORD ww;
WORD i;
WORD txtwidth,txtheight;
app_accid = appl_init();
/* VDI handle... */
app_vh = graf_handle(&txtwidth,&txtheight,&i,&i);
for(i=0;i<10;i++) work_in[i] = 1;
work_in[10] = 2;
v_opnvwk(work_in,&app_vh,work_out);
/* RSC load */
if(rsrc_load(RCS_FILE) == 0) {
form_alert(1,"[3][The resource file was not found][Exit]");
return -1;
}
wind_update(BEG_UPDATE);
rsrc_gaddr(R_TREE,RCMENU,&app_menu);
menu_bar(app_menu,1);
wind_update(END_UPDATE);
rsrc_gaddr(R_TREE,ABOUT,&about_box);
/* Make the application name nicer */
menu_register(app_accid, "Worm!");
return open_window(1);
}
int get_score_height()
{
WORD attrib[10];
vqt_attributes(app_vh, attrib);
return attrib[9];
}
void do_redraw_score(WPLAYER *player, GRECT *update)
{
WORD pts[4];
char score_str[128];
vsf_interior(app_vh, 1);
/* Fill background */
vsf_color(app_vh, (WORD)WHITE);
pts[0] = update->g_x; pts[1] = update->g_y;
pts[2] = update->g_x+update->g_w; pts[3] = update->g_y+update->g_h;
v_bar(app_vh, pts);
/* Text */
sprintf(score_str, "Score: %d", player->score);
vst_color(app_vh, (WORD)BLACK);
v_gtext(app_vh, update->g_x+5, update->g_y + update->g_h - 2, score_str);
}
void force_redraw_score(WPLAYER *player)
{
GRECT score;
graf_mouse(M_OFF,NULL);
wind_update(BEG_UPDATE);
wind_get(app_wh, WF_WXYWH, &score.g_x, &score.g_y, &score.g_w, &score.g_h);
score.g_h = get_score_height();
do_redraw_score(player, &score);
wind_update(END_UPDATE);
graf_mouse(M_ON,NULL);
}
void window_to_field_rect(GRECT *rc)
{
int sh;
sh = get_score_height() + 1;
rc->g_y += sh;
rc->g_h -= sh;
}
#define PRINTRC(n,r) printf("%s -> x=%d y=%d w=%d h=%d\n", n, r.g_x, r.g_y, r.g_w, r.g_h)
/* Not necessary yet... */
void do_redraw(WPLAYER *player)
{
GRECT box, me, field, score, rc;
int updated_score;
WORD pts[4];
#ifdef DEBUG
printf("REDRAW!\n");
#endif
graf_mouse(M_OFF,NULL);
wind_update(BEG_UPDATE);
wind_get(app_wh, WF_WXYWH, &me.g_x, &me.g_y, &me.g_w, &me.g_h);
memcpy(&field, &me, sizeof(GRECT));
memcpy(&score, &me, sizeof(GRECT));
score.g_h = get_score_height();
window_to_field_rect(&field);
wind_get(app_wh, WF_FIRSTXYWH, &box.g_x,
&box.g_y,
&box.g_w,
&box.g_h);
updated_score = 0;
while(box.g_w || box.g_h) {
#ifdef DEBUG
PRINTRC("box", box);
PRINTRC("field", field);
#endif
memcpy(&rc, &field, sizeof(GRECT));
if(rc_intersect(&box, &rc)) {
#ifdef DEBUG
printf("Field draw\n");
#endif
pts[0] = box.g_x;
pts[1] = box.g_y;
pts[2] = box.g_w+box.g_x-1;
pts[3] = box.g_h+box.g_y-1;
vs_clip(app_vh, 1, pts);
draw_field(app_vh, &field);
}
#ifdef DEBUG
PRINTRC("box", box);
PRINTRC("score", score);
#endif
memcpy(&rc, &score, sizeof(GRECT));
if(rc_intersect(&box, &rc)) {
#ifdef DEBUG
printf("Score draw\n");
#endif
pts[0] = box.g_x;
pts[1] = box.g_y;
pts[2] = box.g_w+box.g_x-1;
pts[3] = box.g_h+box.g_y-1;
vs_clip(app_vh, 1, pts);
do_redraw_score(player, &score);
/* updated_score = 1; */
}
wind_get(app_wh, WF_NEXTXYWH, &box.g_x,
&box.g_y,
&box.g_w,
&box.g_h);
}
/* Turn off clipping */
vs_clip(app_vh, 0, pts);
wind_update(END_UPDATE);
graf_mouse(M_ON,NULL);
}
void do_window_change(GRECT *rect)
{
wind_set(app_wh, WF_CXYWH, rect->g_x, rect->g_y, rect->g_w, rect->g_h);
wind_get(app_wh, WF_WXYWH, &app_wdw.g_x, &app_wdw.g_y, &app_wdw.g_w, &app_wdw.g_h);
}
void hndl_keys(WORD key, WPLAYER *player)
{
char asc;
asc = key & 127;
switch(asc) {
case 'w':
case 'W':
player->dir = WUP;
break;
case 's':
case 'S':
player->dir = WDOWN;
break;
case 'a':
case 'A':
player->dir = WLEFT;
break;
case 'd':
case 'D':
player->dir = WRIGHT;
break;
}
}
int main(int argc, char *argv[])
{
WORD ret;
WORD msg[8];
int done;
WORD top;
WORD dummy;
WORD special_keys;
WORD key;
WPLAYER *player;
GRECT field;
int playing = 0;
int palive, falive;
int tailx, taily;
#ifdef __GEMLIB__
EVMULT_IN evin;
EVMULT_OUT evout;
#endif
srand(time(NULL));
if(init_app() > 0) {
done = 0;
#ifdef DEBUG
printf("AppID: %d\n",app_accid);
#endif
player = init_player();
field_init();
food_init();
#ifdef DEBUG
printf("Game init complete\n");
#endif
#ifdef __GEMLIB__
memset(&evin, 0, sizeof(EVMULT_IN));
evin.emi_flags = MU_KEYBD | MU_MESAG | MU_TIMER;
evin.emi_tlow = (int16_t)MOVEDELAY;
#endif
/* Set up the "field" rectangle */
memcpy(&field, &app_wdw, sizeof(GRECT));
window_to_field_rect(&field);
msg[0] = AC_OPEN;
msg[4] = app_accid;
ret = MU_MESAG;
done = -2;
while(done <=0) {
if(done == -2)
done = -1;
else {
#ifdef __GEMLIB__
ret = evnt_multi_fast(&evin, msg, &evout);
key = evout.emo_kreturn;
#else
ret = evnt_multi(MU_KEYBD | MU_MESAG | MU_TIMER, /* Accept keypresses, messages, and timers */
0, 0, 0, /* Mouse clicks, which buttons, and states */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Mouse movement info */
msg, /* 16-byte message array */
(WORD)MOVEDELAY, 0, /* The low and high word of the timer in ms */
&dummy, &dummy, /* Mouse position @ mouse event */
&dummy, /* Mouse button status */
&special_keys, /* "Special" key statuses */
&key, /* Key pressed scancode */
&dummy); /* # of mouse button presses */
#endif
}
#ifdef DEBUG
printf("maybe MSG: %d\n",msg[0]);
#endif
/* Key presses */
if((ret & MU_KEYBD) && playing > 0) {
hndl_keys(key, player);
}
/* Timer - update game */
if((ret & MU_TIMER) && playing > 0) {
wind_update(BEG_UPDATE);
palive = update_player(player, &tailx, &taily);
falive = update_field(player);
switch(food_check(app_vh, &field, player)) {
case FOODADDITION:
player->score += 100;
force_redraw_score(player);
break;
case FOODRESETCOUNT:
player->score -= 10;
if(player->score < 0) player->score = 0;
force_redraw_score(player);
break;
}
/* form_alert(1,"[1][Update][Ok]"); */
/* draw_field(app_vh, &app_wdw); */
incremental_draw(app_vh, &field, player->head->c_x, player->head->c_y);
incremental_draw(app_vh, &field, tailx, taily);
wind_update(END_UPDATE);
if(palive == DEAD || falive == DEAD) {
form_alert(1,"[3][You've Died!|Good try, though...][Reset]");
reset_player(player);
playing = 0;
}
}
/* Messages (menu, resizes, etc.) */
if(ret & MU_MESAG) {
#ifdef DEBUG
printf("MSG: %d\n",msg[0]);
#endif
switch(msg[0]) {
case AC_OPEN:
if(msg[4] != app_accid)
break;
if(app_wh > 0) {
wind_get(0,WF_TOP, &top, &dummy, &dummy, &dummy);
if(top != app_wh) {
wind_set(app_wh, WF_TOP, app_wh, 0, 0, 0);
wind_set(app_wh, WF_CXYWH, 30,30,100,100);
}
} else
open_window(0);
break;
case AC_CLOSE:
if(msg[3] == app_accid)
app_wh = -1;
break;
case WM_CLOSED:
if(msg[3] != app_wh || app_wh < 0)
break;
graf_mouse(M_OFF,NULL);
wind_close(app_wh);
wind_delete(app_wh);
graf_mouse(M_ON,NULL);
app_wh = -1;
done = 1;
break;
case WM_TOPPED:
wind_set(app_wh,WF_TOP,app_wh,0,0,0);
break;
case WM_MOVED:
case WM_SIZED:
do_window_change((GRECT *)&msg[4]);
memcpy(&field, &app_wdw, sizeof(GRECT));
window_to_field_rect(&field);
/* Fall through */
case WM_REDRAW:
update_field(player);
do_redraw(player);
break;
case MN_SELECTED:
switch(msg[4]) {
case MQUIT:
msg[0] = WM_CLOSED;
msg[3] = app_wh;
appl_write(app_accid,sizeof(msg),msg);
break;
case MNEW:
player->score = 0;
force_redraw_score(player);
update_field(player);
draw_field(app_vh, &field);
playing = 1;
break;
case MABOUT:
hndl_about();
break;
}
menu_tnormal(app_menu, msg[3], 1);
break;
} /* switch */
} /* if */
if(app_wh <= 0 )
continue;
/* done = 0; */
} /* while */
v_clsvwk(app_vh);
/* wind_close(app_wh); */
/* wind_delete(app_wh); */
appl_exit();
}
return 0;
}