00001 #include "engine.h"
00002
00003 #define MONSTMOVETIME ((current_map.gamerules==RULESET_KYE92)?(3):(6))
00004 engine_map current_map;
00005 int player_x, player_y;
00006 int scroll_x=0, scroll_y=0;
00007 int current_level_num = 0;
00008 int advance_to_level = 0;
00009 int round;
00010 int num_diamonds;
00011 int have_moved = 0;
00012
00013 #if 0
00014
00015 void game_loop(void)
00016 {
00017 draw_current_map();
00018
00019 OSFreeTimer(USER_TIMER);
00020 OSRegisterTimer(USER_TIMER, DELAY_TIME);
00021
00022 do
00023 {
00024 if(!delay_and_input())
00025 return;
00026 clear_effects();
00027 if(current_map.gamerules == RULESET_DCKYE)
00028 turn_sliders();
00029 set_magnet_skips();
00030
00031 advance();
00032 round++;
00033
00034 if(advance_to_level != current_level_num)
00035 {
00036 if(!level_advance(advance_to_level))
00037 return;
00038 }
00039 } while(1);
00040 }
00041
00042
00043 int delay_and_input(void)
00044 {
00045 short input;
00046 short early_exit = 0;
00047 int have_received_input = 0;
00048 static int previous_move = 0;
00049 static int block_move = 0;
00050
00051 have_moved = 0;
00052
00053 if(OSTimerCurVal(USER_TIMER) > 5) {
00054 OSFreeTimer(USER_TIMER);
00055 OSRegisterTimer(USER_TIMER, DELAY_TIME);
00056 }
00057
00058 do {
00059 GrayIdle();
00060
00061 if(have_moved==0) {
00062 input = poll_char() & ~0x800;
00063 if(!input) continue;
00064 have_received_input = 1;
00065 if(input != previous_move) {
00066 previous_move = input;
00067 block_move = MOVE_DELAY;
00068 if(!make_move(input))
00069 return 0;
00070 else
00071 early_exit = 1;
00072 }
00073 else if(!block_move) {
00074 if(!make_move(input)) return 0;
00075 else early_exit = 1;
00076 }
00077 }
00078 if(early_exit && OSTimerCurVal(USER_TIMER)+1 < DELAY_TIME)
00079 break;
00080 } while(!OSTimerExpired(USER_TIMER));
00081 OSFreeTimer(USER_TIMER);
00082
00083 if(have_moved == 0 && block_move==0) previous_move = 0;
00084 if(have_received_input == 0) {
00085 previous_move = 0;
00086 block_move = 0;
00087 }
00088 if(block_move) block_move--;
00089
00090 flush_input();
00091
00092
00093 OSRegisterTimer(USER_TIMER, DELAY_TIME);
00094
00095 return 1;
00096 }
00097
00098 #else
00099
00100 void game_loop(void)
00101 {
00102 int input;
00103
00104 draw_current_map();
00105
00106 OSFreeTimer(USER_TIMER);
00107 OSRegisterTimer(USER_TIMER, DELAY_TIME);
00108
00109 do
00110 {
00111 have_moved = 0;
00112 input = read_char_with_timeout() & ~0x800;
00113 if(input) {
00114 if( make_move(input) == 0 )
00115 return;
00116 }
00117
00118 OSTimerRestart(USER_TIMER);
00119
00120 clear_effects();
00121 set_magnet_skips();
00122 advance();
00123 round++;
00124
00125 if(advance_to_level != current_level_num) {
00126 if(!level_advance(advance_to_level))
00127 return;
00128 }
00129 } while(1);
00130 }
00131
00132 #endif
00133
00134
00135 int level_advance(int level)
00136 {
00137 int input;
00138 do {
00139 current_level_num = level;
00140 if(!load_kyelib(current_level_num))
00141 return 0;
00142
00143 input = show_splash();
00144 if(input=='+') {
00145 level++;
00146 } else if(input=='-') {
00147 if(current_level_num==0)
00148 break;
00149 level = current_level_num-1;
00150 } else {
00151 break;
00152 }
00153 } while(1);
00154 advance_to_level = level;
00155 begin_level();
00156 draw_current_map();
00157 return 1;
00158 }
00159
00160
00161
00162 int make_move(int key)
00163 {
00164 if(have_moved) return 1;
00165 have_moved = 1;
00166 if (key == KEY_RIGHT) kye_move(1, 0);
00167 else if(key == KEY_DOWN) kye_move(0, 1);
00168 else if(key == KEY_LEFT) kye_move(-1, 0);
00169 else if(key == KEY_UP) kye_move(0, -1);
00170 else if(key == KEY_ESC) return 0;
00171 else if(key == KEY_F1 || key == KEY_CLEAR) restart_level();
00172 else if(key == '+') advance_to_level = current_level_num + 1;
00173 else if(key == '-') {
00174 if(current_level_num > 0)
00175 advance_to_level = current_level_num - 1;
00176 else restart_level();
00177 } else if(key == KEY_F2) {
00178 if( strlen(current_map.hint)>0 )
00179 message(current_map.hint);
00180 draw_current_map();
00181 }
00182
00183 return 1;
00184 }
00185
00186
00187
00188 void kye_move(int dx, int dy)
00189 {
00190 int x = player_x+dx, y = player_y+dy;
00191 int block;
00192 if(!is_in_bounds(x, y))
00193 return;
00194 block = current_map.t[y][x].v;
00195 if(block==TILE_DIAMOND) {
00196 current_map.t[y][x].v = TILE_EMPTY;
00197 check_diamonds();
00198 } else if(block==TILE_EMPTY) {
00199 ;
00200 } else if(block==TILE_FUZZY) {
00201 current_map.t[y][x].v = TILE_EMPTY;
00202 } else if(can_shove(x, y, dx, dy)) {
00203 shove(x, y, dx, dy);
00204 } else if(block==DOOR_EW) {
00205 if(dx!=1) return;
00206 } else if(block==DOOR_WE) {
00207 if(dx!=-1) return;
00208 } else if(block==DOOR_NS) {
00209 if(dy!=1) return;
00210 } else if(block==DOOR_SN) {
00211 if(dy!=-1) return;
00212 } else {
00213 return;
00214 }
00215
00216 if(current_map.t[player_y][player_x].v != TILE_KYE)
00217 {
00218 ;
00219 }
00220 else if(dx && is_in_bounds(player_x-dx, player_y) &&
00221 (current_map.t[player_y][player_x-dx].v == TILE_STICKY_EW ||
00222 current_map.t[player_y][player_x-dx].v == TILE_MAGNET_EW) )
00223 {
00224 current_map.t[player_y][player_x].v =
00225 current_map.t[player_y][player_x-dx].v;
00226 current_map.t[player_y][player_x-dx].v = TILE_EMPTY;
00227 draw_map_tile(player_x-dx, player_y);
00228 if(can_shove(player_x-dx-dx, player_y, dx, 0))
00229 shove(player_x-dx-dx, player_y, dx, 0);
00230 }
00231 else if(dy && is_in_bounds(player_x, player_y-dy) &&
00232 (current_map.t[player_y-dy][player_x].v == TILE_STICKY_NS ||
00233 current_map.t[player_y-dy][player_x].v == TILE_MAGNET_NS) )
00234 {
00235 current_map.t[player_y][player_x].v =
00236 current_map.t[player_y-dy][player_x].v;
00237 current_map.t[player_y-dy][player_x].v = TILE_EMPTY;
00238 draw_map_tile(player_x, player_y-dy);
00239 if(can_shove(player_x, player_y-dy-dy, 0, dy))
00240 shove(player_x, player_y-dy-dy, 0, dy);
00241 } else {
00242 current_map.t[player_y][player_x].v = TILE_EMPTY;
00243 }
00244 player_x += dx;
00245 player_y += dy;
00246 draw_map_tile(player_x-dx, player_y-dy);
00247 if(current_map.t[player_y][player_x].v==TILE_EMPTY)
00248 current_map.t[player_y][player_x].v = TILE_KYE;
00249 if(current_map.t[player_y][player_x].effect.duration > 0) {
00250 current_map.t[player_y][player_x].effect.sprite = EFFECT_NONE;
00251 current_map.t[player_y][player_x].effect.duration = 0;
00252 }
00253 draw_map_tile(player_x, player_y);
00254 scroll_viewport();
00255 }
00256
00257
00258 void scroll_viewport(void)
00259 {
00260 int new_x=scroll_x, new_y=scroll_y;
00261
00262 if(player_x < scroll_x+EDGE_X)
00263 new_x = max(scroll_x-SCROLL_INCR_X, 0);
00264 if(player_y < scroll_y+EDGE_Y)
00265 new_y = max(scroll_y-SCROLL_INCR_Y, 0);
00266 if(player_x+EDGE_X >= scroll_x+VIEWPORT_WIDTH)
00267 new_x = min(scroll_x+SCROLL_INCR_X, FIELD_WIDTH-VIEWPORT_WIDTH);
00268 if(player_y+EDGE_Y >= scroll_y+VIEWPORT_HEIGHT)
00269 new_y = min(scroll_y+SCROLL_INCR_Y, FIELD_HEIGHT-VIEWPORT_HEIGHT);
00270
00271 if(new_x != scroll_x || new_y != scroll_y) {
00272 scroll_x = new_x;
00273 scroll_y = new_y;
00274 draw_current_map();
00275 }
00276 }
00277
00278
00279 void center_viewport(void)
00280 {
00281 int new_x, new_y;
00282
00283 new_x = player_x - VIEWPORT_WIDTH/2;
00284 new_y = player_y - VIEWPORT_HEIGHT/2;
00285 if(new_x+VIEWPORT_WIDTH>=FIELD_WIDTH) new_x=FIELD_WIDTH-VIEWPORT_WIDTH;
00286 if(new_y+VIEWPORT_HEIGHT>=FIELD_HEIGHT) new_y=FIELD_HEIGHT-VIEWPORT_HEIGHT;
00287 if(new_x < 0) new_x = 0;
00288 if(new_y < 0) new_y = 0;
00289
00290 scroll_x = new_x;
00291 scroll_y = new_y;
00292 }
00293
00294
00295
00296 static inline void _drawtile(int x, int y)
00297 {
00298 int xpos = (x-scroll_x)<<3;
00299 int ypos = (y-scroll_y)<<3;
00300
00301 if(x==player_x && y==player_y)
00302 draw_sprite(tile_sprites[ TILE_KYE ], xpos, ypos);
00303 else if(current_map.t[y][x].effect.sprite == EFFECT_NONE)
00304 draw_sprite(tile_sprites[ current_map.t[y][x].v ], xpos, ypos);
00305 else
00306 draw_sprite(effects[ current_map.t[y][x].effect.sprite ], xpos, ypos);
00307
00308 }
00309
00310
00311 void draw_current_map(void)
00312 {
00313 int xi, yi;
00314 int xmax, ymax;
00315
00316 clear_screen();
00317
00318 xmax = scroll_x + VIEWPORT_WIDTH;
00319 ymax = scroll_y + VIEWPORT_HEIGHT;
00320 if(xmax > FIELD_WIDTH) xmax = FIELD_WIDTH;
00321 if(ymax > FIELD_HEIGHT) ymax = FIELD_HEIGHT;
00322
00323
00324 if(FIELD_WIDTH < VIEWPORT_WIDTH) {
00325 draw_line(FIELD_WIDTH*8+1, 0, FIELD_WIDTH*8+1,
00326 ymax*8, A_NORMAL);
00327 }
00328 if(FIELD_HEIGHT < VIEWPORT_HEIGHT) {
00329 draw_line(0, ymax*8+1, FIELD_WIDTH*8+1,
00330 ymax*8+1, A_NORMAL);
00331 }
00332
00333 for(xi=scroll_x; xi<xmax; xi++)
00334 for(yi=scroll_y; yi<ymax; yi++)
00335 {
00336 _drawtile(xi, yi);
00337 }
00338
00339 draw_line(0, LCD_HEIGHT-11, (LCD_WIDTH-1), LCD_HEIGHT-11, A_NORMAL);
00340 redraw_status_bar();
00341 }
00342
00343
00344 void draw_map_tile(int x, int y)
00345 {
00346 if( x<scroll_x || y<scroll_y || x>=scroll_x+VIEWPORT_WIDTH ||
00347 y>=scroll_y+VIEWPORT_HEIGHT)
00348 return;
00349
00350 _drawtile(x, y);
00351 }
00352
00353
00354 void redraw_status_bar(void)
00355 {
00356 char buf[32];
00357 clear_line_range(LCD_HEIGHT-10, LCD_HEIGHT-1);
00358 draw_string("Diamonds: ", 2, LCD_HEIGHT-7, F_4x6);
00359 sprintf(buf, "%i", (int)num_diamonds);
00360 draw_string(buf, 40, LCD_HEIGHT-7, F_4x6);
00361 draw_string("Level: ", 100, LCD_HEIGHT-7, F_4x6);
00362 sprintf(buf, "%i", (int)(current_level_num+1));
00363 draw_string(buf, 125, LCD_HEIGHT-7, F_4x6);
00364 }
00365
00366
00367
00368 void advance(void)
00369 {
00370 int xi, yi;
00371 int xmax = FIELD_WIDTH;
00372 int ymax = FIELD_HEIGHT;
00373
00374
00375 for(yi=0; yi<ymax; yi++)
00376 for(xi=0; xi<xmax; xi++)
00377 {
00378 switch(current_map.t[yi][xi].v)
00379 {
00380 case TILE_SLIDER_S: move_slider(xi, yi, 0, 0, 1); break;
00381 case TILE_SLIDER_E: move_slider(xi, yi, 0, 1, 0); break;
00382 case TILE_SLIDER_N: move_slider(xi, yi, 0, 0, -1); break;
00383 case TILE_SLIDER_W: move_slider(xi, yi, 0, -1, 0); break;
00384 case TILE_ROCKY_S: move_slider(xi, yi, 1, 0, 1); break;
00385 case TILE_ROCKY_E: move_slider(xi, yi, 1, 1, 0); break;
00386 case TILE_ROCKY_N: move_slider(xi, yi, 1, 0, -1); break;
00387 case TILE_ROCKY_W: move_slider(xi, yi, 1, -1, 0); break;
00388
00389 case TILE_PUSHER_S: move_pusher(xi, yi, 0, 1); break;
00390 case TILE_PUSHER_E: move_pusher(xi, yi, 1, 0); break;
00391 case TILE_PUSHER_N: move_pusher(xi, yi, 0, -1); break;
00392 case TILE_PUSHER_W: move_pusher(xi, yi, -1, 0); break;
00393
00394 case TILE_MAGNET_NS:
00395 if(can_shove(xi, yi-2, 0, 1))
00396 shove(xi, yi-2, 0, 1);
00397 if(current_map.t[yi-2][xi].v==TILE_KYE && can_shove(xi,yi,0,-1))
00398 shove(xi, yi, 0, -1);
00399 if(can_shove(xi, yi+2, 0, -1))
00400 shove(xi, yi+2, 0, -1);
00401 if(current_map.t[yi+2][xi].v==TILE_KYE && can_shove(xi,yi,0,1))
00402 shove(xi, yi, 0, 1);
00403 break;
00404 case TILE_MAGNET_EW:
00405 if(can_shove(xi-2, yi, 1, 0))
00406 shove(xi-2, yi, 1, 0);
00407 if(current_map.t[yi][xi-2].v==TILE_KYE && can_shove(xi,yi,-1,0))
00408 shove(xi, yi, -1, 0);
00409 if(can_shove(xi+2, yi, -1, 0))
00410 shove(xi+2, yi, -1, 0);
00411 if(current_map.t[yi][xi+2].v==TILE_KYE && can_shove(xi,yi,1,0))
00412 shove(xi, yi, 1, 0);
00413 break;
00414
00415 case TILE_BLOB:
00416 case TILE_TWISTER:
00417 case TILE_GNASHER:
00418 case TILE_VIRUS:
00419 case TILE_SPIKE:
00420 if( round % MONSTMOVETIME == 0 )
00421 move_monster(xi, yi);
00422 break;
00423
00424 #ifdef ANIMATE_DIAMONDS
00425 case TILE_DIAMOND:
00426 if( current_map.t[yi][xi].effect.duration <= 1)
00427
00428 {
00429 if(current_map.t[yi][xi].effect.sprite == EFFECT_NONE) {
00430 current_map.t[yi][xi].effect.sprite = EFFECT_DIAMOND;
00431 current_map.t[yi][xi].effect.duration = 25+rand()%75;
00432 } else {
00433 current_map.t[yi][xi].effect.sprite = EFFECT_NONE;
00434 current_map.t[yi][xi].effect.duration = 25+rand()%75;
00435 }
00436 draw_map_tile(xi, yi);
00437 }
00438 break;
00439 #endif
00440 }
00441 }
00442
00443
00444 if( tile_is_monster(player_x-1, player_y)
00445 || tile_is_monster(player_x+1, player_y)
00446 || tile_is_monster(player_x, player_y-1)
00447 || tile_is_monster(player_x, player_y+1) )
00448 {
00449 message("Ouch!");
00450 restart_level();
00451 }
00452 }
00453
00454
00455 int tile_is_monster(int x, int y)
00456 {
00457 int tile = current_map.t[y][x].v;
00458 if(tile==TILE_BLOB || tile==TILE_VIRUS ||
00459 tile==TILE_TWISTER || tile==TILE_GNASHER ||
00460 tile==TILE_SPIKE )
00461 return 1;
00462 else
00463 return 0;
00464 }
00465
00466
00467
00468 void turn_sliders(void)
00469 {
00470 int xi, yi;
00471 for(yi=0; yi<FIELD_HEIGHT; yi++)
00472 for(xi=0; xi<FIELD_WIDTH; xi++)
00473 {
00474 switch(current_map.t[yi][xi].v)
00475 {
00476 case TILE_SLIDER_S:
00477 try_rotate(xi, yi, 0, 1, TILE_SLIDER_W, TILE_SLIDER_E);
00478 break;
00479 case TILE_SLIDER_E:
00480 try_rotate(xi, yi, 1, 0, TILE_SLIDER_S, TILE_SLIDER_N);
00481 break;
00482 case TILE_SLIDER_N:
00483 try_rotate(xi, yi, 0, -1, TILE_SLIDER_E, TILE_SLIDER_W);
00484 break;
00485 case TILE_SLIDER_W:
00486 try_rotate(xi, yi, -1, 0, TILE_SLIDER_N, TILE_SLIDER_S);
00487 break;
00488 case TILE_ROCKY_S:
00489 try_rotate(xi, yi, 0, 1, TILE_ROCKY_W, TILE_ROCKY_E);
00490 break;
00491 case TILE_ROCKY_E:
00492 try_rotate(xi, yi, 1, 0, TILE_ROCKY_S, TILE_ROCKY_N);
00493 break;
00494 case TILE_ROCKY_N:
00495 try_rotate(xi, yi, 0, -1, TILE_ROCKY_E, TILE_ROCKY_W);
00496 break;
00497 case TILE_ROCKY_W:
00498 try_rotate(xi, yi, -1, 0, TILE_ROCKY_N, TILE_ROCKY_S);
00499 break;
00500 }
00501 }
00502 }
00503
00504
00505 void try_rotate(int x, int y, int dx, int dy, int cw, int ccw)
00506 {
00507 if(current_map.t[y+dy][x+dx].v == TILE_TWIST_CW) {
00508 current_map.t[y][x].v = cw;
00509 draw_map_tile(x, y);
00510 }
00511 else if(current_map.t[y+dy][x+dx].v == TILE_TWIST_CCW) {
00512 current_map.t[y][x].v = ccw;
00513 draw_map_tile(x, y);
00514 }
00515 }
00516
00517
00518 void move_slider(int x, int y, int slippery, int dx, int dy)
00519 {
00520 int block;
00521 int movedir_1=0, movedir_2=0;
00522
00523 if(current_map.t[y][x].skip)
00524 return;
00525
00526 if(!is_in_bounds(x+dx, y+dy))
00527 return;
00528
00529 block = current_map.t[y+dy][x+dx].v;
00530
00531 if(block == TILE_EMPTY)
00532 {
00533 current_map.t[y+dy][x+dx].v = current_map.t[y][x].v;
00534 current_map.t[y+dy][x+dx].skip = 1;
00535 draw_map_tile(x+dx, y+dy);
00536 current_map.t[y][x].v = TILE_EMPTY;
00537 draw_map_tile(x, y);
00538 return;
00539 }
00540 else if(block == TILE_EXPLODER) {
00541 current_map.t[y][x].v = TILE_EMPTY;
00542 draw_map_tile(x, y);
00543 detonate(x+dx, y+dy);
00544 return;
00545 }
00546 else if(block == TILE_PIT) {
00547 current_map.t[y][x].v = TILE_EMPTY;
00548 draw_map_tile(x, y);
00549 current_map.t[y+dy][x+dx].v = TILE_EMPTY;
00550 draw_map_tile(x+dx, y+dy);
00551 return;
00552 }
00553 else if(block == TILE_TWIST_CW || block == TILE_TWIST_CCW)
00554 {
00555 try_rotate(x, y, dx, dy,
00556 rotate_cw(current_map.t[y][x].v),
00557 rotate_ccw(current_map.t[y][x].v));
00558 return;
00559 }
00560
00561 else if(!slippery) return;
00562
00563 switch(block)
00564 {
00565 case TILE_ROCKY_S:
00566 case TILE_ROCKY_E:
00567 case TILE_ROCKY_N:
00568 case TILE_ROCKY_W:
00569 case TILE_BOULDER:
00570 goto random_falloff;
00571 case TILE_WALL_3:
00572 if(dy==-1) goto negative_falloff;
00573 else if(dx==-1) goto negative_falloff;
00574 break;
00575 case TILE_WALL_9:
00576 if(dy==1) goto positive_falloff;
00577 else if(dx==-1) goto positive_falloff;
00578 break;
00579 case TILE_WALL_7:
00580 if(dy==1) goto negative_falloff;
00581 else if(dx==1) goto negative_falloff;
00582 break;
00583 case TILE_WALL_1:
00584 if(dy==-1) goto positive_falloff;
00585 else if(dx==1) goto positive_falloff;
00586 break;
00587 case TILE_WALL_2:
00588 if(dy==-1) goto random_falloff;
00589 else if(dx==1) goto positive_falloff;
00590 else if(dx==-1) goto negative_falloff;
00591 break;
00592 case TILE_WALL_6:
00593 if(dx==-1) goto random_falloff;
00594 else if(dy==1) goto positive_falloff;
00595 else if(dy==-1) goto negative_falloff;
00596 break;
00597 case TILE_WALL_8:
00598 if(dy==1) goto random_falloff;
00599 else if(dx==1) goto negative_falloff;
00600 else if(dx==-1) goto positive_falloff;
00601 break;
00602 case TILE_WALL_4:
00603 if(dx==1) goto random_falloff;
00604 else if(dy==1) goto negative_falloff;
00605 else if(dy==-1) goto positive_falloff;
00606 break;
00607 }
00608 return;
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 random_falloff:
00621 movedir_1 = movedir_2 = 1;
00622 goto evaluate_falloff;
00623 positive_falloff:
00624 movedir_1 = 1;
00625 goto evaluate_falloff;
00626 negative_falloff:
00627 movedir_2 = 1;
00628 goto evaluate_falloff;
00629
00630
00631
00632 evaluate_falloff:
00633 if(movedir_1 && is_in_bounds(x+dx+dy, y+dx+dy) &&
00634 current_map.t[y+dx][x+dy].v==TILE_EMPTY &&
00635 current_map.t[y+dx+dy][x+dx+dy].v==TILE_EMPTY)
00636 movedir_1 = 1;
00637 else
00638 movedir_1 = 0;
00639 if(movedir_2 && is_in_bounds(x+dx-dy, y-dx+dy) &&
00640 current_map.t[y-dx][x-dy].v==TILE_EMPTY &&
00641 current_map.t[y-dx+dy][x+dx-dy].v==TILE_EMPTY)
00642 movedir_2 = 1;
00643 else
00644 movedir_2 = 0;
00645
00646 if(movedir_1 && movedir_2) {
00647 if(rand()%2) movedir_1 = 0;
00648 else movedir_2 = 0;
00649 }
00650 if(movedir_1) {
00651 current_map.t[y+dx+dy][x+dx+dy].v = current_map.t[y][x].v;
00652 current_map.t[y+dx+dy][x+dx+dy].skip = 1;
00653 current_map.t[y][x].v = TILE_EMPTY;
00654 draw_map_tile(x+dx+dy, y+dx+dy);
00655 draw_map_tile(x, y);
00656 }
00657 else if(movedir_2) {
00658 current_map.t[y-dx+dy][x+dx-dy].v = current_map.t[y][x].v;
00659 current_map.t[y-dx+dy][x+dx-dy].skip = 1;
00660 current_map.t[y][x].v = TILE_EMPTY;
00661 draw_map_tile(x+dx-dy, y-dx+dy);
00662 draw_map_tile(x, y);
00663 }
00664
00665 }
00666
00667
00668 int rotate_cw(int tile)
00669 {
00670 switch(tile)
00671 {
00672 case TILE_SLIDER_N: return TILE_SLIDER_E;
00673 case TILE_SLIDER_E: return TILE_SLIDER_S;
00674 case TILE_SLIDER_S: return TILE_SLIDER_W;
00675 case TILE_SLIDER_W: return TILE_SLIDER_N;
00676 case TILE_ROCKY_N: return TILE_ROCKY_E;
00677 case TILE_ROCKY_E: return TILE_ROCKY_S;
00678 case TILE_ROCKY_S: return TILE_ROCKY_W;
00679 case TILE_ROCKY_W: return TILE_ROCKY_N;
00680 default: return tile;
00681 }
00682 }
00683
00684
00685 int rotate_ccw(int tile)
00686 {
00687 switch(tile)
00688 {
00689 case TILE_SLIDER_N: return TILE_SLIDER_W;
00690 case TILE_SLIDER_E: return TILE_SLIDER_N;
00691 case TILE_SLIDER_S: return TILE_SLIDER_E;
00692 case TILE_SLIDER_W: return TILE_SLIDER_S;
00693 case TILE_ROCKY_N: return TILE_ROCKY_W;
00694 case TILE_ROCKY_E: return TILE_ROCKY_N;
00695 case TILE_ROCKY_S: return TILE_ROCKY_E;
00696 case TILE_ROCKY_W: return TILE_ROCKY_S;
00697 default: return tile;
00698 }
00699 }
00700
00701
00702 void move_pusher(int x, int y, int dx, int dy)
00703 {
00704 if(current_map.t[y][x].skip)
00705 return;
00706
00707 if(current_map.gamerules == RULESET_DCKYE) {
00708 if(round%10 != 0) return;
00709 } else {
00710 if(round%5 != 0) return;
00711 }
00712
00713 if(!is_in_bounds(x+dx, y+dy) || current_map.t[y+dy][x+dx].v != TILE_EMPTY)
00714 {
00715 if(current_map.t[y+dy][x+dx].v == TILE_PIT) {
00716 current_map.t[y][x].v = TILE_EMPTY;
00717 draw_map_tile(x, y);
00718 current_map.t[y+dy][x+dx].v = TILE_EMPTY;
00719 draw_map_tile(x+dx, y+dy);
00720 return;
00721 }
00722
00723
00724 switch(current_map.t[y][x].v)
00725 {
00726 case TILE_PUSHER_W: current_map.t[y][x].v = TILE_PUSHER_E; break;
00727 case TILE_PUSHER_E: current_map.t[y][x].v = TILE_PUSHER_W; break;
00728 case TILE_PUSHER_N: current_map.t[y][x].v = TILE_PUSHER_S; break;
00729 case TILE_PUSHER_S: current_map.t[y][x].v = TILE_PUSHER_N; break;
00730 }
00731 draw_map_tile(x, y);
00732
00733 if(can_shove(x+dx, y+dy, dx, dy))
00734 shove(x+dx, y+dy, dx, dy);
00735 } else {
00736 shove(x, y, dx, dy);
00737 current_map.t[y+dy][x+dx].skip = 1;
00738 }
00739 }
00740
00741
00742 void move_monster(int x, int y)
00743 {
00744 int dx, dy;
00745 dx=dy=0;
00746
00747
00748
00749 if(current_map.t[y][x].skip) return;
00750
00751 if(rand()%2 == 0) {
00752
00753 switch(rand()%5) {
00754 case 0: dx=dy=0; break;
00755 case 1: dx=1, dy=0; break;
00756 case 2: dx=-1, dy=0; break;
00757 case 3: dx=0, dy=1; break;
00758 case 4: dx=0, dy=-1; break;
00759 }
00760 } else {
00761
00762 if(player_x>x) dx=1;
00763 else if(player_x<x) dx=-1;
00764 if(player_y>y) dy=1;
00765 if(player_y<y) dy=-1;
00766 if(!is_in_bounds(x+dx, y) || current_map.t[y][x+dx].v!=TILE_EMPTY) dx=0;
00767 if(!is_in_bounds(x, y+dy) || current_map.t[y+dy][x].v!=TILE_EMPTY) dy=0;
00768 if(dx && dy) {
00769 if( abs(player_y-y) > abs(player_x-x) )
00770 dx=0;
00771 else
00772 dy=0;
00773 }
00774 }
00775
00776 current_map.t[y][x].effect = animate_monster(x, y);
00777
00778 if((dx==0 && dy==0) || !is_in_bounds(x+dx, y+dy)
00779 || current_map.t[y+dy][x+dx].v != TILE_EMPTY) {
00780 draw_map_tile(x, y);
00781 return;
00782 }
00783 current_map.t[y+dy][x+dx].v = current_map.t[y][x].v;
00784 current_map.t[y+dy][x+dx].effect = current_map.t[y][x].effect;
00785 current_map.t[y+dy][x+dx].skip = 1;
00786 current_map.t[y][x].v = TILE_EMPTY;
00787 current_map.t[y][x].effect.sprite = EFFECT_NONE;
00788 current_map.t[y][x].effect.duration = 0;
00789 draw_map_tile(x+dx, y+dy);
00790 draw_map_tile(x, y);
00791 }
00792
00793
00794 effect_info animate_monster(int x, int y)
00795 {
00796 effect_info ret;
00797
00798 if((round/MONSTMOVETIME)%2 == 0) {
00799 ret.duration=0;
00800 ret.sprite = EFFECT_NONE;
00801 return ret;
00802 }
00803
00804 ret.duration = -1;
00805 switch(current_map.t[y][x].v)
00806 {
00807 case TILE_BLOB: ret.sprite=EFFECT_BLOB; break;
00808 case TILE_VIRUS: ret.sprite=EFFECT_VIRUS; break;
00809 case TILE_TWISTER: ret.sprite=EFFECT_TWISTER; break;
00810 case TILE_GNASHER: ret.sprite=EFFECT_GNASHER; break;
00811 case TILE_SPIKE: ret.sprite=EFFECT_SPIKE; break;
00812 }
00813 return ret;
00814 }
00815
00816
00817 void detonate(int x, int y)
00818 {
00819 int xi, yi;
00820
00821
00822
00823 if(is_in_bounds(x-1, y-1)) {
00824 current_map.t[y-1][x-1].effect.sprite = EFFECT_EXPLODE_TOPLEFT;
00825 current_map.t[y-1][x-1].effect.duration = EXPLODE_DURATION;
00826 }
00827 if(is_in_bounds(x, y-1)) {
00828 current_map.t[y-1][x].effect.sprite = EFFECT_EXPLODE_TOP;
00829 current_map.t[y-1][x].effect.duration = EXPLODE_DURATION;
00830 }
00831 if(is_in_bounds(x+1, y-1)) {
00832 current_map.t[y-1][x+1].effect.sprite = EFFECT_EXPLODE_TOPRIGHT;
00833 current_map.t[y-1][x+1].effect.duration = EXPLODE_DURATION;
00834 }
00835 if(is_in_bounds(x-1, y)) {
00836 current_map.t[y][x-1].effect.sprite = EFFECT_EXPLODE_LEFT;
00837 current_map.t[y][x-1].effect.duration = EXPLODE_DURATION;
00838 }
00839 if(is_in_bounds(x, y)) {
00840 current_map.t[y][x].effect.sprite = EFFECT_EXPLODE_CENTER;
00841 current_map.t[y][x].effect.duration = EXPLODE_DURATION;
00842 }
00843 if(is_in_bounds(x+1, y)) {
00844 current_map.t[y][x+1].effect.sprite = EFFECT_EXPLODE_RIGHT;
00845 current_map.t[y][x+1].effect.duration = EXPLODE_DURATION;
00846 }
00847 if(is_in_bounds(x-1, y+1)) {
00848 current_map.t[y+1][x-1].effect.sprite = EFFECT_EXPLODE_BOTLEFT;
00849 current_map.t[y+1][x-1].effect.duration = EXPLODE_DURATION;
00850 }
00851 if(is_in_bounds(x, y+1)) {
00852 current_map.t[y+1][x].effect.sprite = EFFECT_EXPLODE_BOTTOM;
00853 current_map.t[y+1][x].effect.duration = EXPLODE_DURATION;
00854 }
00855 if(is_in_bounds(x+1, y+1)) {
00856 current_map.t[y+1][x+1].effect.sprite = EFFECT_EXPLODE_BOTRIGHT;
00857 current_map.t[y+1][x+1].effect.duration = EXPLODE_DURATION;
00858 }
00859 current_map.t[y][x].v = TILE_PIT;
00860 for(yi=y-1; yi<=y+1; yi++)
00861 for(xi=x-1; xi<=x+1; xi++)
00862 {
00863 if(!is_in_bounds(xi, yi)) continue;
00864 if(current_map.t[yi][xi].v!=TILE_DIAMOND
00865 || current_map.t[yi][xi].v == TILE_KYE
00866 || current_map.t[yi][xi].v == TILE_PIT)
00867 current_map.t[yi][xi].v = TILE_EMPTY;
00868 draw_map_tile(xi, yi);
00869 }
00870 }
00871
00872
00873 void clear_effects(void)
00874 {
00875 int xi, yi;
00876 int xmax = FIELD_WIDTH;
00877 int ymax = FIELD_HEIGHT;
00878 for(yi=0; yi<ymax; yi++)
00879 for(xi=0; xi<xmax; xi++)
00880 {
00881 current_map.t[yi][xi].skip = 0;
00882
00883 if(current_map.t[yi][xi].effect.duration > 0)
00884 {
00885 if(current_map.t[yi][xi].effect.duration == 1) {
00886 current_map.t[yi][xi].effect.duration = 0;
00887 current_map.t[yi][xi].effect.sprite = EFFECT_NONE;
00888 draw_map_tile(xi, yi);
00889 } else {
00890 current_map.t[yi][xi].effect.duration--;
00891 }
00892 }
00893 }
00894 }
00895
00896
00897
00898 int is_in_bounds(int x, int y)
00899 {
00900 if(x<0 || y<0 || x>=FIELD_WIDTH || y>=FIELD_HEIGHT)
00901 return 0;
00902 else
00903 return 1;
00904 }
00905
00906
00907 int can_shove(int x, int y, int dx, int dy)
00908 {
00909 if(!is_in_bounds(x, y))
00910 return 0;
00911 if(!is_in_bounds(x+dx, y+dy))
00912 return 0;
00913
00914 switch(current_map.t[y+dy][x+dx].v)
00915 {
00916 case TILE_EMPTY:
00917 case TILE_PIT:
00918 break;
00919 default:
00920 return 0;
00921 }
00922
00923 switch(current_map.t[y][x].v)
00924 {
00925 case TILE_SLIDER_S: case TILE_SLIDER_E:
00926 case TILE_SLIDER_N: case TILE_SLIDER_W:
00927 case TILE_ROCKY_S: case TILE_ROCKY_E:
00928 case TILE_ROCKY_N: case TILE_ROCKY_W:
00929 case TILE_BLOCK: case TILE_BOULDER:
00930 case TILE_EXPLODER:
00931 case TILE_TWIST_CW: case TILE_TWIST_CCW:
00932 case TILE_STICKY_EW: case TILE_STICKY_NS:
00933 case TILE_MAGNET_EW: case TILE_MAGNET_NS:
00934 case TILE_PUSHER_W: case TILE_PUSHER_E:
00935 case TILE_PUSHER_N: case TILE_PUSHER_S:
00936 case TILE_VIRUS: case TILE_BLOB:
00937 case TILE_TWISTER: case TILE_GNASHER:
00938 case TILE_SPIKE:
00939 break;
00940 default:
00941 return 0;
00942 }
00943
00944 return 1;
00945 }
00946
00947
00948 void shove(int x, int y, int dx, int dy)
00949 {
00950 if(current_map.t[y+dy][x+dx].v == TILE_PIT)
00951 {
00952 current_map.t[y][x].v = TILE_EMPTY;
00953 current_map.t[y+dy][x+dx].v = TILE_EMPTY;
00954 } else {
00955 current_map.t[y+dy][x+dx].v = current_map.t[y][x].v;
00956 current_map.t[y][x].v = TILE_EMPTY;
00957 }
00958 if(current_map.t[y][x].effect.duration == -1) {
00959 current_map.t[y][x].effect.duration = 0;
00960 current_map.t[y][x].effect.sprite = 0;
00961 }
00962 draw_map_tile(x, y);
00963 draw_map_tile(x+dx, y+dy);
00964 }
00965
00966
00967
00968 int check_diamonds(void)
00969 {
00970 int xi, yi;
00971 int prev_diamonds = num_diamonds;
00972 num_diamonds = 0;
00973 for(yi=0; yi<FIELD_HEIGHT; yi++)
00974 for(xi=0; xi<FIELD_WIDTH; xi++)
00975 {
00976 if(current_map.t[yi][xi].v == TILE_DIAMOND)
00977 num_diamonds++;
00978 }
00979 if(num_diamonds==0) {
00980 advance_to_level = current_level_num+1;
00981 if(strlen(current_map.congrat) > 0) {
00982 message(current_map.congrat);
00983 }
00984 return 0;
00985 }
00986 if(num_diamonds != prev_diamonds)
00987 redraw_status_bar();
00988 return 1;
00989 }
00990
00991
00992
00993 void set_magnet_skips(void)
00994 {
00995 int xi, yi;
00996 int xmax = FIELD_WIDTH;
00997 int ymax = FIELD_HEIGHT;
00998 for(yi=0; yi<ymax; yi++)
00999 for(xi=0; xi<xmax; xi++)
01000 {
01001 if( current_map.t[yi][xi].v == TILE_STICKY_NS ||
01002 current_map.t[yi][xi].v == TILE_MAGNET_NS) {
01003 if(yi>0) current_map.t[yi-1][xi].skip = 1;
01004 if(yi+1<ymax) current_map.t[yi+1][xi].skip = 1;
01005 } else if( current_map.t[yi][xi].v == TILE_STICKY_EW ||
01006 current_map.t[yi][xi].v == TILE_MAGNET_EW) {
01007 if(xi>0) current_map.t[yi][xi-1].skip = 1;
01008 if(xi+1<xmax) current_map.t[yi][xi+1].skip = 1;
01009 }
01010 }
01011 }
01012
01013
01014
01015 void restart_level(void)
01016 {
01017 load_kyelib(current_level_num);
01018 begin_level();
01019 draw_current_map();
01020 }
01021
01022
01023 void begin_level(void)
01024 {
01025 int xi, yi;
01026
01027 round = 1;
01028
01029 for(yi=0; yi<FIELD_HEIGHT; yi++)
01030 for(xi=0; xi<FIELD_WIDTH; xi++)
01031 {
01032 current_map.t[yi][xi].effect.duration = 0;
01033 current_map.t[yi][xi].effect.sprite = EFFECT_NONE;
01034 if(current_map.t[yi][xi].v == TILE_KYE) {
01035 player_x = xi;
01036 player_y = yi;
01037 }
01038 }
01039
01040 center_viewport();
01041 check_diamonds();
01042 }
01043
01044