2 Copyright (C) 1998 BJ Eirich (aka vecna)
\r
3 This program is free software; you can redistribute it and/or
\r
4 modify it under the terms of the GNU General Public License
\r
5 as published by the Free Software Foundation; either version 2
\r
6 of the License, or (at your option) any later version.
\r
7 This program is distributed in the hope that it will be useful,
\r
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\r
10 See the GNU General Public Lic
\r
11 See the GNU General Public License for more details.
\r
12 You should have received a copy of the GNU General Public License
\r
13 along with this program; if not, write to the Free Software
\r
14 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
26 #include "keyboard.h"
\r
28 #include "vdriver.h"
\r
31 #include "colstuff.h"
\r
33 #include "smalfont.h"
\r
36 #include "tilesel.h"
\r
38 #define byte unsigned char
\r
39 #define word unsigned short
\r
41 // ================================= Data ====================================
\r
43 char *field, *destruct;
\r
44 char *background, *sprites;
\r
46 int turnlength, turnctr;
\r
47 int destructed, difficulty=4;
\r
48 int blocks, score, scoremultiplier;
\r
51 // Current piece falling
\r
53 char piece[3], tempspot;
\r
54 int xpos, ypos, ypofs;
\r
58 // ================================= Code ====================================
\r
60 void BlitPlayField()
\r
65 for (i=0; i<12; i++)
\r
69 if (c) TCopySprite(128+(j*16), startofs+4+(i*16), 16, 16, sprites+((c+1)*256));
\r
73 void BlitPlayFieldwDestruct(char flash)
\r
78 for (i=0; i<12; i++)
\r
82 if (c && !destruct[(i*6)+j])
\r
83 TCopySprite(128+(j*16), startofs+4+(i*16), 16, 16, sprites+((c+1)*256));
\r
84 if (destruct[(i*6)+j])
\r
85 TCopySprite(128+(j*16), startofs+4+(i*16), 16, 16, sprites+(flash*256));
\r
91 ypofs=((100 * turnctr) / turnlength) * 16 / 100;
\r
93 TCopySprite(128+(xpos*16), startofs+4+(ypos*16)+ypofs, 16, 16, sprites+((piece[0]+1)*256));
\r
94 TCopySprite(128+(xpos*16), startofs+20+(ypos*16)+ypofs, 16, 16, sprites+((piece[1]+1)*256));
\r
95 TCopySprite(128+(xpos*16), startofs+36+(ypos*16)+ypofs, 16, 16, sprites+((piece[2]+1)*256));
\r
97 TCopySprite(276, startofs+70, 16, 16, sprites+((nextpiece[0]+1)*256));
\r
98 TCopySprite(276, startofs+90, 16, 16, sprites+((nextpiece[1]+1)*256));
\r
99 TCopySprite(276, startofs+110, 16, 16, sprites+((nextpiece[2]+1)*256));
\r
102 void GenerateNewPiece()
\r
107 if (field[2]) key[SCAN_ESC]=1;
\r
108 if (field[8]) key[SCAN_ESC]=1;
\r
109 if (field[14]) key[SCAN_ESC]=1;
\r
110 if (field[20]) key[SCAN_ESC]=1;
\r
114 if (difficulty==4 && blocks<240) Message("You really suck at columns, man.",300);
\r
115 if (difficulty==5 && blocks<80) Message("You really suck at columns, man.",300);
\r
116 if (score>3200 && score<=6400) Message("Not bad.",300);
\r
117 if (score>6400) Message("Behold, the Columns God walks among us.",500);
\r
120 memcpy(&piece, &nextpiece, 3);
\r
121 nextpiece[0]=random(1,difficulty);
\r
122 nextpiece[1]=random(1,difficulty);
\r
123 nextpiece[2]=random(1,difficulty);
\r
126 void DestroyBlock(int x, int y)
\r
130 for (i=y; i>0; i--)
\r
132 field[(i*6)+x]=field[((i-1)*6)+x];
\r
135 score+=scoremultiplier;
\r
138 void ClearConsecutiveColumns()
\r
143 // Scan for things to destroy, but don't destroy them, just mark
\r
144 // them in the Destroy field.
\r
147 memset(destruct, 0, (6*13));
\r
149 for (y=0; y<12; y++)
\r
150 for (x=0; x<6; x++)
\r
154 // Test vertical match
\r
157 if ((field[((y+1)*6)+x]==c) && (field[((y+2)*6)+x]==c) && c)
\r
159 // vertical match. Set destruct field.
\r
160 destruct[((y+0)*6)+x]=1;
\r
161 destruct[((y+1)*6)+x]=1;
\r
162 destruct[((y+2)*6)+x]=1;
\r
166 // Test horizontal match
\r
169 if ((field[(y*6)+x+1]==c) && (field[(y*6)+x+2]==c) && c)
\r
171 // horizontal match. Set destruct field.
\r
172 destruct[(y*6)+x+0]=1;
\r
173 destruct[(y*6)+x+1]=1;
\r
174 destruct[(y*6)+x+2]=1;
\r
178 // Test negative diagonal match
\r
181 if ((field[((y+1)*6)+x+1]==c) && (field[((y+2)*6)+x+2]==c) && c)
\r
183 // negative diagonal match. set destruct field.
\r
184 destruct[((y+0)*6)+x+0]=1;
\r
185 destruct[((y+1)*6)+x+1]=1;
\r
186 destruct[((y+2)*6)+x+2]=1;
\r
190 // Test positive diagonal match
\r
193 if ((field[((y+1)*6)+x-1]==c) && (field[((y+2)*6)+x-2]==c) && c)
\r
195 // positive diagonal match. set destruct field.
\r
196 destruct[((y+0)*6)+x-0]=1;
\r
197 destruct[((y+1)*6)+x-1]=1;
\r
198 destruct[((y+2)*6)+x-2]=1;
\r
204 // Show which tiles are being destroyed before clearing out for increase
\r
205 // visual coolishness.
\r
210 while (timer_count<50)
\r
212 if (timer_count<10 || (timer_count>20 && timer_count<30) ||
\r
213 (timer_count>40 && timer_count<50)) c=1;
\r
216 CopySprite(16,16,320,200,background);
\r
217 BlitPlayFieldwDestruct(c);
\r
218 TCopySprite(276, startofs+70, 16, 16, sprites+((nextpiece[0]+1)*256));
\r
219 TCopySprite(276, startofs+90, 16, 16, sprites+((nextpiece[1]+1)*256));
\r
220 TCopySprite(276, startofs+110, 16, 16, sprites+((nextpiece[2]+1)*256));
\r
223 sprintf(strbuf,"Blocks: %d", blocks);
\r
224 printstring(strbuf);
\r
226 sprintf(strbuf,"Score: %d", score);
\r
227 printstring(strbuf);
\r
229 sprintf(strbuf,"Level: %d", level);
\r
230 printstring(strbuf);
\r
236 // Apply destruct-o patch to the field.
\r
238 for (y=0; y<12; y++)
\r
239 for (x=0; x<6; x++)
\r
240 if (destruct[(y*6)+x]) DestroyBlock(x,y);
\r
246 if (field[((ypos+3)*6)+xpos])
\r
248 if (ypos<3) key[SCAN_ESC]=1;
\r
249 // Hit something; set piece here.
\r
250 field[(ypos*6)+xpos]=piece[0];
\r
251 field[((ypos+1)*6)+xpos]=piece[1];
\r
252 field[((ypos+2)*6)+xpos]=piece[2];
\r
255 // Scan for consecutive things to delete.
\r
258 ClearConsecutiveColumns();
\r
259 scoremultiplier*=2;
\r
260 } while (destructed);
\r
266 if (!xpos) return 0;
\r
267 if (field[((ypos+1)*6)+xpos-1]) return 0;
\r
268 if (field[((ypos+2)*6)+xpos-1]) return 0;
\r
269 if (field[((ypos+3)*6)+xpos-1]) return 0;
\r
275 if (xpos==5) return 0;
\r
276 if (field[((ypos+1)*6)+xpos+1]) return 0;
\r
277 if (field[((ypos+2)*6)+xpos+1]) return 0;
\r
278 if (field[((ypos+3)*6)+xpos+1]) return 0;
\r
290 void ProcessLevels()
\r
292 if (blocks>80) { level=2; turnlength=90; }
\r
293 if (blocks>160) { level=3; turnlength=80; }
\r
294 if (blocks>240) { level=4; turnlength=70; }
\r
295 if (blocks>320) { level=5; turnlength=60; }
\r
296 if (blocks>400) { level=6; turnlength=50; }
\r
297 if (blocks>480) { level=7; turnlength=40; }
\r
298 if (blocks>560) { level=8; turnlength=30; }
\r
299 if (blocks>640) { level=9; turnlength=20; }
\r
303 extern int width, depth;
\r
305 extern int vidoffset;
\r
307 void LoadBackground()
\r
311 if (!(pcxf=fopen("colback.pcx","rb")))
\r
313 background=background_;
\r
318 background=(char *) valloc(64000,"col bakg",0);
\r
319 LoadPCXHeaderNP("colback.pcx");
\r
320 for (i=0; i<depth; i++)
\r
323 ReadPCXLine(background);
\r
328 if (!(pcxf=fopen("colspr.pcx","rb")))
\r
335 LoadPCXHeaderNP("colspr.pcx");
\r
336 sprites=(char *) valloc(width*depth,"col spr",0);
\r
337 for (i=0; i<depth; i++)
\r
340 ReadPCXLine(sprites);
\r
351 field=(char *) valloc(6*13,"col field",0);
\r
352 destruct=(char *) valloc(6*13,"col dest",0);
\r
353 memset(field, 0, 6*12);
\r
354 memset(field+(6*12), 255, 6);
\r
362 GenerateNewPiece();
\r
363 GenerateNewPiece();
\r
364 while (!key[SCAN_ESC])
\r
366 CopySprite(16,16,320,200,background);
\r
367 if (key[SCAN_LEFT])
\r
369 if (xpos && CanGoLeft()) xpos--;
\r
372 if (key[SCAN_RIGHT])
\r
374 if (xpos<5 && CanGoRight()) xpos++;
\r
377 if (key[SCAN_DOWN])
\r
387 turnctr+=timer_count;
\r
389 switch (difficulty)
\r
391 case 4: scoremultiplier=5;
\r
392 case 5: scoremultiplier=10;
\r
393 case 6: scoremultiplier=15;
\r
395 if (turnctr>=turnlength)
\r
398 turnctr-=turnlength;
\r
400 if (newpiece) GenerateNewPiece();
\r
405 sprintf(strbuf,"Blocks: %d", blocks);
\r
406 printstring(strbuf);
\r
408 sprintf(strbuf,"Score: %d", score);
\r
409 printstring(strbuf);
\r
411 sprintf(strbuf,"Level: %d", level);
\r
412 printstring(strbuf);
\r