/* Hardwire Sprite based puzzle game. Based on MSDOS version. Version history --------------- 10/05/98 Moved to GCC (hoorah) 20/07/98 Version 2 to try and come up with a GDUK entry. Cripes! 13/08/98 Moved to RCS control. Log follows. $Log: hardwire.c,v $ Revision 1.3 1998/08/23 21:00:39 dosuser Version used for GDUK competition Revision 1.2 1998/08/13 22:07:23 dosuser Working version before moving scroller to credit page and adding SFX Revision 1.1 1998/07/13 21:17:04 dosuser Initial revision */ static char rcs_id[]="$Id: hardwire.c,v 1.3 1998/08/23 21:00:39 dosuser Exp dosuser $"; #include #include #include #include "common.h" #include "sprint.h" #include "sprite.h" #include "tmddef.h" #include "ft16_tim.h" #include "ft_tim.h" #include "spr_tim.h" #include "text_tim.h" #include "sfx_vb.h" #include "sfx_vh.h" #include "t_seq.h" #include "g_seq.h" #define TRACE(x) printf("*** TRACE %d\n",x) /* PS constants */ #define MODE MODE_PAL #define SCRW 320 #define SCRH 240 #define CX 160 #define CY 128 #define OT_LEN 10 /* Length of order table */ #define MAXCHAR 500 /* Max sprites allocated to printing */ #define MAXSPRITE 500 /* Max sprites allocated to sprite drawing */ #define TOTSPRITE MAXCHAR+MAXSPRITE /* Game definitions */ #define NOMODE 3 #define MINPITW 6 #define MAXPITW 9 #define DEFPITW 9 #define PITDEPTH 12 #define PATHLEN (PITDEPTH*MAXPITW) #define MAXLEV 10 #define LEVELCTR(x) MAX(0,(45-(x)*4)) #define SPRSIZE 13 #define SPRCENTRE 7 #define PITXOFF ((SPRSIZE*2)+((MAXPITW-PITW)*SPRSIZE/2)) #define PITYOFF SPRSIZE*5 #define PITX(x) (((x)*SPRSIZE)+PITXOFF) #define PITY(y) (((y)*SPRSIZE)+PITYOFF) #define SCOREPX 200 #define SCOREX (SCOREPX+50) #define SCOREY 120 #define LEVELPX 200 #define LEVELX (LEVELPX+50) #define LEVELY 100 #define NEXTPX 200 #define NEXTX (NEXTPX+50) #define NEXTY 20 #define NODIR -1 #define LEFT 0 #define UP 1 #define RIGHT 2 #define DOWN 3 #define ROR(x) ((x) ? ((x)-1) : (3)) #define ROL(x) (((x)+1)%4) int xi[4]={-1,0,1,0}; int yi[4]={0,-1,0,1}; char *mode[NOMODE]= {" EASY", " HARD", "HECK!"}; /* Sprite definitions */ #define PIT_TL 0 #define PIT_ML 1 #define PIT_BL 2 #define PIT_BM 3 #define PIT_BR 4 #define PIT_MR 5 #define PIT_TR 6 #define BLANK -1 #define PATH 7 #define CROSS 8 #define ACROSS 9 #define UPDOWN 10 #define LEFTDOWN 11 #define LEFTUP 12 #define RIGHTUP 13 #define RIGHTDOWN 14 #define SPECIAL 15 #define PLX_BASE 20 #define SPRADD(no) (((no)%16)*16),(((no)/16)*16) #define SPRADDX(no) (((no)%16)*16) #define SPRADDY(no) (((no)/16)*16) /* Sprite priorities */ #define PRI_BACK 10 #define PRI_PIT 5 #define PRI_PIECE 5 #define PRI_PATH 4 #define PRI_TEXT 3 #define PRI_FORE 2 #define PRI_FADE 1 #define PRI_DEBUG 0 /* Font tables - not used short fw8[256],fw16[256]; */ /* Definie pit */ typedef struct { int data[PITDEPTH][MAXPITW]; int id[PITDEPTH][MAXPITW]; } Pit; Pit pit; typedef struct { int x,y; } PathElem; typedef struct { int len; PathElem p[PATHLEN]; int spr[PATHLEN]; } Path; /* Definie piece types and control structs */ #define PIECE_SIZE 5 typedef struct { int ox,oy; int data[PIECE_SIZE][PIECE_SIZE]; } Piece; typedef struct { int no; int piece[5]; } PieceSet; typedef struct { int x,y; } Offset; typedef struct { int no; Piece *map; Offset *offset; int *height; } PieceMap; #include "pset.c" #include "map4.c" PieceSet *piece_set; PieceMap *piece_map=&piece_map4; PieceSet *piece_set_list[NOMODE]= { piece_set_cross, piece_set_rnd, piece_set_no_rnd }; /* Define the game */ typedef struct { int score; int level; char name[4]; } Hisc; typedef struct { int x,y; int level; int score; int rotate; int is_special; int current_type; Piece current; int next_is_special; int next_type; Piece next; } Game; Game game; /* Sprite/TIM vars */ GsIMAGE font_img,font16_img,sprite_img,texture_img; int font_tp,font16_tp,sprite_tp,texture_tp; /* PS globals */ volatile u_char *pad1,*pad2; #define P_UP 0 #define P_DOWN 1 #define P_LEFT 2 #define P_RIGHT 3 #define P_CROSS 4 #define P_SQUARE 5 #define P_START 6 #define P_SELECT 7 #define P_NO 8 typedef struct { int bounce; int cnt; int pressed; int code; } PadState; /* Bounce val of -1 effectively no bouncing */ PadState padmap[P_NO]= { {1,0,0,PS_PADUP}, /* UP */ {1,0,0,PS_PADDOWN}, /* DOWN */ {1,0,0,PS_PADLEFT}, /* LEFT */ {1,0,0,PS_PADRIGHT}, /* DOWN */ {1,0,0,PS_PADCROSS}, /* CROSS */ {1,0,0,PS_PADSQUARE}, /* SQUARE */ {-1,0,0,PS_PADSTART}, /* START */ {-1,0,0,PS_PADSELECT}, /* SELECT */ }; int bounce_weight=1; #define PRESS(x) (padmap[(x)].pressed) #define SetBounce(x) bounce_weight=(x) /* Ordering tables and GPU odds and sods... */ GsOT ot[2]; GsOT_TAG ot_tag[2][1<-1;f-=2) { NewFrame(); Centre16("THANKS FOR PLAYING",SCRH/2,0,0,PRI_TEXT,f/2,f/2,f); PageFlip(FALSE); } } /* ------------------------------------------------------------------------- CREDIT PAGE ------------------------------------------------------------------------- */ void CreditPage(void) { # define CREDITY(y) (10+(y)*10) # define CREDIT(s,y,r,g,b) Centre8(s,CREDITY(y),0,0,PRI_TEXT,r,g,b) # define CREDITSPR 30 struct { int x; int y,yi; int r,g,b; long a,ai; } crspr[CREDITSPR]; static char scroll_txt[]= { " " "Welcome to HARDWIRE..." " " "Written on the Net Yaroze, " "July/August 98 for the GDUK competition" " " "Special thanks to " "Julianne Regan, " "Suzanne Vega, " "Natalie Imbruglia, " "Laurie Anderson, " "Garbage, " "Fear Factory, " "FSOL, " "Misery Loves Co, " "Front Line Assembly, " "Cubanate and The Prodigy" " " "Extra special thanks to Sony and Team Yaroze" }; int scroll_txt_len; int tc,c; int tx,x; int f; for(f=0;fSCRH+16) crspr[f].y-=SCRH+16; Sprite(crspr[f].x,crspr[f].y, 16,16,7,7,SPRADD(51), crspr[f].a,ONE,ONE, 1,1, PRI_BACK+crspr[f].yi, crspr[f].r,crspr[f].g,crspr[f].g); } /* Scrolling text */ c=tc; x=tx; for(f=0;f<41;f++) { SPutCh8(scroll_txt[c],x,CREDITY(18),0,0,PRI_BACK+2,0x80,0x80,0x80); c=(c+1)%scroll_txt_len; x+=8; } if ((tx-=2)==-8) { tx=0; tc=(tc+1)%scroll_txt_len; } CREDIT("HARDWIRE",0,0x80,0x80,0x80); CREDIT("_________",0,0x80,0x80,0x80); CREDIT("Coded and designed by",2,0x80,0x80,0x00); CREDIT("Ian C",3,0x80,0x00,0x00); CREDIT("For the GDUK competition 1998",4,0x80,0x80,0x00); CREDIT("All graphics and music by",7,0x80,0x80,0x00); CREDIT("Ian C",8,0x80,0x00,0x00); CREDIT("Instrument sounds by",10,0x80,0x80,0x00); CREDIT("Sony",11,0x80,0x00,0x00); CREDIT("Press START to go back",20,0x80,0x80,0x80); CREDIT("ianc@noddybox.demon.co.uk",22,0x80,0x80,0x00); PageFlip(TRUE); } } /* ------------------------------------------------------------------------- TITLE PAGE ------------------------------------------------------------------------- */ void TitlePage(void) { # define MENUY(y) (65+(y)*18) # define MENU(s,y) Centre16(s,MENUY(y),1,0,PRI_TEXT,0x80,0x80,0x80) char sp[80]; int red,redi; int f; int choice=0; int ch_cnt=0; int ch_del=0; int start_game=FALSE; int bh_col=0x00; int lastmode; red=0x40; redi=1; SetBounce(12); StopTune(); PlayTune(title_seq_id); while (!start_game) { NewFrame(); /* Draw title text */ Centre16("HARDWIRE",10,0,0,PRI_TEXT,red,0,0); Centre16("NODDYBOX 1998",30,0,0,PRI_TEXT,0x80,0x80,0x80); red+=redi; if ((red==0x40)||(red==0x80)) redi=-redi; Centre8("Press START to play",SCRH-20,0,0,PRI_TEXT,red,red,0x80-red); Centre8("Press SELECT to quit",SCRH-12,0,0,PRI_TEXT,0x80-red,red,red); /* Redraw menu */ MENU("PLAY GAME",0); sprintf(sp,"DIFFICULTY %5s",mode[GAME]); MENU(sp,1); sprintf(sp,"SPEED %4d",LEVEL); MENU(sp,2); sprintf(sp,"PIT WIDTH %4d",PITW); MENU(sp,3); sprintf(sp,"BACKDROP %4s",(BDROP_ON ? "ON" : "OFF")); MENU(sp,4); sprintf(sp,"SOUND MODE %5s",sound_mode[SOUNDMODE]); MENU(sp,5); sprintf(sp,"VOLUME %-4s",""); MENU(sp,6); MENU("VIEW CREDITS",7); for(f=0;f<12;f++) if (VOLUME>(f*10)) FastSprite(234+f*5,MENUY(6),16,16,SPRADD(52), 0,0,PRI_TEXT,0x40,0x40,0x40); else FastSprite(234+f*5,MENUY(6),16,16,SPRADD(53), 0,0,PRI_TEXT,0x40,0x40,0x40); sprintf(sp,"%c`````````````````%c",'a'+ch_cnt,'k'+ch_cnt); if (ch_del++==8) { ch_cnt=(ch_cnt+1)%4; ch_del=0; } Centre16(sp,MENUY(choice),1,1,PRI_FORE,0x40,0x40,0x40); /* Menu inputs */ if (PRESS(P_UP)) { if (choice) choice--; else choice=7; } if (PRESS(P_DOWN)) { if (choice<7) choice++; else choice=0; } if (PRESS(P_START)) { start_game=TRUE; } if (PRESS(P_SELECT)) { start_game=TRUE; QUIT=TRUE; } if (((PRESS(P_CROSS))||(PRESS(P_SQUARE)))&&(choice==0)) start_game=TRUE; if ((PRESS(P_CROSS))||(PRESS(P_RIGHT))) switch(choice) { case 0: break; case 1: if (++GAME==NOMODE) GAME=0; break; case 2: if (LEVELSOUND_SFX) SOUNDMODE=SOUND_BOTH; if (lastmode==SOUND_SFX) PlayTune(title_seq_id); if (SOUNDMODE==SOUND_SFX) StopTune(); break; case 6: VOLUME=MIN(VOLUME+10,127); SsSetMVol(VOLUME,VOLUME); break; } if ((PRESS(P_SQUARE))||(PRESS(P_LEFT))) switch(choice) { case 0: break; case 1: if (--GAME==-1) GAME=NOMODE-1; break; case 2: if (LEVEL>1) LEVEL--; break; case 3: if (PITW>MINPITW) PITW--; break; case 4: BDROP_ON=!BDROP_ON; break; case 5: lastmode=SOUNDMODE; if (--SOUNDMODElen=0; return (FALSE); } p->p[p->len].x=sx; p->p[p->len].y=sy; p->spr[p->len]=pit.data[sy][sx]; p->len++; sx+=xi[dir]; sy+=yi[dir]; if (sy==-1) { return (FALSE); p->len=0; } if ((sx==-1)||(sx==PITW)||(sy==PITDEPTH)) return (TRUE); else return (FindPathFrom(sx,sy,dir,p)); } int FindPath(Path *p) { int f; p->len=0; for(f=PITDEPTH-1;f>=0;f--) { if (FindPathFrom(0,f,RIGHT,p)) return (TRUE); if (FindPathFrom(PITW-1,f,LEFT,p)) return (TRUE); } for(f=0;flen=0; return (FALSE); } p->p[p->len].x=x; p->p[p->len].y=y; p->spr[p->len]=pit.data[y][x]; p->len++; x+=xi[dir]; y+=yi[dir]; if ((p->len>2)&&(x==p->p[1].x)&&(y==p->p[1].y)) return (TRUE); else return (FindLoopFrom(ox,oy,x,y,dir,p)); } int FindLoop(Path *p) { int x,y; p->len=0; for(y=PITDEPTH-1;y>=0;y--) for(x=0;xp[p->len].x=x; p->p[p->len].y=y; p->spr[p->len]=pit.data[y][x]; p->len++; /* The specials are a special(?!) case, as they must become PATHs as going along, or else the same pieces may be picked up twice and the Path object overflow. Note this will be replaced by a PATH object on DrawPath() anyway. */ pit.data[y][x]=BLANK; } } void GetTotalPath(Path *p) { int x,y; p->len=0; for(y=PITDEPTH-1;y>=0;y--) for(x=0;xp[p->len].x=x; p->p[p->len].y=y; p->spr[p->len]=pit.data[y][x]; p->len++; } } void GetSpecialPath(Path *p) { int x,y; p->len=0; if (game.y>0) GetSpecialPathFromTile(pit.data[game.y-1][game.x],p); if (game.y<(PITDEPTH-1)) GetSpecialPathFromTile(pit.data[game.y+1][game.x],p); if (game.x>0) GetSpecialPathFromTile(pit.data[game.y][game.x-1],p); if (game.x<(PITW-1)) GetSpecialPathFromTile(pit.data[game.y][game.x+1],p); } void DrawPath(Path *p) { int c; int f; short scale; for(f=0;flen;f++) pit.data[p->p[f].y][p->p[f].x]=PATH; scale=ONE; for(c=0x80;c>=0;c-=8) { /* The redraw and pageflip is the inverse of the main loop so that it appears more transparent */ DrawGameScreen(); RedrawPit(); DrawInfo(); UpdateScores(); for(f=0;flen;f++) Sprite(PITX(p->p[f].x)+SPRCENTRE,PITY(p->p[f].y)+SPRCENTRE, SPRSIZE,SPRSIZE,SPRCENTRE,SPRCENTRE,SPRADD(p->spr[f]), 0,scale,scale, 1,1,PRI_FORE,c,c,c); scale+=ONE/6; PageFlip(TRUE); /* Start new frame */ NewFrame(); } } void DebugPath(Path *p) { char s[80]; int c; int f; if (PRESS(P_SELECT)) exit(0); sprintf(s,"len : %d",p->len); SPrint8(s,10,10,0,0,PRI_DEBUG,0x80,0x80,0x80); for(f=0;flen;f++) pit.data[p->p[f].y][p->p[f].x]=BLANK; for(c=0x80;c>=0;c-=8) { /* The redraw and pageflip is the inverse of the main loop so that it appears more transparent */ DrawGameScreen(); RedrawPit(); DrawInfo(); UpdateScores(); for(f=0;flen;f++) FastSprite(PITX(p->p[f].x),PITY(p->p[f].y),SPRSIZE,SPRSIZE, SPRADD(PATH),1,1,PRI_PIT,RND(0x80),RND(0x80),RND(0x80)); PageFlip(TRUE); /* Start new frame */ NewFrame(); } } /* ------------------------------------------------------------------------- SCORE UTILS ------------------------------------------------------------------------- */ #define DSNO 10 #define DSFADE 1 struct { char p[80]; int sc; int col; int cnt; int y; } dispsc[DSNO]; void InitScores(void) { int f; for(f=0;f=0;f--) dispsc[f+1]=dispsc[f]; strcpy(dispsc[0].p,s); dispsc[0].sc=sc; dispsc[0].col=0x80; dispsc[0].cnt=DSFADE; dispsc[0].y=SCOREY+10; } void UpdateScores(void) { int f; char s[80]; for(f=0;fheight[game.current_type]+game.current.oy; game.rotate=0; game.next_is_special=special; if (special) { game.next_type=-1; for(x=0;xno); for(x=0;xmap[game.next_type].data[y][x]==NON_PS) game.next.data[y][x]=BLANK; else { ps=piece_set+piece_map->map[game.next_type].data[y][x]; game.next.data[y][x]=ps->piece[RND(ps->no)]; } game.next.ox=piece_map->offset[game.next_type*4].x; game.next.oy=piece_map->offset[game.next_type*4].y; } } void RotPiece(int dir) { int x,y; Piece p; if (game.is_special) return; if (dir==LEFT) { game.rotate=ROL(game.rotate); for(x=0;xoffset[game.current_type*4+game.rotate].x; p.oy=piece_map->offset[game.current_type*4+game.rotate].y; } else { game.rotate=ROR(game.rotate); for(x=0;xoffset[game.current_type*4+game.rotate].x; p.oy=piece_map->offset[game.current_type*4+game.rotate].y; } game.current=p; } /* ------------------------------------------------------------------------- PLAY GAME UTILS ------------------------------------------------------------------------- */ int MoveOK(int x, int y) { int cx,cy,nx,ny; for(cx=0;cx=PITW)||(ny>=PITDEPTH)) return(FALSE); if ((ny>=0)&&(pit.data[ny][nx]!=BLANK)) return(FALSE); } return(TRUE); } int AddAndCheckIsDead(int id) { int cx,cy,nx,ny; if (game.is_special) return(game.y<0); else for(cx=0;cx=PITW)||(ny<0)||(ny>=PITDEPTH)) return(TRUE); pit.data[ny][nx]=game.current.data[cy][cx]; pit.id[ny][nx]=id; } return(FALSE); } void UnglueID(int id) { int x,y; for(x=0;x=0) if (pit.data[y][x]!=BLANK) return (pit.id[y][x]==0); else y--; return(FALSE); } void CompressBlanks(void) { int x,y,ny; for(x=0;x=0)&&(!PRESS(P_CROSS));f--) { NewFrame(); DrawGameScreen(); RedrawPit(); DrawInfo(); UpdateScores(); Centre16("GAME OVER",SCRH/2-8,1,1,PRI_FORE,f/2,f/4,f/8); PageFlip(TRUE); } } FadeOut(); PadFlush(); } /* ------------------------------------------------------------------------- CD UTILS ------------------------------------------------------------------------- */ void LoadCD(char *file, char *msg, u_long *addr) { CdReadFile(file,addr,0); if (CdReadSync(0,NULL)==-1) { printf("CD Read error!!"); exit(0); } VSync(0); } /* END OF FILE */