4
// Copyright 2007, 2008 Lancer-X/ASCEAI
6
// This file is part of Meritous.
8
// Meritous is free software: you can redistribute it and/or modify
9
// it under the terms of the GNU General Public License as published by
10
// the Free Software Foundation, either version 3 of the License, or
11
// (at your option) any later version.
13
// Meritous is distributed in the hope that it will be useful,
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
// GNU General Public License for more details.
18
// You should have received a copy of the GNU General Public License
19
// along with Meritous. If not, see <http://www.gnu.org/licenses/>.
28
#include <SDL_image.h>
44
#define MERITOUS_VERSION "v 1.1"
51
int WB_StartRange = 0;
52
int WB_EndRange = 1000000;
56
int voluntary_exit = 0;
58
int enter_room_x = 0, enter_room_y = 0;
60
int agate_knife_loc = -1;
63
char record_filename[256];
65
void DrawLevel(int off_x, int off_y, int hide_not_visited, int fog_of_war);
66
void DrawPlayer(int x, int y, int pl_dir, int pl_frm);
68
void ActivateRoom(int room);
71
void ReleaseCircuit();
72
void DrawCircle(int x, int y, int r, unsigned char c);
79
void draw_text(int x, int y, char *str, Uint8 tcol);
80
unsigned char font_data[128][8][8];
84
int key_held[10] = {0};
100
int checkpoints_found;
104
int player_lives = 5;
105
int player_lives_part = 0;
110
int player_walk_speed;
116
int opening_door_x, opening_door_y, opening_door_i = 0, opening_door_n;
122
//#define DEBUG_STATS 1
125
SDL_Surface *artifact_spr = NULL;
128
int circuit_fillrate;
129
int circuit_recoverrate;
131
int scroll_x, scroll_y;
138
int specialmessagetimer;
145
return (float)(rand()%256)*M_PI*2.0/256.0;
148
int UpgradePrice(int t);
150
void PlayerDefaultStats()
161
checkpoints_found = 0;
172
player_walk_speed = 5;
174
player_lives_part = 0;
184
circuit_fillrate = 2;
185
circuit_recoverrate = 3;
187
prv_player_room = -1;
190
specialmessagetimer = 0;
196
for (i = 0; i < 12; i++) {
203
circuit_fillrate = 24;
204
circuit_recoverrate = 24;
206
for (i = 0; i < 12; i++) {
214
void ScrollTo(int x, int y);
223
void SetGreyscalePalette();
224
void SetTonedPalette(float pct);
225
void SetTitlePalette(int curve_start, int curve_end);
226
void SetTitlePalette2(int t);
227
int TouchTile(int ix, int iy);
228
void SpecialTile(int x, int y);
229
void DrawRect(int x, int y, int w, int h, unsigned char c);
231
void DrawCircleEx(int x, int y, int r, int r2, unsigned char c);
233
void ThinLine(SDL_Surface *scr, int x1, int y1, int x2, int y2, Uint8 col);
234
void LockDoors(int r);
244
SDL_UpdateRect(screen, 0, 0, 0, 0);
246
if ((bmp >= WB_StartRange)&&(bmp < WB_EndRange)) {
247
sprintf(bmp_name, "v/bmp%d.bmp", bmp);
248
SDL_SaveBMP(screen, bmp_name);
256
static int last_ticks;
258
tick_delta = SDL_GetTicks() - last_ticks;
260
if (n == 0) n = frame_len;
262
if (tick_delta < n) {
263
SDL_Delay(n-tick_delta);
266
if (!game_paused) expired_ms += n;
268
last_ticks = SDL_GetTicks();
271
void WritePlayerData()
280
FWInt(magic_circuit);
283
FWInt(player_walk_speed);
285
FWInt(circuit_fillrate);
286
FWInt(circuit_recoverrate);
288
FWInt(player_shield);
289
FWInt(shield_recover);
292
FWInt(checkpoints_found);
295
FWInt(player_lives_part);
298
FWInt(agate_knife_loc);
300
for (i = 0; i < 12; i++) {
301
FWChar(artifacts[i]);
305
void ReadPlayerData()
309
expired_ms = FRInt();
314
magic_circuit = FRInt();
315
checkpoint_x = FRInt();
316
checkpoint_y = FRInt();
317
player_walk_speed = FRInt();
319
circuit_fillrate = FRInt();
320
circuit_recoverrate = FRInt();
322
player_shield = FRInt();
323
shield_recover = FRInt();
325
player_gems = FRInt();
326
checkpoints_found = FRInt();
328
player_lives = FRInt();
329
player_lives_part = FRInt();
330
current_boss = FRInt();
333
agate_knife_loc = FRInt();
335
for (i = 0; i < 12; i++) {
336
artifacts[i] = FRChar();
340
int min(int x, int y)
346
void DummyEventPoll()
352
int DungeonPlay(char *fname);
354
Uint8 Uint8_Bound(int c)
357
if (c>255) return 255;
361
int dist(int x1, int y1, int x2, int y2)
367
return sqrt((dx*dx)+(dy*dy));
379
int main(int argc, char **argv)
382
int executable_running = 1;
383
SDL_Surface *title, *title_pr, *asceai;
384
SDL_Surface *wm_icon;
385
Uint8 *src_p, *col_p;
390
int pulse[SCREEN_W * SCREEN_H];
391
int precalc_sine[400];
394
int can_continue = 0;
401
unsigned int stime = 0;
406
for (i = 1; i < argc; i++) {
407
if (!strcasecmp(argv[i], "fullscreen")) {
410
/* if (!strcasecmp(argv[i], "record")) {
412
strcpy(record_filename, argv[i+1]);
414
if (!strcasecmp(argv[i], "play")) {
416
strcpy(record_filename, argv[i+1]);
418
if (!strcasecmp(argv[i], "framedelay")) {
419
frame_len = atoi(argv[i+1]);
421
if (!strcasecmp(argv[i], "bmpwrite")) {
424
if (!strcasecmp(argv[i], "bmpstart")) {
425
WB_StartRange = atoi(argv[i+1]);
427
if (!strcasecmp(argv[i], "bmpend")) {
428
WB_EndRange = atoi(argv[i+1]);
433
if ((RECORDING) && (PLAYBACK)) {
438
record_file = fopen(record_filename, "wb");
441
fputc(stime & 0x000000FF, record_file);
442
fputc((stime & 0x0000FF00) >> 8, record_file);
443
fputc((stime & 0x00FF0000) >> 16, record_file);
444
fputc((stime & 0xFF000000) >> 24, record_file);
449
record_file = fopen(record_filename, "rb");
450
stime = fgetc(record_file);
451
stime |= fgetc(record_file) << 8;
452
stime |= fgetc(record_file) << 16;
453
stime |= fgetc(record_file) << 24;
458
asceai = IMG_Load("dat/i/asceai.png");
459
wm_icon = IMG_Load("dat/i/icon.png");
461
screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 8, SDL_SWSURFACE | (SDL_FULLSCREEN * fullscreen));
463
wm_mask_file = fopen("dat/d/icon_bitmask.dat", "rb");
464
fread(wm_mask, 1, 128, wm_mask_file);
465
fclose(wm_mask_file);
466
SDL_WM_SetCaption("~ m e r i t o u s ~", "MT");
467
SDL_WM_SetIcon(wm_icon, wm_mask);
471
for (i = 0; i < 400; i++) {
472
precalc_sine[i] = sin((float)i / 400 * M_PI * 2)*24+24;
476
for (i = 0; i < screen->w * screen->h; i++) {
480
pulse[i] = dist(x, y, SCREEN_W / 2, SCREEN_H / 2);
482
SetGreyscalePalette();
485
SDL_BlitSurface(asceai, NULL, screen, NULL);
487
for (i = 0; i < 75; i++) {
488
SetTitlePalette(i * 5 - 375, i * 5 - 120);
494
for (i = 0; i < 50; i++) {
495
SetTitlePalette(i * 5, 255 - (i * 5));
501
for (i = 0; i < 50; i++) {
502
SetTitlePalette(255, (i * 5)+5);
508
while (executable_running) {
518
maxoptions = 2 + can_continue;
520
title = IMG_Load("dat/i/title.png");
521
title_pr = IMG_Load("dat/i/title.png");
524
SetTitlePalette2(ticker_tick);
525
col_p = (Uint8 *)title_pr->pixels;
526
src_p = (Uint8 *)title->pixels;
527
if ((tick % 10) == 0) {
528
for (i = 0; i < 640*480; i++) {
529
*(col_p++) = Uint8_Bound(*(src_p++)+precalc_sine[(pulse[i]+tick)%400]);
532
SDL_BlitSurface(title_pr, NULL, screen, NULL);
534
draw_text(17, 156, MERITOUS_VERSION, 225 + sin((float)ticker_tick / 15)*30);
535
if (can_continue) draw_text((SCREEN_W - 14*8)/2, 310, "Continue", 255);
536
draw_text((SCREEN_W - 14*8)/2, 310 + can_continue*10, "New Game", 255);
537
draw_text((SCREEN_W - 14*8)/2, 320 + can_continue*10, "New Game (Wuss mode)", 255);
539
if (ticker_tick >= 30) {
540
draw_text((SCREEN_W - 14*8)/2 - 17, 310 + option * 10, "-", 205 + sin((float)ticker_tick / 5.0)*24);
541
draw_text((SCREEN_W - 14*8)/2 - 20, 310 + option * 10, " >", 205 + sin((float)ticker_tick / 5.0)*24);
542
draw_text((SCREEN_W - 14*8)/2 - 19, 310 + option * 10, " >", 190 + sin((float)ticker_tick / 5.0)*24);
543
draw_text((SCREEN_W - 14*8)/2 - 21, 310 + option * 10, " >", 190 + sin((float)ticker_tick / 5.0)*24);
544
draw_text((SCREEN_W - 14*8)/2 - 18, 310 + option * 10, " >", 165 + sin((float)ticker_tick / 5.0)*24);
545
draw_text((SCREEN_W - 14*8)/2 - 22, 310 + option * 10, " >", 165 + sin((float)ticker_tick / 5.0)*24);
550
if (ticker_tick++ > 30) {
553
if (key_held[K_UP]) {
555
if (option > 0) option--;
558
if (key_held[K_DN]) {
560
if (option < maxoptions-1) option++;
564
if (key_held[K_SP] || enter_pressed) {
570
if (voluntary_exit) {
571
executable_running = 0;
586
if (executable_running == 1) {
587
SDL_FreeSurface(title);
588
SDL_FreeSurface(title_pr);
589
if ((option == 0) && can_continue) {
590
DungeonPlay("SaveFile.sav");
592
if (option == (0 + can_continue)) {
611
// if (argc >= 2) DungeonPlay(argv[1]);
612
// else DungeonPlay("");
618
void DrawMeter(int x, int y, int n)
620
static SDL_Surface *meter = NULL;
621
SDL_Rect drawfrom, drawto;
623
meter = IMG_Load("dat/i/meter.png");
624
SDL_SetColorKey(meter, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
635
SDL_BlitSurface(meter, &drawfrom, screen, &drawto);
640
SDL_BlitSurface(meter, &drawfrom, screen, &drawto);
643
void ProgressBarScreen(int part, float progress, char *message, float t_parts)
645
memset(screen->pixels, 0, 640*480);
647
DrawRect(200, 217, 240, 50, 80);
648
DrawRect(202, 219, 236, 46, 20);
649
draw_text(232, 228, message, 255);
650
DrawRect(232, 244, 176, 12, 128);
651
DrawRect(234, 246, 172, 8, 0);
653
if ((int)(172.0 * progress / t_parts + (172.0 / t_parts * part)) > 0) {
654
DrawRect(234, 246, (int)(172.0 * progress / t_parts + (172.0 / t_parts * part)), 8, 200);
660
void LoadingScreen(int part, float progress)
664
if (game_load) t_parts = 5.0;
667
ProgressBarScreen(part, progress, "Loading... please wait", t_parts);
671
void SavingScreen(int part, float progress)
673
ProgressBarScreen(part, progress, "Saving... please wait", 4.0);
677
void Arc(SDL_Surface *s, int x, int y, int r, float dir)
681
float pdir, cdir, ndir;
683
int l_x = x, l_y = y;
684
int cx, cy, c1x, c1y, c2x, c2y;
686
bright = rand()%128+63;
690
pdir = dir + (float)(rand()%16)/16.0*2.0*(M_PI / 15.0);
691
ndir = dir - (float)(rand()%16)/16.0*2.0*(M_PI / 15.0);
692
cdir = dir + (float)(rand()%16)/16.0*2.0*(M_PI / 20.0) - (float)(rand()%16)/16.0*2.0*(M_PI / 20.0);
697
if (bright < 0) bright = 0;
698
if (bright > 255) bright = 255;
700
c1x = x + cos(pdir) * i;
701
c1y = y + sin(pdir) * i;
702
ThinLine(s, l_x, l_y, c1x, c1y, bright);
703
c2x = x + cos(ndir) * i;
704
c2y = y + sin(ndir) * i;
705
ThinLine(s, l_x, l_y, c2x, c2y, bright);
707
for (c = 0; c < 5; c++) {
708
DrawRect(x + cos(dir - (M_PI / 10.0) + (float)(rand()%16)/16.0*2.0*(M_PI / 10.0)) * i, y + sin(dir - (M_PI / 10.0) +
709
(float)(rand()%16)/16.0*2.0*(M_PI / 10.0)) * i, 1, 1, rand()%128+63);
713
cx = x + cos(cdir) * i;
714
cy = y + sin(cdir) * i;
715
ThinLine(s, c1x, c1y, cx, cy, bright);
716
ThinLine(s, c2x, c2y, cx, cy, bright);
723
int DungeonPlay(char *fname)
730
int rg_x, rg_y, rg_v;
741
LoadingScreen(0, 0.0);
750
PlayerDefaultStats();
754
//Paint(rooms[0].x+1, rooms[0].y+1, rooms[0].w-2, rooms[0].h-2, "dat/d/fbossroom.loc");
756
player_x = map.w * 32 / 2 - PLAYERW/2;
757
player_y = map.h * 32 / 2 - PLAYERH/2;
762
if (game_load) CloseFile();
765
for (i = 0; i < 3000; i++) {
766
if (rooms[i].s_dist > max_dist) {
767
max_dist = rooms[i].s_dist;
772
while (game_running) {
773
//sprintf(buf, "X: %d Y: %d", (player_x + PLAYERW/2)/32*32 + PLAYERW/2, (player_y + PLAYERH/2)/32*32 + PLAYERH/2);
774
//SDL_WM_SetCaption(buf, "MT");
776
if (player_dying > 30) {
779
if (player_hp <= 0) {
780
if (!training) player_lives--;
781
lost_gems = player_gems / 3;
782
player_gems -= lost_gems;
784
lost_gems = lost_gems * 95 / 100;
785
while (lost_gems > 0) {
786
rg_x = rooms[player_room].x * 32 + 32 + rand()%(rooms[player_room].w*32-64);
787
rg_y = rooms[player_room].y * 32 + 32 + rand()%(rooms[player_room].h*32-64);
788
rg_v = rand() % (lost_gems / 4 + 2);
789
CreateGem(rg_x, rg_y, player_room, rg_v);
796
if ( (current_boss == 3) && (boss_fight_mode != 0) ) {
797
player_x = enter_room_x;
798
player_y = enter_room_y;
801
player_x = checkpoint_x;
802
player_y = checkpoint_y;
805
CircuitBullets(player_x, player_y, 100);
806
player_hp = 3 + (player_shield == 30)*3;
813
circuit_size = 250 + 50*(circuit_fillrate + circuit_recoverrate);
815
if (magic_circuit > 0) {
816
circuit_range = (sqrt(magic_circuit + 1) * 6 + min(magic_circuit / 2, 50))*1.66;
817
if (artifacts[3]) circuit_range += circuit_range / 2.4;
818
} else circuit_range = -1;
819
player_room = GetRoom(player_x/32, player_y/32);
821
if (player_room != prv_player_room) {
822
SetTonedPalette((float)rooms[player_room].s_dist / (float)max_dist);
823
prv_player_room = player_room;
824
RecordRoom(player_room);
826
enter_room_x = player_x;
827
enter_room_y = player_y;
829
if (rooms[player_room].room_type == 2) {
831
LockDoors(player_room);
833
BossRoom(player_room);
835
if (((rooms[player_room].checkpoint)||(player_room==0))&&(!artifacts[11])) {
836
checkpoint_x = rooms[player_room].x * 32 + (rooms[player_room].w / 2 * 32) + 8;
837
checkpoint_y = rooms[player_room].y * 32 + (rooms[player_room].h / 2 * 32) + 4;
839
if (rooms[player_room].visited == 0) {
840
rooms[player_room].visited = 1;
843
if (explored == 3000) {
844
agate_knife_loc = player_room;
847
ActivateRoom(player_room);
851
if (last_killed != killed_enemies) {
852
SetTonedPalette((float)rooms[player_room].s_dist / (float)max_dist);
853
last_killed = killed_enemies;
855
if ((player_room == 0)&&(artifacts[11] == 1)) {
861
ScrollTo(player_x + PLAYERW/2 - 320, player_y + PLAYERH/2 - 240);
862
DrawLevel(scroll_x, scroll_y, 1, 1);
863
//DrawLevel(player_x + 8 - 320, player_y + 12 - 240);
865
if (player_dying == 0) {
868
if (magic_circuit > 0) {
869
if (player_dying == 0) {
870
if (circuit_release == 0) {
871
arcdir = RandomDir();
872
n_arcs = 1 + (circuit_size / 200 + 2) * magic_circuit / circuit_size;
873
for (i = 0; i < n_arcs; i++) {
874
Arc(screen, player_x - scroll_x + PLAYERW/2, player_y - scroll_y + PLAYERH/2, circuit_range, arcdir);
875
arcdir += (float)(rand()%16) / 16.0 * (M_PI*2/(float)n_arcs);
881
DrawPlayer(312, 228, player_dir, player_wlk / wlk_wait);
883
if (t % 2 == 0) DrawPlayer(312, 228, player_dir, player_wlk / wlk_wait);
889
if ((boss_fight_mode != 0)&&(boss_fight_mode < 23)&&(!game_paused)) {
893
if (!game_paused) MoveEntities();
895
if (boss_fight_mode == 2) {
899
if (rooms[player_room].room_type == 5) {
902
if ( (rooms[player_room].room_type == 6) && (current_boss == 3) ) {
905
if ((rooms[player_room].room_type == 4) && ((player_room % 1000) == 999)) {
908
if (player_room == agate_knife_loc) {
910
static float agate_t = 0.0;
911
static SDL_Surface *agate_knife = NULL;
916
room_x = rooms[player_room].x * 32 + 32;
917
room_y = rooms[player_room].y * 32 + 32;
918
room_w = rooms[player_room].w * 32 - 64;
919
room_h = rooms[player_room].h * 32 - 64;
922
if (agate_knife == NULL) {
923
agate_knife = IMG_Load("dat/i/agate.png");
924
SDL_SetColorKey(agate_knife, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
926
xpos = (int)((sin(agate_t * 1.33)*0.5+0.5) * (float)room_w) + room_x;
927
ypos = (int)((cos(agate_t * 0.7)*0.5+0.5) * (float)room_h) + room_y;
929
if (dist(player_x, player_y, xpos, ypos) < 20) {
930
agate_knife_loc = -1;
932
specialmessagetimer = 150;
933
SND_Pos("dat/a/crystal2.wav", 128, 0);
936
circuit_fillrate = 30;
937
circuit_recoverrate = 30;
940
draw_to.x = xpos - 16 - scroll_x;
941
draw_to.y = ypos - 16 - scroll_y;
943
SDL_BlitSurface(agate_knife, NULL, screen, &draw_to);
949
if (opening_door_i > 0) {
950
DrawArtifactOverhead(opening_door_n);
951
for (i = 0; i < 5; i++) {
952
j = i * 50 - 250 + (opening_door_i * 5);
954
DrawCircle(player_x - scroll_x, player_y - scroll_y, j, 255);
960
if (opening_door_i >= 100) {
962
Put(opening_door_x, opening_door_y, Get(opening_door_x, opening_door_y) - 38 + 13, GetRoom(opening_door_x, opening_door_y));
967
if (circuit_release > 0) {
968
DrawCircle(release_x - player_x + 320, release_y - player_y + 240, circuit_release * release_range / 20, sin((float)circuit_release / 20.0)*127+127);
970
CircuitBullets(release_x, release_y, circuit_release * release_range / 20);
971
//HurtEnemies(release_x, release_y, circuit_release * release_range / 20, release_str);
974
if (circuit_release > 24) {
976
HurtEnemies(release_x, release_y, release_range, release_str);
977
if (boss_fight_mode == 2) TryHurtBoss(release_x, release_y, release_range, release_str);
983
if (shield_hp < player_shield) {
984
shield_recover += player_shield * 3 / (3 - training - (player_shield == 30));
985
if (artifacts[1]) shield_recover += player_shield * 3 / (3 - training - (player_shield == 30));
986
if (shield_recover >= 50) {
988
shield_recover -= 50 - (player_shield == 30)*25;
994
DrawRect(0, 0, 640, 29, 0);
995
DrawRect(1, 1, 638, 27, 32);
996
DrawRect(2, 2, 636, 25, 64);
999
sprintf(buf, "Psi Crystals: %d", player_gems);
1000
draw_text(3, 3, buf, 200);
1001
sprintf(buf, "Explored: %.1f%% (%d/%d rooms)", (float)explored/30.0, explored, 3000);
1002
draw_text(3, 11, buf, 200);
1003
sprintf(buf, "Cleared: %.1f%% (%d/%d monsters)", (float)killed_enemies/(float)total_enemies*100.0, killed_enemies, total_enemies);
1004
draw_text(3, 19, buf, 200);
1006
draw_text(316, 3, "Reflect shield", (player_gems >= UpgradePrice(0))&&(player_shield!=30) ? (231 + (t%13)*2) : 200);
1007
DrawMeter(434, 3, player_shield);
1009
draw_text(316, 11, "Circuit charge", (player_gems >= UpgradePrice(1))&&(circuit_fillrate!=30) ? (231 + (t%13)*2) : 200);
1010
DrawMeter(434, 11, circuit_fillrate);
1012
draw_text(316, 19, "Circuit refill", (player_gems >= UpgradePrice(2))&&(circuit_recoverrate!=30) ? (231 + (t%13)*2) : 200);
1013
DrawMeter(434, 19, circuit_recoverrate);
1016
draw_text(80, 11-6, "Use the movement keys to locate a checkpoint. Press ENTER to", 240);
1017
draw_text(52, 11+6, "teleport to this checkpoint. Press ESCAPE or TAB once you are done.", 240);
1023
if (player_lives <= 99) {
1024
if (player_lives < 10) {
1025
sprintf(buf+1, " %d", player_lives);
1027
sprintf(buf+1, "%d", player_lives);
1030
sprintf(buf+1, "**");
1033
draw_text(615, 4, buf, 200);
1035
DrawRect(615, 13, 24, 4, 240);
1036
DrawRect(616, 14, 22, 2, 0);
1037
i = (player_lives_part * 22 / 88);
1039
DrawRect(616, 14, i, 2, 160 + (t % 40));
1043
if (player_shield != 30) {
1044
for (i = 0; i < player_hp; i++) {
1049
for (i = 0; i < (player_hp / 2); i++) {
1052
if ((player_hp % 2) == 1) {
1053
buf[(player_hp + 1) / 2 - 1] = 2;
1055
buf[(player_hp+1)/2]=0;
1058
draw_text(615, 18 - (5*training), buf, 200);
1060
DrawRect(0, 466, 640, 14, 0);
1061
DrawRect(1, 467, 638, 12, 32);
1062
DrawRect(2, 468, 636, 10, 64);
1067
SpecialTile((player_x+PLAYERW/2)/32, (player_y+PLAYERH/2)/32);
1069
if (map_enabled) DisplayAutomap();
1071
if ((boss_fight_mode != 0)&&(boss_fight_mode == 23)&&(!game_paused)) {
1074
if ( (boss_dlg != 0) && (!game_paused)) {
1078
if (game_paused && (!map_enabled) && (!voluntary_exit)) {
1079
for (i = 0; i < 10; i++) {
1080
DrawRect((640 - 6 * 8) / 2 - i, (480 - 8) / 2 - i, 6*8 + 2*i, 8 + 2*i, 64 - i*5);
1082
draw_text((640 - 6 * 8) / 2, (480 - 8) / 2, "Paused", 255);
1090
t_seconds = (expired_ms / 1000) % 60;
1091
t_minutes = ((expired_ms / 1000) / 60) % 60;
1092
t_hours = (((expired_ms / 1000) / 60) / 60) % 24;
1093
t_days = (((expired_ms / 1000) / 60) / 60) / 24;
1096
sprintf(buf, "%dd %dh %dm %ds", t_days, t_hours, t_minutes, t_seconds);
1099
sprintf(buf, "%dh %dm %ds", t_hours, t_minutes, t_seconds);
1101
sprintf(buf, "%dm %ds", t_minutes, t_seconds);
1104
draw_text(636 - strlen(buf)*8, 470, buf, 255);
1108
if (voluntary_exit) {
1109
DrawRect(152, 200, 336, 80, 128);
1110
DrawRect(160, 208, 320, 64, 64);
1111
draw_text((640 - 30 * 8) / 2, (480 - 8) / 2 - 4, "Are you sure you want to quit?", 255);
1112
draw_text((640 - 23 * 8) / 2, (480 - 8) / 2 + 4, "Press enter to confirm.", 255);
1123
if ((player_dying != 0) && (player_hp <= 1)) can_move = 0;
1124
if (rooms[player_room].room_type == 5)
1125
if (CanGetArtifact())
1126
if (Get((player_x+PLAYERW/2)/32, (player_y+PLAYERH/2)/32)==42)
1127
if (rooms[player_room].enemies == 0)
1130
if (rooms[player_room].room_type == 6)
1131
if (CanGetArtifact())
1132
if (PlayerDist(rooms[player_room].w * 16 + rooms[player_room].x * 32,
1133
rooms[player_room].h * 16 + rooms[player_room].y * 32) < 32)
1134
if (rooms[player_room].enemies == 0)
1135
if (current_boss == 3)
1138
if (scroll_home != 0) can_move = 0;
1139
if (boss_fight_mode == 1) can_move = 0;
1140
if (boss_fight_mode >= 3) can_move = 0;
1141
if (opening_door_i != 0) can_move = 0;
1142
if (game_paused) can_move = 0;
1155
if (key_held[K_UP] && !key_held[K_DN]) {
1156
iy -= player_walk_speed * (artifacts[4]?1.4:1);
1159
if (key_held[K_DN] && !key_held[K_UP]) {
1160
iy += player_walk_speed * (artifacts[4]?1.4:1);;
1164
if (key_held[K_LT] && !key_held[K_RT]) {
1165
ix -= player_walk_speed * (artifacts[4]?1.4:1);;
1166
if (!(key_held[K_UP] || key_held[K_DN])) {
1170
if (key_held[K_RT] && !key_held[K_LT]) {
1172
ix += player_walk_speed * (artifacts[4]?1.4:1);;
1173
if (!(key_held[K_UP] || key_held[K_DN])) {
1178
if ((key_held[K_SP])&&(magic_circuit >= 0)) {
1179
magic_circuit += (circuit_fillrate * (3+training+(circuit_fillrate==30))/3);
1181
if (magic_circuit < 0) {
1182
magic_circuit += (circuit_recoverrate * (3+training+(circuit_recoverrate==30))/3);
1183
if (magic_circuit > 0) magic_circuit = 0;
1185
if (magic_circuit > 0) {
1191
if (magic_circuit > circuit_size) magic_circuit = circuit_size;
1193
if ((ix!=player_x)||(iy!=player_y)) {
1194
// Are we changing to a new square?
1195
if (((player_x / 32)!=((ix+off_x) / 32)) || ((player_y / 32)!=((iy+off_y) / 32))) {
1196
//printf("%d\n", tile);
1197
if (TouchTile(ix, iy)) {
1198
player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
1200
if (TouchTile(player_x, iy)) {
1201
player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
1203
if (TouchTile(ix, player_y)) {
1204
player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
1205
if (off_x > 0) player_dir = 2;
1206
else player_dir = 3;
1215
player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
1220
if ((t % (33 * 10))==(33 * 10 - 1)) {
1224
if (voluntary_exit && enter_pressed) {
1230
if ((player_lives == 0) && (!training)) {
1243
if ((player_lives == 0) && (!training)) {
1244
SDL_FillRect(screen, NULL, 0);
1245
draw_text(252, 236, "G A M E O V E R", 255);
1257
nd = rooms[player_room].s_dist + 1;
1259
for (i = 0; i < 3000; i++) {
1260
if (rooms[i].s_dist == nd) {
1261
player_x = rooms[i].x * 32 + 64;
1262
player_y = rooms[i].y * 32 + 64;
1267
void CancelVoluntaryExit()
1269
if (voluntary_exit) {
1278
static SDL_Event event;
1279
int pressed_tab = 0;
1282
db = fgetc(record_file);
1283
db |= fgetc(record_file) << 8;
1285
key_held[K_UP] = (db & 0x0001)>0;
1286
key_held[K_DN] = (db & 0x0002)>0;
1287
key_held[K_LT] = (db & 0x0004)>0;
1288
key_held[K_RT] = (db & 0x0008)>0;
1289
key_held[K_SP] = (db & 0x0010)>0;
1290
enter_pressed = (db & 0x0020)>0;
1291
map_enabled = (db & 0x0040)>0;
1292
game_running = (db & 0x0080)>0;
1293
game_paused = (db & 0x0100)>0;
1294
voluntary_exit = (db & 0x0200)>0;
1295
pressed_tab = (db & 0x0400)>0;
1296
tele_select = (db & 0x0800)>0;
1302
c_scroll_x = player_x;
1303
c_scroll_y = player_y;
1307
while (SDL_PollEvent(&event)) {
1308
if (event.type == SDL_KEYDOWN) {
1309
switch (event.key.keysym.sym) {
1313
CancelVoluntaryExit();
1318
CancelVoluntaryExit();
1323
CancelVoluntaryExit();
1328
CancelVoluntaryExit();
1332
CancelVoluntaryExit();
1343
voluntary_exit ^= 1;
1344
game_paused = voluntary_exit;
1355
game_paused = map_enabled;
1356
c_scroll_x = player_x;
1357
c_scroll_y = player_y;
1359
CancelVoluntaryExit();
1362
CancelVoluntaryExit();
1367
CancelVoluntaryExit();
1375
circuit_recoverrate = 20;
1376
circuit_fillrate = 20;
1382
for (j = 0; j < 1; j++) {
1383
for (i = 0; i < 50000; i++) {
1385
if (rooms[n].visited == 0) {
1386
player_x = rooms[n].x * 32 + rooms[n].w * 16;
1387
player_y = rooms[n].y * 32 + rooms[n].h * 16;
1388
rooms[n].visited = 1;
1400
for (i = 0; i < 8; i++) {
1403
for (i = 8; i < 11; i++) {
1413
expired_ms = 1000000;
1421
if (event.type == SDL_KEYUP) {
1422
switch (event.key.keysym.sym) {
1446
if (event.type == SDL_QUIT) {
1454
db |= 0x0001 * key_held[K_UP];
1455
db |= 0x0002 * key_held[K_DN];
1456
db |= 0x0004 * key_held[K_LT];
1457
db |= 0x0008 * key_held[K_RT];
1458
db |= 0x0010 * key_held[K_SP];
1459
db |= 0x0020 * enter_pressed;
1460
db |= 0x0040 * map_enabled;
1461
db |= 0x0080 * game_running;
1462
db |= 0x0100 * game_paused;
1463
db |= 0x0200 * voluntary_exit;
1464
db |= 0x0400 * pressed_tab;
1465
db |= 0x0800 * tele_select;
1467
fputc(db & 0x00FF, record_file);
1468
fputc((db & 0xFF00)>>8, record_file);
1474
void DrawLevel(int off_x, int off_y, int hide_not_visited, int fog_of_war)
1476
static SDL_Surface *tiles = NULL;
1477
static SDL_Surface *fog = NULL;
1479
SDL_Rect tilerec, screenrec;
1481
int resolve_x, resolve_y;
1483
DrawRect(0, 0, 640, 480, 255);
1485
if (tiles == NULL) {
1486
tiles = IMG_Load("dat/i/tileset.png");
1487
fog = IMG_Load("dat/i/tileset.png");
1491
for (i = 0; i < fog->w*fog->h; i++) {
1492
*pp = *pp / 2 + 128;
1496
for (y = 0; y < 16; y++) {
1497
for (x = 0; x < 21; x++) {
1498
resolve_x = x + (off_x/32);
1499
resolve_y = y + (off_y/32);
1501
if ((GetVisited(resolve_x, resolve_y) == 0)&&(player_room != GetRoom(resolve_x, resolve_y))&&(hide_not_visited)) {
1502
tilerec.x = 17 * 32;
1504
tilerec.x = Get(resolve_x, resolve_y) * 32;
1510
screenrec.x = x*32 - ( (off_x) %32);
1511
screenrec.y = y*32 - ( (off_y) %32);
1513
if ((player_room != GetRoom(resolve_x, resolve_y))&&(fog_of_war)) {
1514
SDL_BlitSurface(fog, &tilerec, screen, &screenrec);
1516
SDL_BlitSurface(tiles, &tilerec, screen, &screenrec);
1522
void DrawPlayer(int x, int y, int pl_dir, int pl_frm)
1524
static SDL_Surface *playersprite = NULL;
1525
SDL_Rect playerrec, screenrec;
1527
if (playersprite == NULL) {
1528
playersprite = IMG_Load("dat/i/player.png");
1529
SDL_SetColorKey(playersprite, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
1532
playerrec.x = pl_frm * 16;
1533
playerrec.y = pl_dir * 24;
1540
SDL_BlitSurface(playersprite, &playerrec, screen, &screenrec);
1543
void SetGreyscalePalette()
1545
SDL_Color grey[256];
1551
for (i = 0; i < 256; i++) {
1552
grey[i].r = grey[i].g = grey[i].b = i;
1555
for (i = 0; i < 256; i++) {
1556
ip = (float)i / 255.0;
1557
pal[i].r = (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255;
1558
pal[i].g = (sin(ip * M_PI / 2.0) * 255 + i) / 2;
1559
pal[i].b = sin(ip * M_PI / 2.0) * 255;
1562
SDL_SetPalette(screen, SDL_LOGPAL, grey, 0, 256);
1563
SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
1566
void SetTonedPalette(float dct)
1569
float pct = 1.0 - dct;
1570
float rp_dct, rp_pct;
1576
ec = rooms[player_room].enemies;
1579
rp_dct = (float)ec / 50.0;
1583
rp_pct = 1.0 - rp_dct;
1585
if ( (player_room == 0) && (current_boss == 3) && (boss_fight_mode >= 3) ) {
1586
if (boss_fight_mode == 23) {
1587
for (i = 0; i < 256; i++) {
1594
pct = sin((float)tk / 20.0 * M_PI) * (0.5 - (float)(boss_fight_mode-3)*0.025) + (0.5 - (float)(boss_fight_mode-3)*0.025);
1596
if (magic_circuit < 0.1) pct = 1.0;
1598
for (i = 0; i < 256; i++) {
1599
ip = (float)i / 255.0;
1600
pal[i].r = 255 - (255 - (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255)*pct;
1601
pal[i].g = 255 - (255 - i)*pct;
1602
pal[i].b = 255 - (255 - sin(ip * M_PI / 2.0) * 255) * pct;
1611
if (artifacts[11]) {
1612
if (player_room == 0) {
1614
pct = sin((float)tk / 33.0 * M_PI) * 0.5 + 0.5;
1615
for (i = 0; i < 256; i++) {
1617
pal[i].g = (i / 3)*pct;
1618
pal[i].b = (i * 2 / 3)*pct;
1621
for (i = 0; i < 256; i++) {
1622
ip = (float)i / 255.0;
1625
pal[i].b = (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255 * dct;
1629
if ( (current_boss == 3) && (player_shield == 30) && (player_room == 0)) {
1630
if (boss_lives <= 1) {
1632
for (i = 0; i < 256; i++) {
1633
pct = sin((float) (tk + i) / 24.0 * M_PI) * 0.5 + 0.5;
1635
pal[i].r = (i * 0.5 + 128)*pct;
1636
pal[i].g = i * 0.5 + 128;
1637
pal[i].b = (i * 0.5 + 128)*pct;
1642
for (i = 0; i < 256; i++) {
1643
ip = (float)i / 255.0;
1644
pal[i].r = (((cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255)*pct + i*dct)*rp_pct + (sin(ip * M_PI / 2.0) * 207 + 48)*rp_dct;
1645
pal[i].g = (i)*rp_pct + ((cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255)*rp_dct;
1646
pal[i].b = ((sin(ip * M_PI / 2.0) * 255 * pct)+((cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255 * dct))*rp_pct + ((cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255)*rp_dct;
1651
SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
1654
void SetTitlePalette(int curve_start, int curve_end)
1660
for (i = 0; i < 256; i++) {
1661
ec = (i - curve_start) * 255 / (curve_end-curve_start);
1663
if (ec > 255) ec = 255;
1670
SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
1673
void SetTitlePalette2(int t)
1682
bright = 1 - ((float)t / 30.0);
1683
if (bright < 0.0) bright = 0.0;
1684
b_coeff = 1 - bright;
1686
for (i = 0; i < 256; i++) {
1687
ip = (float)i / 255.0;
1688
pal[i].r = (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255 * b_coeff + 255*bright;
1689
pal[i].g = (sin(ip * M_PI / 2.0) * 255 + i) / 2 * b_coeff + 255*bright;
1690
pal[i].b = sin(ip * M_PI / 2.0) * 255 * b_coeff + 255*bright;
1693
SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
1696
int IsSolid(unsigned char tile)
1698
return TileData[tile].Is_Solid;
1701
void ActivateBossDoor(int x, int y)
1703
static int bd_timer = 0;
1707
if (rooms[GetRoom(x+1, y)].room_type == 2) {
1710
if (rooms[GetRoom(x-1, y)].room_type == 2) {
1713
if (rooms[GetRoom(x, y+1)].room_type == 2) {
1716
if (rooms[GetRoom(x, y-1)].room_type == 2) {
1721
if (artifacts[8 + rooms[GetRoom(bx, by)].room_param]) {
1725
opening_door_n = rooms[GetRoom(bx, by)].room_param;
1726
if ((SDL_GetTicks() - bd_timer) > 100) {
1727
SND_Pos("dat/a/crystal2.wav", 100, 0);
1728
bd_timer = SDL_GetTicks();
1733
int TouchTile(int ix, int iy)
1740
for (i = 0; i < 4; i++) {
1744
tile = Get((ix+off_x)/32, (iy+off_y)/32);
1750
ActivateBossDoor((ix+off_x)/32, (iy+off_y)/32);
1754
player_x = (ix + off_x) / 32 * 32 + 8;
1755
player_y = (iy/32 + 2)*32 + 32;
1759
player_x = (ix + off_x) / 32 * 32 + 8;
1760
player_y = (iy/32 - 2)*32 + 8;
1764
player_x = (ix/32 + 2)*32 + 32;
1765
player_y = (iy + off_y) / 32 * 32 + 4;
1769
player_x = (ix/32 - 2)*32 + 16;
1770
player_y = (iy + off_y) / 32 * 32 + 4;
1774
if (TileData[tile].Is_Solid) ret = 0;
1788
FILE *font_data_file;
1790
font_data_file = fopen("dat/d/font.dat", "rb");
1792
for (chr = 0; chr < 128; chr++) {
1793
for (y = 0; y < 8; y++) {
1794
for (x = 0; x < 8; x++) {
1795
font_data[chr][x][y] = fgetc(font_data_file);
1800
fclose(font_data_file);
1803
void draw_char(int cur_x, int cur_y, int c, Uint8 tcol)
1808
for (py = 0; py < 8; py++) {
1809
pix = (Uint8 *)screen->pixels;
1810
pix += (py+cur_y)*screen->w;
1813
if ((cur_x >= 0)&&(py+cur_y >= 0)&&(cur_x < screen->w-8)&&(py+cur_y < screen->h)) {
1814
for (px = 0; px < 8; px++) {
1815
if (font_data[c][px][py] == 255) {
1818
if ((font_data[c][px][py] < 255)&&(font_data[c][px][py] > 0)) {
1819
*pix = ((int)tcol * font_data[c][px][py] / 256) + ((int)*pix * (256-font_data[c][px][py]) / 256);
1827
void draw_text(int x, int y, char *str, Uint8 tcol)
1829
int c, cur_x, cur_y;
1840
draw_char(cur_x, cur_y, c, tcol);
1846
void draw_text_ex(int x, int y, char *str, Uint8 tcol, SDL_Surface *srf)
1849
int c, cur_x, cur_y, px, py;
1860
for (py = 0; py < 8; py++) {
1861
pix = (Uint8 *)srf->pixels;
1862
pix += (py+cur_y)*srf->w;
1864
for (px = 0; px < 8; px++) {
1865
if (font_data[c][px][py]) {
1876
void LockDoors(int r)
1878
//printf("Locking room %d...", r);
1884
for (y = 0; y < rooms[r].h; y++) {
1885
for (x = 0; x < rooms[r].w; x++) {
1886
rx = x + rooms[r].x;
1887
ry = y + rooms[r].y;
1890
if ((rt >= 13) && (rt <= 16)) {
1892
Put(rx, ry, rt - 13 + 21, r);
1896
//printf("locked %d doors\n", rcount);
1899
void ActivateRoom(int room)
1901
//printf("Activating room %d (type %d)\n", room, rooms[room].room_type);
1902
if (rooms[room].checkpoint) {
1903
checkpoints_found++;
1905
if (rooms[room].room_type == 3) {
1909
ActivateEnemies(room);
1912
void DrawRect(int x, int y, int w, int h, unsigned char c)
1921
SDL_FillRect(screen, &r, c);
1929
if (magic_circuit != 0) {
1930
DrawRect(110, 469, 8+abs(magic_circuit) * vd / circuit_size, 9, (magic_circuit > 0) ? 159 : 72);
1931
DrawRect(111, 470, 6+abs(magic_circuit) * vd / circuit_size, 7, (magic_circuit > 0) ? 183 : 80);
1932
DrawRect(112, 471, 4+abs(magic_circuit) * vd / circuit_size, 5, (magic_circuit > 0) ? 207 : 96);
1933
DrawRect(113, 472, 2+abs(magic_circuit) * vd / circuit_size, 3, (magic_circuit > 0) ? 231 : 112);
1934
DrawRect(114, 473, abs(magic_circuit) * vd / circuit_size, 1, (magic_circuit > 0) ? 255 : 128);
1936
sprintf(buf, "%.1f", fabs((float)magic_circuit / 100.0));
1937
draw_text(115, 470, buf, 0);
1938
draw_text(3, 469, "Psi Circuit", 200);
1941
void ReleaseCircuit()
1943
circuit_release = 1;
1944
release_range = circuit_range;
1945
release_x = player_x;
1946
release_y = player_y;
1947
release_str = magic_circuit;
1948
if (circuit_fillrate==30) {
1949
release_str *= 1.25;
1952
SND_CircuitRelease(release_str);
1953
magic_circuit *= -1;
1956
void DrawCircle(int x, int y, int r, unsigned char c)
1960
int len_x, outer_len_x, inner_len_x;
1962
int inner_r = r - 10;
1963
if (inner_r < 1) inner_r = 1;
1967
for (circ_y = 0; circ_y < r; circ_y++) {
1968
if (circ_y < (r-10)) {
1969
outer_len_x = sqrt(r*r - circ_y*circ_y);
1970
inner_len_x = sqrt((r-10)*(r-10) - circ_y*circ_y);
1971
DrawRect(x - outer_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
1972
DrawRect(x + inner_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
1973
DrawRect(x - outer_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
1974
DrawRect(x + inner_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
1976
len_x = sqrt(r*r - circ_y*circ_y);
1978
DrawRect(x - len_x, y - circ_y, len_x*2, 1, c);
1979
DrawRect(x - len_x, y + circ_y, len_x*2, 1, c);
1984
void DrawCircleEx(int x, int y, int r, int r2, unsigned char c)
1988
int len_x, outer_len_x, inner_len_x;
1992
if (inner_r < 1) inner_r = 1;
1998
for (circ_y = 0; circ_y < r; circ_y++) {
1999
if (circ_y < (r-diffi)) {
2000
outer_len_x = sqrt(r*r - circ_y*circ_y);
2001
inner_len_x = sqrt((r-diffi)*(r-diffi) - circ_y*circ_y);
2002
DrawRect(x - outer_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
2003
DrawRect(x + inner_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
2004
DrawRect(x - outer_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
2005
DrawRect(x + inner_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
2007
len_x = sqrt(r*r - circ_y*circ_y);
2009
DrawRect(x - len_x, y - circ_y, len_x*2, 1, c);
2010
DrawRect(x - len_x, y + circ_y, len_x*2, 1, c);
2023
if (player_shield == 0) return;
2024
if (shield_hp == 0) return;
2028
belts = s_size - 15;
2031
DrawCircleEx(320, 240, 28+s_size, 28-s_size, 128 + (shield_hp*127/player_shield) - (50*(shield_hp<player_shield) + shield_recover) - 45 + ((t%4)*15));
2033
for (i = 0; i < belts; i++) {
2034
bpos = 13 + (30 * (i+1) / (belts+1));
2035
DrawCircleEx(320, 240, bpos + 1, bpos - 1, ((i+t)%6*12));
2043
int UpgradePrice(int t)
2048
price = (100 - training*50) * player_shield + (5<<player_shield) * (5 - training*2);
2051
price = (80 - training*40) * circuit_fillrate + (5<<circuit_fillrate) * (4 - training*2);
2054
price = (80 - training*40) * circuit_recoverrate + (5<<circuit_recoverrate) * (4 - training*2);
2064
void RoomTreasure(int room, int typ)
2067
int given_treasure = 0;
2071
treasure = rooms[room].room_param;
2072
artifacts[treasure] = 1;
2073
specialmessage = treasure + 1;
2074
specialmessagetimer = 30;
2075
SND_Pos("dat/a/crystal2.wav", 128, 0);
2079
while (!given_treasure) {
2080
treasure = rand() % 4;
2084
specialmessage = 20;
2085
player_gems += rand()%((1 << (rooms[room].s_dist / 7)) * 1500);
2087
SND_Pos("dat/a/tone.wav", 128, 0);
2090
if (player_shield < 25) {
2091
specialmessage = 10;
2094
SND_Pos("dat/a/tone.wav", 128, 0);
2098
if (circuit_fillrate < 25) {
2099
specialmessage = 11;
2100
circuit_fillrate += 1;
2102
SND_Pos("dat/a/tone.wav", 128, 0);
2106
if (circuit_recoverrate < 25) {
2107
specialmessage = 12;
2108
circuit_recoverrate += 1;
2110
SND_Pos("dat/a/tone.wav", 128, 0);
2117
specialmessagetimer = 30;
2121
int GetNearestCheckpoint(int nx, int ny)
2124
int nearest_checkpoint = -1;
2125
int nearest_dist = 10000000;
2126
int cp_x, cp_y, cp_dist;
2127
int room_chk[3000] = {0};
2130
i = GetRoom(nx/32, ny/32);
2133
if ((rooms[i].checkpoint != 0)&&(rooms[i].visited!=0)) {
2134
nearest_checkpoint = i;
2137
if (nearest_checkpoint == -1) {
2139
for (y = 0; y < 54;) {
2140
for (x = 0; x < 54;) {
2141
rx = nx/32 - 27 + x;
2142
ry = ny/32 - 27 + y;
2144
i = GetRoom(rx, ry);
2146
if (room_chk[i] == 0) {
2148
if ((rooms[i].checkpoint != 0)&&(rooms[i].visited!=0)) {
2149
cp_x = rooms[i].x * 32 + rooms[i].w * 16;
2150
cp_y = rooms[i].y * 32 + rooms[i].h * 16;
2151
cp_dist = dist(cp_x, cp_y, nx, ny);
2152
if (cp_dist < nearest_dist) {
2153
nearest_dist = cp_dist;
2154
nearest_checkpoint = i;
2166
return nearest_checkpoint;
2169
void TeleportPlayerToRoom(int c_room)
2175
player_x = rooms[c_room].x * 32 + (rooms[c_room].w / 2 * 32) + 8;
2176
player_y = rooms[c_room].y * 32 + (rooms[c_room].h / 2 * 32) + 4;
2178
c_scroll_x = player_x;
2179
c_scroll_y = player_y;
2184
void TeleportPlayerToNextRoom()
2187
c_room = (player_room + 1) % 3000;
2188
while (! ((rooms[c_room].checkpoint!=0)&&(rooms[c_room].visited!=0))) {
2189
c_room = (c_room + 1) % 3000;
2196
player_x = rooms[c_room].x * 32 + (rooms[c_room].w / 2 * 32) + 8;
2197
player_y = rooms[c_room].y * 32 + (rooms[c_room].h / 2 * 32) + 4;
2199
c_scroll_x = player_x;
2200
c_scroll_y = player_y;
2204
void ActivateTile(unsigned char tile, int x, int y)
2211
if (artifacts[11]) break;
2213
c_room = GetNearestCheckpoint(c_scroll_x, c_scroll_y);
2216
if (c_room == player_room) {
2217
TeleportPlayerToNextRoom();
2219
TeleportPlayerToRoom(c_room);
2227
c_scroll_x = player_x;
2228
c_scroll_y = player_y;
2233
RoomTreasure(GetRoom(x, y), (x+y)%2);
2234
Put(x, y, 27, GetRoom(x, y));
2237
if (player_shield >= 24) return;
2238
if (player_gems >= UpgradePrice(0)) {
2239
player_gems -= UpgradePrice(0);
2241
SND_Pos("dat/a/crystal.wav", 128, 0);
2245
if (circuit_fillrate >= 24) return;
2246
if (player_gems >= UpgradePrice(1)) {
2247
player_gems -= UpgradePrice(1);
2248
circuit_fillrate += 1;
2249
SND_Pos("dat/a/crystal.wav", 128, 0);
2253
if (circuit_recoverrate >= 24) return;
2254
if (player_gems >= UpgradePrice(2)) {
2255
player_gems -= UpgradePrice(2);
2256
circuit_recoverrate += 1;
2257
SND_Pos("dat/a/crystal.wav", 128, 0);
2265
SND_Pos("dat/a/crystal.wav", 80, 0);
2274
int nearest = 1000000;
2280
int bosses_defeated = current_boss;
2283
int pdir_1t = 0, pdir_2t = 0;
2285
rplx = player_x + PLAYERW/2;
2286
rply = player_y + PLAYERH/2;
2287
// Find the nearest SIGNIFICANT LOCATION for the player
2289
// Look at the three artifacts
2290
// Unless the player is going for the place of power
2292
if (current_boss < 3) {
2293
for (i = 0; i < 3; i++) {
2294
// Has the player got this artifact already?
2295
if (artifacts[8+i] == 0) { // no
2296
// Has the player already destroyed the boss?
2297
if (rooms[i * 1000 + 999].room_type == 2) { // no
2298
// Can the player get the artifact?
2299
if (CanGetArtifact()) {
2300
// Point player to this artifact room, if it is the nearest
2301
loc_x = rooms[i * 1000 + 499].x * 32 + rooms[i * 1000 + 499].w * 16;
2302
loc_y = rooms[i * 1000 + 499].y * 32 + rooms[i * 1000 + 499].h * 16;
2303
cdist = dist(rplx, rply, loc_x, loc_y);
2304
if (cdist < nearest) {
2306
n_room = i * 1000 + 499;
2310
} else { // has artifact
2311
// Has the player already destroyed the boss?
2312
if (rooms[i * 1000 + 999].room_type == 2) { // no
2313
// Point player to the boss room, if it is the nearest
2314
loc_x = rooms[i * 1000 + 999].x * 32 + rooms[i * 1000 + 999].w * 16;
2315
loc_y = rooms[i * 1000 + 999].y * 32 + rooms[i * 1000 + 999].h * 16;
2316
cdist = dist(rplx, rply, loc_x, loc_y);
2317
if (cdist < nearest) {
2319
n_room = i * 1000 + 999;
2327
// If, on the other hand, the player has destroyed all three bosses, point them towards the
2329
if (bosses_defeated == 3) {
2330
// If the player already has the seal, point them to home
2331
if (artifacts[11] == 1) {
2332
loc_x = rooms[0].x * 32 + rooms[0].w * 16;
2333
loc_y = rooms[0].y * 32 + rooms[0].h * 16;
2334
cdist = dist(rplx, rply, loc_x, loc_y);
2335
if (cdist < nearest) {
2340
// Can the player touch the seal?
2341
if (CanGetArtifact()) {
2342
loc_x = rooms[place_of_power].x * 32 + rooms[place_of_power].w * 16;
2343
loc_y = rooms[place_of_power].y * 32 + rooms[place_of_power].h * 16;
2344
cdist = dist(rplx, rply, loc_x, loc_y);
2345
if (cdist < nearest) {
2347
n_room = place_of_power;
2353
// Did we find a room? If so, point to it
2356
loc_x = rooms[n_room].x * 32 + rooms[n_room].w * 16;
2357
loc_y = rooms[n_room].y * 32 + rooms[n_room].h * 16;
2359
pdir_1 = PlayerDir(loc_x, loc_y) + M_PI;
2366
// Find the nearest uncleared artifact room
2367
for (i = 0; i < 3000; i++) {
2368
if (rooms[i].room_type == 3) {
2369
loc_x = rooms[i].x * 32 + rooms[i].w * 16;
2370
loc_y = rooms[i].y * 32 + rooms[i].h * 16;
2371
cdist = dist(rplx, rply, loc_x, loc_y);
2372
if (cdist < nearest) {
2380
loc_x = rooms[n_room].x * 32 + rooms[n_room].w * 16;
2381
loc_y = rooms[n_room].y * 32 + rooms[n_room].h * 16;
2383
pdir_2 = PlayerDir(loc_x, loc_y) + M_PI;
2389
// Did we find at least one thing to point to? If not, abort
2390
if (!(pdir_1t || pdir_2t))
2393
DrawCircleEx(rplx - scroll_x, rply - scroll_y, 200, 190, 255);
2395
DrawCircleEx(rplx - scroll_x + cos(pdir_1) * 170, rply - scroll_y + sin(pdir_1) * 170, 30, 20, 255);
2397
DrawCircleEx(rplx - scroll_x + cos(pdir_2) * 170, rply - scroll_y + sin(pdir_2) * 170, 30, 20, 195);
2399
for (i = 0; i < 50; i++) {
2401
DrawCircle(rplx - scroll_x + cos(pdir_1) * (25 + i * 4), rply - scroll_y + sin(pdir_1) * (25 + i * 4), 5, 255);
2403
DrawCircle(rplx - scroll_x + cos(pdir_2) * (25 + i * 4), rply - scroll_y + sin(pdir_2) * (25 + i * 4), 5, 195);
2405
DrawCircleEx(rplx - scroll_x, rply - scroll_y, 30, 20, 255);
2407
DrawCircleEx(rplx - scroll_x, rply - scroll_y, 197, 193, 128);
2409
DrawCircleEx(rplx - scroll_x + cos(pdir_1) * 170, rply - scroll_y + sin(pdir_1) * 170, 27, 23, 128);
2411
DrawCircleEx(rplx - scroll_x + cos(pdir_2) * 170, rply - scroll_y + sin(pdir_2) * 170, 27, 23, 78);
2413
for (i = 0; i < 50; i++) {
2415
DrawCircle(rplx - scroll_x + cos(pdir_1) * (25 + i * 4), rply - scroll_y + sin(pdir_1) * (25 + i * 4), 3, 128);
2417
DrawCircle(rplx - scroll_x + cos(pdir_2) * (25 + i * 4), rply - scroll_y + sin(pdir_2) * (25 + i * 4), 3, 78);
2419
DrawCircleEx(rplx - scroll_x, rply - scroll_y, 27, 23, 128);
2422
void SpecialTile(int x, int y)
2424
static int otext = 0;
2427
char message[100] = "";
2432
if (artifacts[11]) {
2433
sprintf(message, "This is a checkpoint, but it doesn't seem to be working");
2436
if (checkpoints_found <= 1) {
2437
sprintf(message, "This is a checkpoint. You will return here when you die.");
2439
sprintf(message, "Press ENTER to teleport between checkpoints.");
2443
sprintf(message, "Press ENTER to open the storage chest");
2446
if (player_shield >= 25) {
2447
sprintf(message, "Your shield is already at full efficiency");
2449
sprintf(message, "Press ENTER to upgrade shields (%d crystals)", UpgradePrice(0));
2453
if (circuit_fillrate >= 25) {
2454
sprintf(message, "Your circuit charge rate is already at its highest");
2456
sprintf(message, "Press ENTER to upgrade circuit charge (%d crystals)", UpgradePrice(1));
2460
if (circuit_recoverrate >= 25) {
2461
sprintf(message, "Your circuit refill rate is already at its highest");
2463
sprintf(message, "Press ENTER to upgrade circuit refill (%d crystals)", UpgradePrice(2));
2467
sprintf(message, "Press ENTER to record your progress");
2470
if (total_gems == 0) {
2471
sprintf(message, "This is a crystal device. It isn't working at the moment.");
2473
sprintf(message, "Press ENTER to activate the crystal device");
2477
if (rooms[player_room].room_type == 5) {
2478
if (CanGetArtifact(rooms[player_room].room_param)) {
2481
sprintf(message, "The artifact is tainted with shadow. You must slay more of the shadow first.");
2491
sprintf(message, "Press H to read the help file");
2498
if (message[0] == 0) {
2499
if (specialmessage != 0) {
2500
switch (specialmessage) {
2501
case 1: sprintf(message, "Ancient artifact: Complete Map"); break;
2502
case 2: sprintf(message, "Ancient artifact: Shield boost"); break;
2503
case 3: sprintf(message, "Ancient artifact: Extra crystal efficiency"); break;
2504
case 4: sprintf(message, "Ancient artifact: Circuit booster"); break;
2505
case 5: sprintf(message, "Ancient artifact: Metabolism increase"); break;
2506
case 6: sprintf(message, "Ancient artifact: Dodge enhancer"); break;
2507
case 7: sprintf(message, "Ancient artifact: Ethereal Monocle"); break;
2508
case 8: sprintf(message, "Ancient artifact: Crystal gatherer"); break;
2510
case 10: sprintf(message, "Enhancement: Shield upgrade"); break;
2511
case 11: sprintf(message, "Enhancement: Circuit charge upgrade"); break;
2512
case 12: sprintf(message, "Enhancement: Circuit refill upgrade"); break;
2514
case 20: sprintf(message, "Reward: Psi crystals"); break;
2516
case 30: sprintf(message, "Holy Sword 'Balmung' answers your call"); break;
2517
case 31: sprintf(message, "Mystic Halberd 'Amenonuhoko' answers your call"); break;
2518
case 32: sprintf(message, "Divine Bow 'Gandiva' answers your call"); break;
2519
case 33: sprintf(message, "You capture the cursed seal. Return to the entrance"); break;
2521
case 40: sprintf(message, "Balmung will remain here, where the ley lines are strong"); break;
2522
case 41: sprintf(message, "Amenonuhoko will remain here, where the ley lines are strong"); break;
2523
case 42: sprintf(message, "Gandiva will remain here, where the ley lines are strong"); break;
2525
case 50: sprintf(message, ". . . . . . retrieved 'Agate Knife'"); break;
2527
default: sprintf(message, "ERROR: NO MESSAGE VALUE GIVEN"); break;
2529
specialmessagetimer--;
2530
if (specialmessagetimer <= 0) {
2536
if (message[0] == 0) return;
2538
DrawRect(320 - strlen(message)*8 / 2 - 20, 100, strlen(message)*8+40, 48, 200);
2539
DrawRect(320 - strlen(message)*8 / 2 - 15, 105, strlen(message)*8+30, 38, 32);
2540
DrawRect(320 - strlen(message)*8 / 2 - 10, 110, strlen(message)*8+20, 28, 64);
2542
draw_text(320 - strlen(message)*8 / 2, 120, message, t%16<8 ? 255 : 192);
2544
if (enter_pressed) {
2545
ActivateTile(tile, x, y);
2549
void ScrollTo(int x, int y)
2551
static int scrollspeed_x = 1, scrollspeed_y = 1;
2552
if (scroll_home == 0) {
2558
if (scroll_home == 1) {
2559
scrollspeed_x = (x - scroll_x)/20;
2560
scrollspeed_y = (y - scroll_y)/20;
2564
if (scroll_home == 2) {
2565
scroll_x += (x - scroll_x)/2;
2566
scroll_y += (y - scroll_y)/2;
2568
if ((abs(scroll_x-x)<2)&&(abs(scroll_y-y)<2)) {
2576
void DrawArtifacts()
2581
if (artifact_spr == NULL) {
2582
artifact_spr = IMG_Load("dat/i/artifacts.png");
2583
SDL_SetColorKey(artifact_spr, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
2586
for (i = 0; i < 12; i++) {
2595
SDL_BlitSurface(artifact_spr, &from, screen, &to);
2600
void Swap(int *a, int *b)
2602
*a ^= *b ^= *a ^= *b;
2605
void ThinLine(SDL_Surface *scr, int x1, int y1, int x2, int y2, Uint8 col)
2613
dm = abs(dx) > abs(dy) ? dx : dy;
2615
if (dm == 0) return;
2628
DrawRect(x1, y1, x2-x1+1, 1, col);
2631
for (i = 0; i < dm; i++) {
2633
DrawRect(i+x1, j+y1, 1, 1, col);
2638
DrawRect(x1, y1, 1, y2-y1+1, col);
2641
for (i = 0; i < dm; i++) {
2643
DrawRect(j+x1, i+y1, 1, 1, col);