1 //
2 //   levelblit.c
3 //
4 //   Copyright 2007, 2008 Lancer-X/ASCEAI
5 //
6 //   This file is part of Meritous.
7 //
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.
12 //
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.
17 //
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/>.
20 //
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <time.h>
27 #include <SDL.h>
28 #include <SDL_image.h>
29 #include <assert.h>
30 
31 #include <errno.h>
32 #include <unistd.h>
33 #include <err.h>
34 #include <sys/stat.h>
35 
36 #include "mapgen.h"
37 #include "demon.h"
38 #include "gamemap.h"
39 #include "tiles.h"
40 #include "save.h"
41 #include "help.h"
42 #include "audio.h"
43 #include "boss.h"
44 #include "ending.h"
45 
46 #define PLAYERW 16
47 #define PLAYERH 24
48 
49 #define MERITOUS_VERSION "v 1.1"
50 int RECORDING = 0;
51 int PLAYBACK = 0;
52 
53 int expired_ms = 0;
54 int frame_len = 33;
55 int WriteBitmaps = 0;
56 int WB_StartRange = 0;
57 int WB_EndRange = 1000000;
58 int training = 0;
59 int game_paused = 0;
60 int show_ending = 0;
61 int voluntary_exit = 0;
62 int tele_select = 0;
63 int enter_room_x = 0, enter_room_y = 0;
64 
65 int agate_knife_loc = -1;
66 
67 FILE *record_file;
68 char record_filename[256];
69 
70 void DrawLevel(int off_x, int off_y, int hide_not_visited, int fog_of_war);
71 void DrawPlayer(int x, int y, int pl_dir, int pl_frm);
72 void LoadLevel();
73 void ActivateRoom(int room);
74 
75 void DrawCircuit();
76 void ReleaseCircuit();
77 void DrawCircle(int x, int y, int r, unsigned char c);
78 
79 void DrawArtifacts();
80 
81 void HandleEvents();
82 
83 void text_init();
84 void draw_text(int x, int y, char *str, Uint8 tcol);
85 unsigned char font_data[128][8][8];
86 
87 void DrawShield();
88 
89 int key_held[10] = {0};
90 int game_running = 1;
91 
92 int player_x;
93 int player_y;
94 int player_dying;
95 int magic_circuit;
96 int circuit_range;
97 int release_range;
98 int release_x;
99 int release_y;
100 int release_str;
101 
102 int shield_hp;
103 int shield_recover;
104 int player_gems;
105 int checkpoints_found;
106 int circuit_size;
107 int first_game;
108 int player_hp;
109 int player_lives = 5;
110 int player_lives_part = 0;
111 
112 int player_room;
113 int player_dir;
114 int player_wlk;
115 int player_walk_speed;
116 int wlk_wait;
117 int circuit_release;
118 int scroll_home;
119 int enter_pressed;
120 
121 int opening_door_x, opening_door_y, opening_door_i = 0, opening_door_n;
122 
123 int checkpoint_x;
124 int checkpoint_y;
125 
126 int explored = 0;
127 //#define DEBUG_STATS 1
128 
129 int artifacts[12];
130 SDL_Surface *artifact_spr = NULL;
131 
132 int player_shield;
133 int circuit_fillrate;
134 int circuit_recoverrate;
135 
136 int scroll_x, scroll_y;
137 
138 int map_enabled;
139 
140 int prv_player_room;
141 
142 int specialmessage;
143 int specialmessagetimer;
144 
145 int timer_ps = 0;
146 int timer_v[10];
147 
RandomDir()148 float RandomDir()
149 {
150 	return (float)(rand()%256)*M_PI*2.0/256.0;
151 }
152 
153 int UpgradePrice(int t);
154 
PlayerDefaultStats()155 void PlayerDefaultStats()
156 {
157 	int i;
158 
159 	player_dying = 0;
160 	magic_circuit = 0;
161 	circuit_range = 100;
162 	release_range = 100;
163 	shield_hp = 0;
164 	shield_recover = 0;
165 	player_gems = 0;
166 	checkpoints_found = 0;
167 	circuit_size = 1000;
168 	first_game = 1;
169 	player_hp = 3;
170 
171 	explored = 0;
172 
173 	voluntary_exit = 0;
174 	player_room = 0;
175 	player_dir = 0;
176 	player_wlk = 0;
177 	player_walk_speed = 5;
178 	player_lives = 5;
179 	player_lives_part = 0;
180 	wlk_wait = 8;
181 	circuit_release = 0;
182 	scroll_home = 0;
183 	enter_pressed = 0;
184 	show_ending = 0;
185 
186 	game_paused = 0;
187 
188 	player_shield = 0;
189 	circuit_fillrate = 2;
190 	circuit_recoverrate = 3;
191 
192 	prv_player_room = -1;
193 
194 	specialmessage = 0;
195 	specialmessagetimer = 0;
196 
197 	opening_door_i = 0;
198 
199 	map_enabled = 0;
200 
201 	for (i = 0; i < 12; i++) {
202 		artifacts[i] = 0;
203 	}
204 
205 	#ifdef DEBUG_STATS
206 
207 	player_shield = 24;
208 	circuit_fillrate = 24;
209 	circuit_recoverrate = 24;
210 
211 	for (i = 0; i < 12; i++) {
212 		artifacts[i] = 1;
213 	}
214 
215 	#endif
216 }
217 
218 
219 void ScrollTo(int x, int y);
220 #define K_UP 0
221 #define K_DN 1
222 #define K_LT 2
223 #define K_RT 3
224 #define K_SP 4
225 
226 SDL_Surface *screen;
227 
228 void SetGreyscalePalette();
229 void SetTonedPalette(float pct);
230 void SetTitlePalette(int curve_start, int curve_end);
231 void SetTitlePalette2(int t);
232 int TouchTile(int ix, int iy);
233 void SpecialTile(int x, int y);
234 void DrawRect(int x, int y, int w, int h, unsigned char c);
235 
236 void DrawCircleEx(int x, int y, int r, int r2, unsigned char c);
237 
238 void ThinLine(SDL_Surface *scr, int x1, int y1, int x2, int y2, Uint8 col);
239 void LockDoors(int r);
240 
241 #define SCREEN_W 640
242 #define SCREEN_H 480
243 
VideoUpdate()244 void VideoUpdate()
245 {
246 	static int bmp = 0;
247 	char bmp_name[256];
248 
249 	SDL_UpdateRect(screen, 0, 0, 0, 0);
250 	if (WriteBitmaps) {
251 		if ((bmp >= WB_StartRange)&&(bmp < WB_EndRange)) {
252 			sprintf(bmp_name, "v/bmp%d.bmp", bmp);
253 			SDL_SaveBMP(screen, bmp_name);
254 		}
255 		bmp++;
256 	}
257 }
258 
EndCycle(int n)259 void EndCycle(int n)
260 {
261 	static int last_ticks;
262 	int tick_delta;
263 	tick_delta = SDL_GetTicks() - last_ticks;
264 
265 	if (n == 0) n = frame_len;
266 
267 	if (tick_delta < n) {
268 		SDL_Delay(n-tick_delta);
269 	}
270 
271 	if (!game_paused) expired_ms += n;
272 
273 	last_ticks = SDL_GetTicks();
274 }
275 
WritePlayerData()276 void WritePlayerData()
277 {
278 	int i;
279 
280 	FWInt(expired_ms);
281 	FWInt(checkpoint_x);
282 	FWInt(checkpoint_y);
283 	FWInt(scroll_x);
284 	FWInt(scroll_y);
285 	FWInt(magic_circuit);
286 	FWInt(checkpoint_x);
287 	FWInt(checkpoint_y);
288 	FWInt(player_walk_speed);
289 	FWInt(wlk_wait);
290 	FWInt(circuit_fillrate);
291 	FWInt(circuit_recoverrate);
292 	FWInt(explored);
293 	FWInt(player_shield);
294 	FWInt(shield_recover);
295 	FWInt(shield_hp);
296 	FWInt(player_gems);
297 	FWInt(checkpoints_found);
298 	FWInt(player_hp);
299 	FWInt(player_lives);
300 	FWInt(player_lives_part);
301 	FWInt(current_boss);
302 	FWInt(training);
303 	FWInt(agate_knife_loc);
304 
305 	for (i = 0; i < 12; i++) {
306 		FWChar(artifacts[i]);
307 	}
308 }
309 
ReadPlayerData()310 void ReadPlayerData()
311 {
312 	int i;
313 
314 	expired_ms = FRInt();
315 	player_x = FRInt();
316 	player_y = FRInt();
317 	scroll_x = FRInt();
318 	scroll_y = FRInt();
319 	magic_circuit = FRInt();
320 	checkpoint_x = FRInt();
321 	checkpoint_y = FRInt();
322 	player_walk_speed = FRInt();
323 	wlk_wait = FRInt();
324 	circuit_fillrate = FRInt();
325 	circuit_recoverrate = FRInt();
326 	explored = FRInt();
327 	player_shield = FRInt();
328 	shield_recover = FRInt();
329 	shield_hp = FRInt();
330 	player_gems = FRInt();
331 	checkpoints_found = FRInt();
332 	player_hp = FRInt();
333 	player_lives = FRInt();
334 	player_lives_part = FRInt();
335 	current_boss = FRInt();
336 	training = FRInt();
337 
338 	agate_knife_loc = FRInt();
339 
340 	for (i = 0; i < 12; i++) {
341 		artifacts[i] = FRChar();
342 	}
343 }
344 
min(int x,int y)345 int min(int x, int y)
346 {
347 	if (x<y) return x;
348 	return y;
349 }
350 
DummyEventPoll()351 void DummyEventPoll()
352 {
353 	SDL_Event e;
354 	SDL_PollEvent(&e);
355 }
356 
357 int DungeonPlay(char *fname);
358 
Uint8_Bound(int c)359 Uint8 Uint8_Bound(int c)
360 {
361 	if (c<0) return 0;
362 	if (c>255) return 255;
363 	return c;
364 }
365 
dist(int x1,int y1,int x2,int y2)366 int dist(int x1, int y1, int x2, int y2)
367 {
368 	int dx, dy;
369 	dx = x2 - x1;
370 	dy = y2 - y1;
371 
372 	return sqrt((dx*dx)+(dy*dy));
373 }
374 
ClearInput()375 void ClearInput()
376 {
377 	key_held[K_SP] = 0;
378 	key_held[K_UP] = 0;
379 	key_held[K_DN] = 0;
380 	key_held[K_LT] = 0;
381 	key_held[K_RT] = 0;
382 }
383 
main(int argc,char ** argv)384 int main(int argc, char **argv)
385 {
386 	{
387 		if (chdir(getenv("HOME")) != 0)
388 			err(1, "cannot cd to $HOME");
389 		if (mkdir(".meritous", 0755) != 0 && errno != EEXIST)
390 			err(1, "cannot mkdir $HOME/.meritous");
391 		if (chdir(".meritous") != 0)
392 			err(1, "cannot cd to $HOME/.meritous");
393 	}
394 	int on_title = 1;
395 	int executable_running = 1;
396 	SDL_Surface *title, *title_pr, *asceai;
397 	SDL_Surface *wm_icon;
398 	Uint8 *src_p, *col_p;
399 	Uint8 wm_mask[128];
400 	int i;
401 	int light = 0;
402 	int x, y;
403 	int pulse[SCREEN_W * SCREEN_H];
404 	int precalc_sine[400];
405 	int tick = 10000000;
406 	int option = 0;
407 	int can_continue = 0;
408 	int maxoptions;
409 
410 	int last_key = 0;
411 
412 	int fullscreen = 0;
413 	int ticker_tick = 0;
414 	unsigned int stime = 0;
415 
416 	FILE *wm_mask_file;
417 
418 	if (argc > 1) {
419 		for (i = 1; i < argc; i++) {
420 			if (!strcasecmp(argv[i], "fullscreen")) {
421 				fullscreen = 1;
422 			}
423 /*			if (!strcasecmp(argv[i], "record")) {
424 				RECORDING = 1;
425 				strcpy(record_filename, argv[i+1]);
426 			}
427 			if (!strcasecmp(argv[i], "play")) {
428 				PLAYBACK = 1;
429 				strcpy(record_filename, argv[i+1]);
430 			}
431 			if (!strcasecmp(argv[i], "framedelay")) {
432 				frame_len = atoi(argv[i+1]);
433 			}
434 			if (!strcasecmp(argv[i], "bmpwrite")) {
435 				WriteBitmaps = 1;
436 			}
437 			if (!strcasecmp(argv[i], "bmpstart")) {
438 				WB_StartRange = atoi(argv[i+1]);
439 			}
440 			if (!strcasecmp(argv[i], "bmpend")) {
441 				WB_EndRange = atoi(argv[i+1]);
442 			} */
443 		}
444 	}
445 
446 	if ((RECORDING) && (PLAYBACK)) {
447 		exit(1);
448 	}
449 	srand(time(NULL));
450 	if (RECORDING) {
451 		record_file = fopen(record_filename, "wb");
452 		stime = time(NULL);
453 
454 		fputc(stime & 0x000000FF, record_file);
455 		fputc((stime & 0x0000FF00) >> 8, record_file);
456 		fputc((stime & 0x00FF0000) >> 16, record_file);
457 		fputc((stime & 0xFF000000) >> 24, record_file);
458 
459 		srand(stime);
460 	}
461 	if (PLAYBACK) {
462 		record_file = fopen(record_filename, "rb");
463 		stime = fgetc(record_file);
464 		stime |= fgetc(record_file) << 8;
465 		stime |= fgetc(record_file) << 16;
466 		stime |= fgetc(record_file) << 24;
467 
468 		srand(stime);
469 	}
470 
471 	asceai = IMG_Load("/usr/local/share/meritous/i/asceai.png");
472 	wm_icon = IMG_Load("/usr/local/share/meritous/i/icon.png");
473 
474 	screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 8, SDL_SWSURFACE | (SDL_FULLSCREEN * fullscreen));
475 
476 	wm_mask_file = fopen("/usr/local/share/meritous/d/icon_bitmask.dat", "rb");
477 	fread(wm_mask, 1, 128, wm_mask_file);
478 	fclose(wm_mask_file);
479 	SDL_WM_SetCaption("~ m e r i t o u s ~", "MT");
480 	SDL_WM_SetIcon(wm_icon, wm_mask);
481 	InitAudio();
482 
483 	text_init();
484 	for (i = 0; i < 400; i++) {
485 		precalc_sine[i] = sin((float)i / 400 * M_PI * 2)*24+24;
486 	}
487 
488 
489 	for (i = 0; i < screen->w * screen->h; i++) {
490 		x = i % SCREEN_W;
491 		y = i / SCREEN_W;
492 
493 		pulse[i] = dist(x, y, SCREEN_W / 2, SCREEN_H / 2);
494 	}
495 	SetGreyscalePalette();
496 
497 	// asceai logo
498 	SDL_BlitSurface(asceai, NULL, screen, NULL);
499 
500 	for (i = 0; i < 75; i++) {
501 		SetTitlePalette(i * 5 - 375, i * 5 - 120);
502 		VideoUpdate();
503 		DummyEventPoll();
504 		EndCycle(20);
505 	}
506 	SDL_Delay(500);
507 	for (i = 0; i < 50; i++) {
508 		SetTitlePalette(i * 5, 255 - (i * 5));
509 		VideoUpdate();
510 		DummyEventPoll();
511 		EndCycle(20);
512 	}
513 	SDL_Delay(500);
514 	for (i = 0; i < 50; i++) {
515 		SetTitlePalette(255, (i * 5)+5);
516 		VideoUpdate();
517 		DummyEventPoll();
518 		EndCycle(20);
519 	}
520 
521 	while (executable_running) {
522 		ticker_tick = 0;
523 		TitleScreenMusic();
524 
525 		if (IsSaveFile()) {
526 			can_continue = 1;
527 		} else {
528 			can_continue = 0;
529 		}
530 
531 		maxoptions = 2 + can_continue;
532 
533 		title = IMG_Load("/usr/local/share/meritous/i/title.png");
534 		title_pr = IMG_Load("/usr/local/share/meritous/i/title.png");
535 
536 		while (on_title) {
537 			SetTitlePalette2(ticker_tick);
538 			col_p = (Uint8 *)title_pr->pixels;
539 			src_p = (Uint8 *)title->pixels;
540 			if ((tick % 10) == 0) {
541 				for (i = 0; i < 640*480; i++) {
542 					*(col_p++) = Uint8_Bound(*(src_p++)+precalc_sine[(pulse[i]+tick)%400]);
543 				}
544 			}
545 			SDL_BlitSurface(title_pr, NULL, screen, NULL);
546 
547 			draw_text(17, 156, MERITOUS_VERSION, 225 + sin((float)ticker_tick / 15)*30);
548 			if (can_continue) draw_text((SCREEN_W - 14*8)/2, 310, "Continue", 255);
549 			draw_text((SCREEN_W - 14*8)/2, 310 + can_continue*10, "New Game", 255);
550 			draw_text((SCREEN_W - 14*8)/2, 320 + can_continue*10, "New Game (Wuss mode)", 255);
551 
552 			if (ticker_tick >= 30) {
553 				draw_text((SCREEN_W - 14*8)/2 - 17, 310 + option * 10, "-", 205 + sin((float)ticker_tick / 5.0)*24);
554 				draw_text((SCREEN_W - 14*8)/2 - 20, 310 + option * 10, " >", 205 + sin((float)ticker_tick / 5.0)*24);
555 				draw_text((SCREEN_W - 14*8)/2 - 19, 310 + option * 10, " >", 190 + sin((float)ticker_tick / 5.0)*24);
556 				draw_text((SCREEN_W - 14*8)/2 - 21, 310 + option * 10, " >", 190 + sin((float)ticker_tick / 5.0)*24);
557 				draw_text((SCREEN_W - 14*8)/2 - 18, 310 + option * 10, " >", 165 + sin((float)ticker_tick / 5.0)*24);
558 				draw_text((SCREEN_W - 14*8)/2 - 22, 310 + option * 10, " >", 165 + sin((float)ticker_tick / 5.0)*24);
559 			}
560 
561 			VideoUpdate();
562 
563 			if (ticker_tick++ > 30) {
564 				HandleEvents();
565 
566 				if (key_held[K_UP]) {
567 					if (last_key != 1)
568 						if (option > 0) option--;
569 					last_key = 1;
570 				} else {
571 					if (key_held[K_DN]) {
572 						if (last_key != 2)
573 							if (option < maxoptions-1) option++;
574 						last_key = 2;
575 					} else {
576 						last_key = 0;
577 						if (key_held[K_SP] || enter_pressed) {
578 							on_title = 0;
579 						}
580 					}
581 				}
582 
583 				if (voluntary_exit) {
584 					executable_running = 0;
585 					on_title = 0;
586 					SDL_Quit();
587 					exit(0);
588 				}
589 			}
590 
591 			EndCycle(10);
592 
593 			light = 0;
594 			tick -= 2;
595 		}
596 
597 		ClearInput();
598 
599 		if (executable_running == 1) {
600 			SDL_FreeSurface(title);
601 			SDL_FreeSurface(title_pr);
602 			if ((option == 0) && can_continue) {
603 				DungeonPlay("SaveFile.sav");
604 			} else {
605 				if (option == (0 + can_continue)) {
606 					training = 0;
607 					DungeonPlay("");
608 				} else {
609 					training = 1;
610 					DungeonPlay("");
611 				}
612 			}
613 			// clean up
614 			ClearInput();
615 			DestroyDungeon();
616 			DestroyThings();
617 			on_title = 1;
618 			game_load = 0;
619 
620 			game_running = 1;
621 		}
622 	}
623 
624 //	if (argc >= 2) DungeonPlay(argv[1]);
625 //	else DungeonPlay("");
626 
627 	SDL_Quit();
628 	return 0;
629 }
630 
DrawMeter(int x,int y,int n)631 void DrawMeter(int x, int y, int n)
632 {
633 	static SDL_Surface *meter = NULL;
634 	SDL_Rect drawfrom, drawto;
635 	if (meter == NULL) {
636 		meter = IMG_Load("/usr/local/share/meritous/i/meter.png");
637 		SDL_SetColorKey(meter, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
638 	}
639 
640 	drawfrom.x = 0;
641 	drawfrom.y = 6;
642 	drawfrom.w = 150;
643 	drawfrom.h = 6;
644 
645 	drawto.x = x;
646 	drawto.y = y;
647 
648 	SDL_BlitSurface(meter, &drawfrom, screen, &drawto);
649 
650 	drawfrom.w = n*6;
651 	drawfrom.y = 0;
652 
653 	SDL_BlitSurface(meter, &drawfrom, screen, &drawto);
654 }
655 
ProgressBarScreen(int part,float progress,char * message,float t_parts)656 void ProgressBarScreen(int part, float progress, char *message, float t_parts)
657 {
658 	memset(screen->pixels, 0, 640*480);
659 
660 	DrawRect(200, 217, 240, 50, 80);
661 	DrawRect(202, 219, 236, 46, 20);
662 	draw_text(232, 228, message, 255);
663 	DrawRect(232, 244, 176, 12, 128);
664 	DrawRect(234, 246, 172, 8, 0);
665 
666 	if ((int)(172.0 * progress / t_parts + (172.0 / t_parts * part)) > 0) {
667 		DrawRect(234, 246, (int)(172.0 * progress / t_parts + (172.0 / t_parts * part)), 8, 200);
668 	}
669 	VideoUpdate();
670 	DummyEventPoll();
671 }
672 
LoadingScreen(int part,float progress)673 void LoadingScreen(int part, float progress)
674 {
675 	float t_parts;
676 
677 	if (game_load) t_parts = 5.0;
678 	else t_parts = 3.0;
679 
680 	ProgressBarScreen(part, progress, "Loading... please wait", t_parts);
681 	ClearInput();
682 }
683 
SavingScreen(int part,float progress)684 void SavingScreen(int part, float progress)
685 {
686 	ProgressBarScreen(part, progress, "Saving... please wait", 4.0);
687 	ClearInput();
688 }
689 
Arc(SDL_Surface * s,int x,int y,int r,float dir)690 void Arc(SDL_Surface *s, int x, int y, int r, float dir)
691 {
692 	int bright;
693 	int i, c;
694 	float pdir, cdir, ndir;
695 
696 	int l_x = x, l_y = y;
697 	int cx, cy, c1x, c1y, c2x, c2y;
698 
699 	bright = rand()%128+63;
700 	i = 0;
701 	while (i < r) {
702 		i += rand()%5+25;
703 		pdir = dir + (float)(rand()%16)/16.0*2.0*(M_PI / 15.0);
704 		ndir = dir - (float)(rand()%16)/16.0*2.0*(M_PI / 15.0);
705 		cdir = dir + (float)(rand()%16)/16.0*2.0*(M_PI / 20.0) - (float)(rand()%16)/16.0*2.0*(M_PI / 20.0);
706 
707 		bright += rand()%30;
708 		bright -= rand()%30;
709 
710 		if (bright < 0) bright = 0;
711 		if (bright > 255) bright = 255;
712 
713 		c1x = x + cos(pdir) * i;
714 		c1y = y + sin(pdir) * i;
715 		ThinLine(s, l_x, l_y, c1x, c1y, bright);
716 		c2x = x + cos(ndir) * i;
717 		c2y = y + sin(ndir) * i;
718 		ThinLine(s, l_x, l_y, c2x, c2y, bright);
719 
720 		for (c = 0; c < 5; c++) {
721 			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) +
722 					  (float)(rand()%16)/16.0*2.0*(M_PI / 10.0)) * i, 1, 1, rand()%128+63);
723 		}
724 
725 		i += rand()%5+25;
726 		cx = x + cos(cdir) * i;
727 		cy = y + sin(cdir) * i;
728 		ThinLine(s, c1x, c1y, cx, cy, bright);
729 		ThinLine(s, c2x, c2y, cx, cy, bright);
730 		l_x = cx;
731 		l_y = cy;
732 	}
733 
734 }
735 
DungeonPlay(char * fname)736 int DungeonPlay(char *fname)
737 {
738 	int ix,  iy;
739 	int off_x, off_y;
740 	int t = 0;
741 	int i, j;
742 	int lost_gems;
743 	int rg_x, rg_y, rg_v;
744 	int max_dist;
745 	int last_killed = 0;
746 	int n_arcs = 0;
747 	int can_move;
748 
749 	float arcdir;
750 
751 	char buf[50];
752 
753 	expired_ms = 0;
754 	LoadingScreen(0, 0.0);
755 	if (fname[0] != 0) {
756 		LoadGame(fname);
757 	}
758 
759 	RandomGenerateMap();
760 	InitEnemies();
761 	InitBossVars();
762 
763 	PlayerDefaultStats();
764 	if (game_load) {
765 		first_game = 0;
766 		ReadPlayerData();
767 		//Paint(rooms[0].x+1, rooms[0].y+1, rooms[0].w-2, rooms[0].h-2, "/usr/local/share/meritous/d/fbossroom.loc");
768 	} else {
769 		player_x = map.w * 32 / 2 - PLAYERW/2;
770 		player_y = map.h * 32 / 2 - PLAYERH/2;
771 	}
772 
773 	InitAutomap();
774 
775 	if (game_load) CloseFile();
776 
777 	max_dist = 0;
778 	for (i = 0; i < 3000; i++) {
779 		if (rooms[i].s_dist > max_dist) {
780 			max_dist = rooms[i].s_dist;
781 		}
782 	}
783 
784 	game_running = 1;
785 	while (game_running) {
786 		//sprintf(buf, "X: %d  Y: %d", (player_x + PLAYERW/2)/32*32 + PLAYERW/2, (player_y + PLAYERH/2)/32*32 + PLAYERH/2);
787 		//SDL_WM_SetCaption(buf, "MT");
788 		if (!game_paused) {
789 			if (player_dying > 30) {
790 				player_hp--;
791 
792 				if (player_hp <= 0) {
793 					if (!training) player_lives--;
794 					lost_gems = player_gems / 3;
795 					player_gems -= lost_gems;
796 
797 					lost_gems = lost_gems * 95 / 100;
798 					while (lost_gems > 0) {
799 						rg_x = rooms[player_room].x * 32 + 32 + rand()%(rooms[player_room].w*32-64);
800 						rg_y = rooms[player_room].y * 32 + 32 + rand()%(rooms[player_room].h*32-64);
801 						rg_v = rand() % (lost_gems / 4 + 2);
802 						CreateGem(rg_x, rg_y, player_room, rg_v);
803 						lost_gems -= rg_v;
804 					}
805 
806 					player_dying = 0;
807 					shield_hp = 0;
808 
809 					if ( (current_boss == 3) && (boss_fight_mode != 0) ) {
810 						player_x = enter_room_x;
811 						player_y = enter_room_y;
812 						prv_player_room = 1;
813 					} else {
814 						player_x = checkpoint_x;
815 						player_y = checkpoint_y;
816 					}
817 					scroll_home = 1;
818 					CircuitBullets(player_x, player_y, 100);
819 					player_hp = 3 + (player_shield == 30)*3;
820 				} else {
821 					player_dying = 0;
822 				}
823 			}
824 		}
825 
826 		circuit_size = 250 + 50*(circuit_fillrate + circuit_recoverrate);
827 
828 		if (magic_circuit > 0) {
829 			circuit_range = (sqrt(magic_circuit + 1) * 6 + min(magic_circuit / 2, 50))*1.66;
830 			if (artifacts[3]) circuit_range += circuit_range / 2.4;
831 		} else circuit_range = -1;
832 		player_room = GetRoom(player_x/32, player_y/32);
833 
834 		if (player_room != prv_player_room) {
835 			SetTonedPalette((float)rooms[player_room].s_dist / (float)max_dist);
836 			prv_player_room = player_room;
837 			RecordRoom(player_room);
838 
839 			enter_room_x = player_x;
840 			enter_room_y = player_y;
841 
842 			if (rooms[player_room].room_type == 2) {
843 				// lock the doors
844 				LockDoors(player_room);
845 				// it's a boss room
846 				BossRoom(player_room);
847 			}
848 			if (((rooms[player_room].checkpoint)||(player_room==0))&&(!artifacts[11])) {
849 				checkpoint_x = rooms[player_room].x * 32 + (rooms[player_room].w / 2 * 32) + 8;
850 				checkpoint_y = rooms[player_room].y * 32 + (rooms[player_room].h / 2 * 32) + 4;
851 			}
852 			if (rooms[player_room].visited == 0) {
853 				rooms[player_room].visited = 1;
854 				explored++;
855 
856 				if (explored == 3000) {
857 					agate_knife_loc = player_room;
858 				}
859 
860 				ActivateRoom(player_room);
861 			}
862 		}
863 
864 		if (last_killed != killed_enemies) {
865 			SetTonedPalette((float)rooms[player_room].s_dist / (float)max_dist);
866 			last_killed = killed_enemies;
867 		} else {
868 			if ((player_room == 0)&&(artifacts[11] == 1)) {
869 				SetTonedPalette(0);
870 			}
871 		}
872 
873 		if (!map_enabled) {
874 			ScrollTo(player_x + PLAYERW/2 - 320, player_y + PLAYERH/2 - 240);
875 			DrawLevel(scroll_x, scroll_y, 1, 1);
876 			//DrawLevel(player_x + 8 - 320, player_y + 12 - 240);
877 
878 			if (player_dying == 0) {
879 				DrawShield();
880 
881 				if (magic_circuit > 0) {
882 					if (player_dying == 0) {
883 						if (circuit_release == 0) {
884 							arcdir = RandomDir();
885 							n_arcs = 1 + (circuit_size / 200 + 2) * magic_circuit / circuit_size;
886 							for (i = 0; i < n_arcs; i++) {
887 								Arc(screen, player_x - scroll_x + PLAYERW/2, player_y - scroll_y + PLAYERH/2, circuit_range, arcdir);
888 								arcdir += (float)(rand()%16) / 16.0 * (M_PI*2/(float)n_arcs);
889 							}
890 						}
891 					}
892 				}
893 
894 				DrawPlayer(312, 228, player_dir, player_wlk / wlk_wait);
895 			} else {
896 				if (t % 2 == 0) DrawPlayer(312, 228, player_dir, player_wlk / wlk_wait);
897 
898 				if (!game_paused)
899 					player_dying++;
900 			}
901 			t++;
902 			if ((boss_fight_mode != 0)&&(boss_fight_mode < 23)&&(!game_paused)) {
903 				BossControl();
904 			}
905 			DrawEntities();
906 			if (!game_paused) MoveEntities();
907 
908 			if (boss_fight_mode == 2) {
909 				DrawBossHP(100);
910 			}
911 
912 			if (rooms[player_room].room_type == 5) {
913 				DrawPowerObject();
914 			}
915 			if ( (rooms[player_room].room_type == 6) && (current_boss == 3) ) {
916 				DrawPowerObject();
917 			}
918 			if ((rooms[player_room].room_type == 4) && ((player_room % 1000) == 999)) {
919 				DrawPowerObject();
920 			}
921 			if (player_room == agate_knife_loc) {
922 				{
923 					static float agate_t = 0.0;
924 					static SDL_Surface *agate_knife = NULL;
925 					int xpos, ypos;
926 					int room_w, room_h;
927 					int room_x, room_y;
928 
929 					room_x = rooms[player_room].x * 32 + 32;
930 					room_y = rooms[player_room].y * 32 + 32;
931 					room_w = rooms[player_room].w * 32 - 64;
932 					room_h = rooms[player_room].h * 32 - 64;
933 
934 					SDL_Rect draw_to;
935 					if (agate_knife == NULL) {
936 						agate_knife = IMG_Load("/usr/local/share/meritous/i/agate.png");
937 						SDL_SetColorKey(agate_knife, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
938 					}
939 					xpos = (int)((sin(agate_t * 1.33)*0.5+0.5) * (float)room_w) + room_x;
940 					ypos = (int)((cos(agate_t * 0.7)*0.5+0.5) * (float)room_h) + room_y;
941 
942 					if (dist(player_x, player_y, xpos, ypos) < 20) {
943 						agate_knife_loc = -1;
944 						specialmessage = 50;
945 						specialmessagetimer = 150;
946 						SND_Pos("/usr/local/share/meritous/a/crystal2.wav", 128, 0);
947 
948 						player_shield = 30;
949 						circuit_fillrate = 30;
950 						circuit_recoverrate = 30;
951 						player_hp = 6;
952 					}
953 					draw_to.x = xpos - 16 - scroll_x;
954 					draw_to.y = ypos - 16 - scroll_y;
955 
956 					SDL_BlitSurface(agate_knife, NULL, screen, &draw_to);
957 
958 					agate_t += 0.05;
959 				}
960 			}
961 
962 			if (opening_door_i > 0) {
963 				DrawArtifactOverhead(opening_door_n);
964 				for (i = 0; i < 5; i++) {
965 					j = i * 50 - 250 + (opening_door_i * 5);
966 					if (j > 0) {
967 						DrawCircle(player_x - scroll_x, player_y - scroll_y, j, 255);
968 					}
969 				}
970 
971 				if (!game_paused) {
972 					opening_door_i++;
973 					if (opening_door_i >= 100) {
974 						opening_door_i = 0;
975 						Put(opening_door_x, opening_door_y, Get(opening_door_x, opening_door_y) - 38 + 13, GetRoom(opening_door_x, opening_door_y));
976 					}
977 				}
978 			}
979 
980 			if (circuit_release > 0) {
981 				DrawCircle(release_x - player_x + 320, release_y - player_y + 240, circuit_release * release_range / 20, sin((float)circuit_release / 20.0)*127+127);
982 				if (!game_paused) {
983 					CircuitBullets(release_x, release_y, circuit_release * release_range / 20);
984 					//HurtEnemies(release_x, release_y, circuit_release * release_range / 20, release_str);
985 					circuit_release+=2;
986 
987 					if (circuit_release > 24) {
988 						circuit_release = 0;
989 						HurtEnemies(release_x, release_y, release_range, release_str);
990 						if (boss_fight_mode == 2) TryHurtBoss(release_x, release_y, release_range, release_str);
991 					}
992 				}
993 			}
994 
995 			if (!game_paused) {
996 				if (shield_hp < player_shield) {
997 					shield_recover += player_shield * 3 / (3 - training - (player_shield == 30));
998 					if (artifacts[1]) shield_recover += player_shield * 3 / (3 - training - (player_shield == 30));
999 					if (shield_recover >= 50) {
1000 						shield_hp++;
1001 						shield_recover -= 50 - (player_shield == 30)*25;
1002 					}
1003 				}
1004 			}
1005 		}
1006 
1007 		DrawRect(0, 0, 640, 29, 0);
1008 		DrawRect(1, 1, 638, 27, 32);
1009 		DrawRect(2, 2, 636, 25, 64);
1010 
1011 		if (!tele_select) {
1012 			sprintf(buf, "Psi Crystals: %d", player_gems);
1013 			draw_text(3, 3, buf, 200);
1014 			sprintf(buf, "Explored: %.1f%% (%d/%d rooms)", (float)explored/30.0, explored, 3000);
1015 			draw_text(3, 11, buf, 200);
1016 			sprintf(buf, "Cleared: %.1f%% (%d/%d monsters)", (float)killed_enemies/(float)total_enemies*100.0, killed_enemies, total_enemies);
1017 			draw_text(3, 19, buf, 200);
1018 
1019 			draw_text(316, 3, "Reflect shield", (player_gems >= UpgradePrice(0))&&(player_shield!=30) ? (231 + (t%13)*2) : 200);
1020 			DrawMeter(434, 3, player_shield);
1021 
1022 			draw_text(316, 11, "Circuit charge", (player_gems >= UpgradePrice(1))&&(circuit_fillrate!=30) ? (231 + (t%13)*2) : 200);
1023 			DrawMeter(434, 11, circuit_fillrate);
1024 
1025 			draw_text(316, 19, "Circuit refill", (player_gems >= UpgradePrice(2))&&(circuit_recoverrate!=30) ? (231 + (t%13)*2) : 200);
1026 			DrawMeter(434, 19, circuit_recoverrate);
1027 
1028 		} else {
1029 			draw_text(80, 11-6, "Use the movement keys to locate a checkpoint. Press ENTER to", 240);
1030 			draw_text(52, 11+6, "teleport to this checkpoint. Press ESCAPE or TAB once you are done.", 240);
1031 		}
1032 
1033 		if (!training) {
1034 			buf[0] = 30;
1035 
1036 			if (player_lives <= 99) {
1037 				if (player_lives < 10) {
1038 					sprintf(buf+1, " %d", player_lives);
1039 				} else {
1040 					sprintf(buf+1, "%d", player_lives);
1041 				}
1042 			} else {
1043 				sprintf(buf+1, "**");
1044 			}
1045 
1046 			draw_text(615, 4, buf, 200);
1047 
1048 			DrawRect(615, 13, 24, 4, 240);
1049 			DrawRect(616, 14, 22, 2, 0);
1050 			i = (player_lives_part * 22 / 88);
1051 			if (i > 0) {
1052 				DrawRect(616, 14, i, 2, 160 + (t % 40));
1053 			}
1054 		}
1055 
1056 		if (player_shield != 30) {
1057 			for (i = 0; i < player_hp; i++) {
1058 				buf[i] = 3;
1059 			}
1060 			buf[player_hp]=0;
1061 		} else {
1062 			for (i = 0; i < (player_hp / 2); i++) {
1063 				buf[i] = 3;
1064 			}
1065 			if ((player_hp % 2) == 1) {
1066 				buf[(player_hp + 1) / 2 - 1] = 2;
1067 			}
1068 			buf[(player_hp+1)/2]=0;
1069 		}
1070 
1071 		draw_text(615, 18 - (5*training), buf, 200);
1072 
1073 		DrawRect(0, 466, 640, 14, 0);
1074 		DrawRect(1, 467, 638, 12, 32);
1075 		DrawRect(2, 468, 636, 10, 64);
1076 
1077 		DrawCircuit();
1078 		DrawArtifacts();
1079 
1080 		SpecialTile((player_x+PLAYERW/2)/32, (player_y+PLAYERH/2)/32);
1081 
1082 		if (map_enabled) DisplayAutomap();
1083 
1084 		if ((boss_fight_mode != 0)&&(boss_fight_mode == 23)&&(!game_paused)) {
1085 			BossControl();
1086 		}
1087 		if ( (boss_dlg != 0) && (!game_paused)) {
1088 			BossDialog();
1089 		}
1090 
1091 		if (game_paused && (!map_enabled) && (!voluntary_exit)) {
1092 			for (i = 0; i < 10; i++) {
1093 				DrawRect((640 - 6 * 8) / 2 - i, (480 - 8) / 2 - i, 6*8 + 2*i, 8 + 2*i, 64 - i*5);
1094 			}
1095 			draw_text((640 - 6 * 8) / 2, (480 - 8) / 2, "Paused", 255);
1096 
1097 			{
1098 				int t_days;
1099 				int t_hours;
1100 				int t_minutes;
1101 				int t_seconds;
1102 
1103 				t_seconds = (expired_ms / 1000) % 60;
1104 				t_minutes = ((expired_ms / 1000) / 60) % 60;
1105 				t_hours = (((expired_ms / 1000) / 60) / 60) % 24;
1106 				t_days = (((expired_ms / 1000) / 60) / 60) / 24;
1107 
1108 				if (t_days > 0) {
1109 					sprintf(buf, "%dd %dh %dm %ds", t_days, t_hours, t_minutes, t_seconds);
1110 				} else {
1111 					if (t_hours > 0) {
1112 						sprintf(buf, "%dh %dm %ds", t_hours, t_minutes, t_seconds);
1113 					} else {
1114 						sprintf(buf, "%dm %ds", t_minutes, t_seconds);
1115 					}
1116 				}
1117 				draw_text(636 - strlen(buf)*8, 470, buf, 255);
1118 			}
1119 		}
1120 
1121 		if (voluntary_exit) {
1122 			DrawRect(152, 200, 336, 80, 128);
1123 			DrawRect(160, 208, 320, 64, 64);
1124 			draw_text((640 - 30 * 8) / 2, (480 - 8) / 2 - 4, "Are you sure you want to quit?", 255);
1125 			draw_text((640 - 23 * 8) / 2, (480 - 8) / 2 + 4, "Press enter to confirm.", 255);
1126 		}
1127 
1128 		VideoUpdate();
1129 
1130 		MusicUpdate();
1131 
1132 		EndCycle(0);
1133 
1134 		can_move = 1;
1135 
1136 		if ((player_dying != 0) && (player_hp <= 1)) can_move = 0;
1137 		if (rooms[player_room].room_type == 5)
1138 			if (CanGetArtifact())
1139 				if (Get((player_x+PLAYERW/2)/32, (player_y+PLAYERH/2)/32)==42)
1140 					if (rooms[player_room].enemies == 0)
1141 						can_move = 0;
1142 
1143 		if (rooms[player_room].room_type == 6)
1144 			if (CanGetArtifact())
1145 				if (PlayerDist(rooms[player_room].w * 16 + rooms[player_room].x * 32,
1146 							rooms[player_room].h * 16 + rooms[player_room].y * 32) < 32)
1147 					if (rooms[player_room].enemies == 0)
1148 						if (current_boss == 3)
1149 							can_move = 0;
1150 
1151 		if (scroll_home != 0) can_move = 0;
1152 		if (boss_fight_mode == 1) can_move = 0;
1153 		if (boss_fight_mode >= 3) can_move = 0;
1154 		if (opening_door_i != 0) can_move = 0;
1155 		if (game_paused) can_move = 0;
1156 
1157 		HandleEvents();
1158 		if (map_enabled) {
1159 			game_paused = 1;
1160 		}
1161 
1162 		if (can_move) {
1163 
1164 			ix = player_x;
1165 			iy = player_y;
1166 			off_x = 0;
1167 			off_y = 0;
1168 			if (key_held[K_UP] && !key_held[K_DN]) {
1169 				iy -= player_walk_speed * (artifacts[4]?1.4:1);
1170 				player_dir = 0;
1171 			}
1172 			if (key_held[K_DN] && !key_held[K_UP]) {
1173 				iy += player_walk_speed * (artifacts[4]?1.4:1);;
1174 				player_dir = 1;
1175 				off_y = 24;
1176 			}
1177 			if (key_held[K_LT] && !key_held[K_RT]) {
1178 				ix -= player_walk_speed * (artifacts[4]?1.4:1);;
1179 				if (!(key_held[K_UP] || key_held[K_DN])) {
1180 					player_dir = 3;
1181 				}
1182 			}
1183 			if (key_held[K_RT] && !key_held[K_LT]) {
1184 				off_x = 16;
1185 				ix += player_walk_speed * (artifacts[4]?1.4:1);;
1186 				if (!(key_held[K_UP] || key_held[K_DN])) {
1187 					player_dir = 2;
1188 
1189 				}
1190 			}
1191 			if ((key_held[K_SP])&&(magic_circuit >= 0)) {
1192 				magic_circuit += (circuit_fillrate * (3+training+(circuit_fillrate==30))/3);
1193 			} else {
1194 				if (magic_circuit < 0) {
1195 					magic_circuit += (circuit_recoverrate * (3+training+(circuit_recoverrate==30))/3);
1196 					if (magic_circuit > 0) magic_circuit = 0;
1197 				} else {
1198 					if (magic_circuit > 0) {
1199 						ReleaseCircuit();
1200 					}
1201 				}
1202 			}
1203 
1204 			if (magic_circuit > circuit_size) magic_circuit = circuit_size;
1205 
1206 			if ((ix!=player_x)||(iy!=player_y)) {
1207 				// Are we changing to a new square?
1208 				if (((player_x / 32)!=((ix+off_x) / 32)) || ((player_y / 32)!=((iy+off_y) / 32))) {
1209 					//printf("%d\n", tile);
1210 					if (TouchTile(ix, iy)) {
1211 						player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
1212 					} else {
1213 						if (TouchTile(player_x, iy)) {
1214 							player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
1215 						} else {
1216 							if (TouchTile(ix, player_y)) {
1217 								player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
1218 								if (off_x > 0) player_dir = 2;
1219 								else player_dir = 3;
1220 							}
1221 						}
1222 
1223 					}
1224 				} else {
1225 					player_x = ix;
1226 					player_y = iy;
1227 
1228 					player_wlk = (player_wlk + 1 + artifacts[4]*3) % (4*wlk_wait);
1229 				}
1230 			}
1231 		}
1232 
1233 		if ((t % (33 * 10))==(33 * 10 - 1)) {
1234 			ActivateRand();
1235 		}
1236 
1237 		if (voluntary_exit && enter_pressed) {
1238 			voluntary_exit = 0;
1239 			game_running = 0;
1240 			game_paused = 0;
1241 		}
1242 
1243 		if ((player_lives == 0) && (!training)) {
1244 			break;
1245 		}
1246 		if (show_ending) {
1247 			break;
1248 		}
1249 	}
1250 
1251 	if (show_ending) {
1252 		show_ending = 0;
1253 		ShowEnding();
1254 	}
1255 
1256 	if ((player_lives == 0) && (!training)) {
1257 		SDL_FillRect(screen, NULL, 0);
1258 		draw_text(252, 236, "G A M E   O V E R", 255);
1259 		VideoUpdate();
1260 		SDL_Delay(2000);
1261 	}
1262 
1263 	return 0;
1264 }
1265 
UpRoom()1266 void UpRoom()
1267 {
1268 	int i, nd;
1269 
1270 	nd = rooms[player_room].s_dist + 1;
1271 
1272 	for (i = 0; i < 3000; i++) {
1273 		if (rooms[i].s_dist == nd) {
1274 			player_x = rooms[i].x * 32 + 64;
1275 			player_y = rooms[i].y * 32 + 64;
1276 		}
1277 	}
1278 }
1279 
CancelVoluntaryExit()1280 void CancelVoluntaryExit()
1281 {
1282 	if (voluntary_exit) {
1283 		voluntary_exit = 0;
1284 		game_paused = 0;
1285 	}
1286 }
1287 
HandleEvents()1288 void HandleEvents()
1289 {
1290 	unsigned short db;
1291 	static SDL_Event event;
1292 	int pressed_tab = 0;
1293 
1294 	if (PLAYBACK) {
1295 		db = fgetc(record_file);
1296 		db |= fgetc(record_file) << 8;
1297 
1298 		key_held[K_UP] = (db & 0x0001)>0;
1299 		key_held[K_DN] = (db & 0x0002)>0;
1300 		key_held[K_LT] = (db & 0x0004)>0;
1301 		key_held[K_RT] = (db & 0x0008)>0;
1302 		key_held[K_SP] = (db & 0x0010)>0;
1303 		enter_pressed  = (db & 0x0020)>0;
1304 		map_enabled    = (db & 0x0040)>0;
1305 		game_running   = (db & 0x0080)>0;
1306 		game_paused    = (db & 0x0100)>0;
1307 		voluntary_exit = (db & 0x0200)>0;
1308 		pressed_tab    = (db & 0x0400)>0;
1309 		tele_select    = (db & 0x0800)>0;
1310 
1311 		return;
1312 	}
1313 
1314 	if (pressed_tab) {
1315 		c_scroll_x = player_x;
1316 		c_scroll_y = player_y;
1317 	}
1318 
1319 	enter_pressed = 0;
1320 		while (SDL_PollEvent(&event)) {
1321 			if (event.type == SDL_KEYDOWN) {
1322 				switch (event.key.keysym.sym) {
1323 					case SDLK_w:
1324 					case SDLK_UP:
1325 						key_held[K_UP] = 1;
1326 						CancelVoluntaryExit();
1327 						break;
1328 					case SDLK_s:
1329 					case SDLK_DOWN:
1330 						key_held[K_DN] = 1;
1331 						CancelVoluntaryExit();
1332 						break;
1333 					case SDLK_a:
1334 					case SDLK_LEFT:
1335 						key_held[K_LT] = 1;
1336 						CancelVoluntaryExit();
1337 						break;
1338 					case SDLK_d:
1339 					case SDLK_RIGHT:
1340 						key_held[K_RT] = 1;
1341 						CancelVoluntaryExit();
1342 						break;
1343 					case SDLK_SPACE:
1344 						key_held[K_SP] = 1;
1345 						CancelVoluntaryExit();
1346 						break;
1347 					case SDLK_RETURN:
1348 						enter_pressed = 1;
1349 						break;
1350 					case SDLK_ESCAPE:
1351 						if (map_enabled) {
1352 							map_enabled = 0;
1353 							game_paused = 0;
1354 							tele_select = 0;
1355 						} else {
1356 							voluntary_exit ^= 1;
1357 							game_paused = voluntary_exit;
1358 						}
1359 						break;
1360 					case SDLK_TAB:
1361 						if (tele_select) {
1362 							map_enabled = 0;
1363 							game_paused = 0;
1364 							tele_select = 0;
1365 						} else {
1366 							pressed_tab = 1;
1367 							map_enabled ^= 1;
1368 							game_paused = map_enabled;
1369 							c_scroll_x = player_x;
1370 							c_scroll_y = player_y;
1371 						}
1372 						CancelVoluntaryExit();
1373 						break;
1374 					case SDLK_h:
1375 						CancelVoluntaryExit();
1376 						ShowHelp();
1377 						break;
1378 					case SDLK_p:
1379 						game_paused ^= 1;
1380 						CancelVoluntaryExit();
1381 						break;
1382 
1383 
1384 					/*
1385 					case SDLK_j:
1386 						{
1387 							player_shield = 20;
1388 							circuit_recoverrate = 20;
1389 							circuit_fillrate = 20;
1390 						}
1391 						break;
1392 					case SDLK_k:
1393 						{
1394 							int i, n, j;
1395 							for (j = 0; j < 1; j++) {
1396 								for (i = 0; i < 50000; i++) {
1397 									n = rand()%3000;
1398 									if (rooms[n].visited == 0) {
1399 										player_x = rooms[n].x * 32 + rooms[n].w * 16;
1400 										player_y = rooms[n].y * 32 + rooms[n].h * 16;
1401 										rooms[n].visited = 1;
1402 										explored++;
1403 										break;
1404 									}
1405 								}
1406 							}
1407 						}
1408 						break;
1409 
1410 					case SDLK_m:
1411 						{
1412 							int i;
1413 							for (i = 0; i < 8; i++) {
1414 								artifacts[i] = 1;
1415 							}
1416 							for (i = 8; i < 11; i++) {
1417 								artifacts[i] = 0;
1418 							}
1419 							artifacts[11] = 0;
1420 						}
1421 						break;
1422 
1423 					case SDLK_n:
1424 						{
1425 							current_boss = 3;
1426 							expired_ms = 1000000;
1427 						}
1428 						break;
1429 					*/
1430 					default:
1431 						break;
1432 				}
1433 			}
1434 			if (event.type == SDL_KEYUP) {
1435 				switch (event.key.keysym.sym) {
1436 					case SDLK_w:
1437 					case SDLK_UP:
1438 						key_held[K_UP] = 0;
1439 						break;
1440 					case SDLK_s:
1441 					case SDLK_DOWN:
1442 						key_held[K_DN] = 0;
1443 						break;
1444 					case SDLK_a:
1445 					case SDLK_LEFT:
1446 						key_held[K_LT] = 0;
1447 						break;
1448 					case SDLK_d:
1449 					case SDLK_RIGHT:
1450 						key_held[K_RT] = 0;
1451 						break;
1452 					case SDLK_SPACE:
1453 						key_held[K_SP] = 0;
1454 						break;
1455 					default:
1456 						break;
1457 				}
1458 			}
1459 			if (event.type == SDL_QUIT) {
1460 				voluntary_exit = 1;
1461 			}
1462 		}
1463 
1464 	if (RECORDING) {
1465 		db = 0;
1466 
1467 		db |= 0x0001 * key_held[K_UP];
1468 		db |= 0x0002 * key_held[K_DN];
1469 		db |= 0x0004 * key_held[K_LT];
1470 		db |= 0x0008 * key_held[K_RT];
1471 		db |= 0x0010 * key_held[K_SP];
1472 		db |= 0x0020 * enter_pressed;
1473 		db |= 0x0040 * map_enabled;
1474 		db |= 0x0080 * game_running;
1475 		db |= 0x0100 * game_paused;
1476 		db |= 0x0200 * voluntary_exit;
1477 		db |= 0x0400 * pressed_tab;
1478 		db |= 0x0800 * tele_select;
1479 
1480 		fputc(db & 0x00FF, record_file);
1481 		fputc((db & 0xFF00)>>8, record_file);
1482 		return;
1483 	}
1484 
1485 }
1486 
DrawLevel(int off_x,int off_y,int hide_not_visited,int fog_of_war)1487 void DrawLevel(int off_x, int off_y, int hide_not_visited, int fog_of_war)
1488 {
1489 	static SDL_Surface *tiles = NULL;
1490 	static SDL_Surface *fog = NULL;
1491 	Uint8 *pp;
1492 	SDL_Rect tilerec, screenrec;
1493 	int x, y, i;
1494 	int resolve_x, resolve_y;
1495 
1496 	DrawRect(0, 0, 640, 480, 255);
1497 
1498 	if (tiles == NULL) {
1499 		tiles = IMG_Load("/usr/local/share/meritous/i/tileset.png");
1500 		fog = IMG_Load("/usr/local/share/meritous/i/tileset.png");
1501 
1502 		pp = fog->pixels;
1503 
1504 		for (i = 0; i < fog->w*fog->h; i++) {
1505 			*pp = *pp / 2 + 128;
1506 			pp++;
1507 		}
1508 	}
1509 	for (y = 0; y < 16; y++) {
1510 		for (x = 0; x < 21; x++) {
1511 			resolve_x = x + (off_x/32);
1512 			resolve_y = y + (off_y/32);
1513 
1514 			if ((GetVisited(resolve_x, resolve_y) == 0)&&(player_room != GetRoom(resolve_x, resolve_y))&&(hide_not_visited)) {
1515 				tilerec.x = 17 * 32;
1516 			} else {
1517 				tilerec.x = Get(resolve_x, resolve_y) * 32;
1518 			}
1519 			tilerec.y = 0;
1520 			tilerec.w = 32;
1521 			tilerec.h = 32;
1522 
1523 			screenrec.x = x*32 - ( (off_x) %32);
1524 			screenrec.y = y*32 - ( (off_y) %32);
1525 
1526 			if ((player_room != GetRoom(resolve_x, resolve_y))&&(fog_of_war)) {
1527 				SDL_BlitSurface(fog, &tilerec, screen, &screenrec);
1528 			} else {
1529 				SDL_BlitSurface(tiles, &tilerec, screen, &screenrec);
1530 			}
1531 		}
1532 	}
1533 }
1534 
DrawPlayer(int x,int y,int pl_dir,int pl_frm)1535 void DrawPlayer(int x, int y, int pl_dir, int pl_frm)
1536 {
1537 	static SDL_Surface *playersprite = NULL;
1538 	SDL_Rect playerrec, screenrec;
1539 
1540 	if (playersprite == NULL) {
1541 		playersprite = IMG_Load("/usr/local/share/meritous/i/player.png");
1542 		SDL_SetColorKey(playersprite, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
1543 	}
1544 
1545 	playerrec.x = pl_frm * 16;
1546 	playerrec.y = pl_dir * 24;
1547 	playerrec.w = 16;
1548 	playerrec.h = 24;
1549 
1550 	screenrec.x = x;
1551 	screenrec.y = y;
1552 
1553 	SDL_BlitSurface(playersprite, &playerrec, screen, &screenrec);
1554 }
1555 
SetGreyscalePalette()1556 void SetGreyscalePalette()
1557 {
1558 	SDL_Color grey[256];
1559 	SDL_Color pal[256];
1560 	int i;
1561 
1562 	float ip;
1563 
1564 	for (i = 0; i < 256; i++) {
1565 		grey[i].r = grey[i].g = grey[i].b = i;
1566 	}
1567 
1568 	for (i = 0; i < 256; i++) {
1569 		ip = (float)i / 255.0;
1570 		pal[i].r = (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255;
1571 		pal[i].g = (sin(ip * M_PI / 2.0) * 255 + i) / 2;
1572 		pal[i].b = sin(ip * M_PI / 2.0) * 255;
1573 	}
1574 
1575 	SDL_SetPalette(screen, SDL_LOGPAL, grey, 0, 256);
1576 	SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
1577 }
1578 
SetTonedPalette(float dct)1579 void SetTonedPalette(float dct)
1580 {
1581 	SDL_Color pal[256];
1582 	float pct = 1.0 - dct;
1583 	float rp_dct, rp_pct;
1584 	float ip;
1585 	int ec;
1586 	int i;
1587 	static int tk = 0;
1588 
1589 	ec = rooms[player_room].enemies;
1590 
1591 	if (ec < 50) {
1592 		rp_dct = (float)ec / 50.0;
1593 	} else {
1594 		rp_dct = 1.0;
1595 	}
1596 	rp_pct = 1.0 - rp_dct;
1597 
1598 	if ( (player_room == 0) && (current_boss == 3) && (boss_fight_mode >= 3) ) {
1599 		if (boss_fight_mode == 23) {
1600 			for (i = 0; i < 256; i++) {
1601 				pal[i].r = i;
1602 				pal[i].g = i;
1603 				pal[i].b = i;
1604 			}
1605 		} else {
1606 			tk++;
1607 			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);
1608 
1609 			if (magic_circuit < 0.1) pct = 1.0;
1610 
1611 			for (i = 0; i < 256; i++) {
1612 				ip = (float)i / 255.0;
1613 				pal[i].r = 255 - (255 - (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255)*pct;
1614 				pal[i].g = 255 - (255 - i)*pct;
1615 				pal[i].b = 255 - (255 - sin(ip * M_PI / 2.0) * 255) * pct;
1616 			}
1617 
1618 
1619 			pal[1].r = 0;
1620 			pal[1].g = 0;
1621 			pal[1].b = 0;
1622 		}
1623 	} else {
1624 		if (artifacts[11]) {
1625 			if (player_room == 0) {
1626 				tk++;
1627 				pct = sin((float)tk / 33.0 * M_PI) * 0.5 + 0.5;
1628 				for (i = 0; i < 256; i++) {
1629 					pal[i].r = i;
1630 					pal[i].g = (i / 3)*pct;
1631 					pal[i].b = (i * 2 / 3)*pct;
1632 				}
1633 			} else {
1634 				for (i = 0; i < 256; i++) {
1635 					ip = (float)i / 255.0;
1636 					pal[i].r = i;
1637 					pal[i].g = i * dct;
1638 					pal[i].b = (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255 * dct;
1639 				}
1640 			}
1641 
1642 			if ( (current_boss == 3) && (player_shield == 30) && (player_room == 0)) {
1643 				if (boss_lives <= 1) {
1644 					tk++;
1645 					for (i = 0; i < 256; i++) {
1646 						pct = sin((float) (tk + i) / 24.0 * M_PI) * 0.5 + 0.5;
1647 
1648 						pal[i].r = (i * 0.5 + 128)*pct;
1649 						pal[i].g = i * 0.5 + 128;
1650 						pal[i].b = (i * 0.5 + 128)*pct;
1651 					}
1652 				}
1653 			}
1654 		} else {
1655 			for (i = 0; i < 256; i++) {
1656 				ip = (float)i / 255.0;
1657 				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;
1658 				pal[i].g = (i)*rp_pct + ((cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255)*rp_dct;
1659 				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;
1660 			}
1661 		}
1662 	}
1663 
1664 	SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
1665 }
1666 
SetTitlePalette(int curve_start,int curve_end)1667 void SetTitlePalette(int curve_start, int curve_end)
1668 {
1669 	SDL_Color pal[256];
1670 	int ec;
1671 	int i;
1672 
1673 	for (i = 0; i < 256; i++) {
1674 		ec = (i - curve_start) * 255 / (curve_end-curve_start);
1675 		if (ec < 0) ec = 0;
1676 		if (ec > 255) ec = 255;
1677 
1678 		pal[i].r = ec;
1679 		pal[i].g = ec;
1680 		pal[i].b = ec;
1681 	}
1682 
1683 	SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
1684 }
1685 
SetTitlePalette2(int t)1686 void SetTitlePalette2(int t)
1687 {
1688 	SDL_Color pal[256];
1689 	int i;
1690 
1691 	float ip;
1692 	float bright;
1693 	float b_coeff;
1694 
1695 	bright = 1 - ((float)t / 30.0);
1696 	if (bright < 0.0) bright = 0.0;
1697 	b_coeff = 1 - bright;
1698 
1699 	for (i = 0; i < 256; i++) {
1700 		ip = (float)i / 255.0;
1701 		pal[i].r = (cos(ip * M_PI / 2.0 + M_PI) + 1.0) * 255 * b_coeff + 255*bright;
1702 		pal[i].g = (sin(ip * M_PI / 2.0) * 255 + i) / 2 * b_coeff + 255*bright;
1703 		pal[i].b = sin(ip * M_PI / 2.0) * 255 * b_coeff + 255*bright;
1704 	}
1705 
1706 	SDL_SetPalette(screen, SDL_PHYSPAL, pal, 0, 256);
1707 }
1708 
IsSolid(unsigned char tile)1709 int IsSolid(unsigned char tile)
1710 {
1711 	return TileData[tile].Is_Solid;
1712 }
1713 
ActivateBossDoor(int x,int y)1714 void ActivateBossDoor(int x, int y)
1715 {
1716 	static int bd_timer = 0;
1717 	int bx = x, by = y;
1718 
1719 	// find boss room
1720 	if (rooms[GetRoom(x+1, y)].room_type == 2) {
1721 		bx += 1;
1722 	} else
1723 		if (rooms[GetRoom(x-1, y)].room_type == 2) {
1724 		bx -= 1;
1725 	} else
1726 		if (rooms[GetRoom(x, y+1)].room_type == 2) {
1727 		by += 1;
1728 	} else
1729 		if (rooms[GetRoom(x, y-1)].room_type == 2) {
1730 		by -= 1;
1731 	} else
1732 		return;
1733 
1734 	if (artifacts[8 + rooms[GetRoom(bx, by)].room_param]) {
1735 		opening_door_x = x;
1736 		opening_door_y = y;
1737 		opening_door_i = 1;
1738 		opening_door_n = rooms[GetRoom(bx, by)].room_param;
1739 		if ((SDL_GetTicks() - bd_timer) > 100) {
1740 			SND_Pos("/usr/local/share/meritous/a/crystal2.wav", 100, 0);
1741 			bd_timer = SDL_GetTicks();
1742 		}
1743 	}
1744 }
1745 
TouchTile(int ix,int iy)1746 int TouchTile(int ix, int iy)
1747 {
1748 		int i;
1749 		int off_x, off_y;
1750 		int ret = 1;
1751 		unsigned char tile;
1752 
1753 		for (i = 0; i < 4; i++) {
1754 			off_x = 15*(i%2);
1755 			off_y = 23*(i/2);
1756 
1757 			tile = Get((ix+off_x)/32, (iy+off_y)/32);
1758 			switch (tile) {
1759 				case 38:
1760 				case 39:
1761 				case 40:
1762 				case 41:
1763 					ActivateBossDoor((ix+off_x)/32, (iy+off_y)/32);
1764 					ret = 0;
1765 					break;
1766 				case 13:
1767 					player_x = (ix + off_x) / 32 * 32 + 8;
1768 					player_y = (iy/32 + 2)*32 + 32;
1769 					return 1;
1770 					break;
1771 				case 14:
1772 					player_x = (ix + off_x) / 32 * 32 + 8;
1773 					player_y = (iy/32 - 2)*32 + 8;
1774 					return 1;
1775 					break;
1776 				case 15:
1777 					player_x = (ix/32 + 2)*32 + 32;
1778 					player_y = (iy + off_y) / 32 * 32 + 4;
1779 					return 1;
1780 					break;
1781 				case 16:
1782 					player_x = (ix/32 - 2)*32 + 16;
1783 					player_y = (iy + off_y) / 32 * 32 + 4;
1784 					return 1;
1785 					break;
1786 				default:
1787 					if (TileData[tile].Is_Solid) ret = 0;
1788 					//ret = 0;
1789 					break;
1790 			}
1791 		}
1792 		if (ret == 1) {
1793 			player_x = ix;
1794 			player_y = iy;
1795 		}
1796 		return ret;
1797 }
1798 
text_init()1799 void text_init()
1800 {
1801 	FILE *font_data_file;
1802 	int chr, x, y;
1803 	font_data_file = fopen("/usr/local/share/meritous/d/font.dat", "rb");
1804 
1805 	for (chr = 0; chr < 128; chr++) {
1806 		for (y = 0; y < 8; y++) {
1807 			for (x = 0; x < 8; x++) {
1808 				font_data[chr][x][y] = fgetc(font_data_file);
1809 			}
1810 		}
1811 	}
1812 
1813 	fclose(font_data_file);
1814 }
1815 
draw_char(int cur_x,int cur_y,int c,Uint8 tcol)1816 void draw_char(int cur_x, int cur_y, int c, Uint8 tcol)
1817 {
1818 	int px, py;
1819 	Uint8 *pix;
1820 
1821 	for (py = 0; py < 8; py++) {
1822 		pix = (Uint8 *)screen->pixels;
1823 		pix += (py+cur_y)*screen->w;
1824 		pix += cur_x;
1825 
1826 		if ((cur_x >= 0)&&(py+cur_y >= 0)&&(cur_x < screen->w-8)&&(py+cur_y < screen->h)) {
1827 			for (px = 0; px < 8; px++) {
1828 				if (font_data[c][px][py] == 255) {
1829 					*pix = tcol;
1830 				}
1831 				if ((font_data[c][px][py] < 255)&&(font_data[c][px][py] > 0)) {
1832 					*pix = ((int)tcol * font_data[c][px][py] / 256) + ((int)*pix * (256-font_data[c][px][py]) / 256);
1833 				}
1834 				pix++;
1835 			}
1836 		}
1837 	}
1838 }
1839 
draw_text(int x,int y,char * str,Uint8 tcol)1840 void draw_text(int x, int y, char *str, Uint8 tcol)
1841 {
1842 	int c, cur_x, cur_y;
1843 
1844 	cur_x = x;
1845 	cur_y = y;
1846 
1847 	while (*str != 0) {
1848 		c = *(str++);
1849 		if (c == '\n') {
1850 			cur_x = x;
1851 			cur_y+=10;
1852 		} else {
1853 			draw_char(cur_x, cur_y, c, tcol);
1854 			cur_x+=8;
1855 		}
1856 	}
1857 }
1858 
draw_text_ex(int x,int y,char * str,Uint8 tcol,SDL_Surface * srf)1859 void draw_text_ex(int x, int y, char *str, Uint8 tcol, SDL_Surface *srf)
1860 {
1861 	Uint8 *pix;
1862 	int c, cur_x, cur_y, px, py;
1863 
1864 	cur_x = x;
1865 	cur_y = y;
1866 
1867 	while (*str != 0) {
1868 		c = *(str++);
1869 		if (c == '\n') {
1870 			cur_x = x;
1871 			cur_y+=8;
1872 		} else {
1873 			for (py = 0; py < 8; py++) {
1874 				pix = (Uint8 *)srf->pixels;
1875 				pix += (py+cur_y)*srf->w;
1876 				pix += cur_x;
1877 				for (px = 0; px < 8; px++) {
1878 					if (font_data[c][px][py]) {
1879 						*pix = tcol;
1880 					}
1881 					pix++;
1882 				}
1883 			}
1884 			cur_x+=8;
1885 		}
1886 	}
1887 }
1888 
LockDoors(int r)1889 void LockDoors(int r)
1890 {
1891 	//printf("Locking room %d...", r);
1892 	int x, y;
1893 	int rx, ry;
1894 	int rt;
1895 	int rcount = 0;
1896 
1897 	for (y = 0; y < rooms[r].h; y++) {
1898 		for (x = 0; x < rooms[r].w; x++) {
1899 			rx = x + rooms[r].x;
1900 			ry = y + rooms[r].y;
1901 			rt = Get(rx, ry);
1902 
1903 			if ((rt >= 13) && (rt <= 16)) {
1904 				rcount++;
1905 				Put(rx, ry, rt - 13 + 21, r);
1906 			}
1907 		}
1908 	}
1909 	//printf("locked %d doors\n", rcount);
1910 }
1911 
ActivateRoom(int room)1912 void ActivateRoom(int room)
1913 {
1914 	//printf("Activating room %d (type %d)\n", room, rooms[room].room_type);
1915 	if (rooms[room].checkpoint) {
1916 		checkpoints_found++;
1917 	}
1918 	if (rooms[room].room_type == 3) {
1919 		// lock the doors!
1920 		LockDoors(room);
1921 	}
1922 	ActivateEnemies(room);
1923 }
1924 
DrawRect(int x,int y,int w,int h,unsigned char c)1925 void DrawRect(int x, int y, int w, int h, unsigned char c)
1926 {
1927 	SDL_Rect r;
1928 
1929 	r.x = x;
1930 	r.y = y;
1931 	r.w = w;
1932 	r.h = h;
1933 
1934 	SDL_FillRect(screen, &r, c);
1935 }
1936 
DrawCircuit()1937 void DrawCircuit()
1938 {
1939 	int vd = 520;
1940 	char buf[20];
1941 
1942 	if (magic_circuit != 0) {
1943 		DrawRect(110, 469, 8+abs(magic_circuit) * vd / circuit_size, 9, (magic_circuit > 0) ? 159 : 72);
1944 		DrawRect(111, 470, 6+abs(magic_circuit) * vd / circuit_size, 7, (magic_circuit > 0) ? 183 : 80);
1945 		DrawRect(112, 471, 4+abs(magic_circuit) * vd / circuit_size, 5, (magic_circuit > 0) ? 207 : 96);
1946 		DrawRect(113, 472, 2+abs(magic_circuit) * vd / circuit_size, 3, (magic_circuit > 0) ? 231 : 112);
1947 		DrawRect(114, 473, abs(magic_circuit) * vd / circuit_size, 1, (magic_circuit > 0) ? 255 : 128);
1948 	}
1949 	sprintf(buf, "%.1f", fabs((float)magic_circuit / 100.0));
1950 	draw_text(115, 470, buf, 0);
1951 	draw_text(3, 469, "Psi Circuit", 200);
1952 }
1953 
ReleaseCircuit()1954 void ReleaseCircuit()
1955 {
1956 	circuit_release = 1;
1957 	release_range = circuit_range;
1958 	release_x = player_x;
1959 	release_y = player_y;
1960 	release_str = magic_circuit;
1961 	if (circuit_fillrate==30) {
1962 		release_str *= 1.25;
1963 	}
1964 
1965 	SND_CircuitRelease(release_str);
1966 	magic_circuit *= -1;
1967 }
1968 
DrawCircle(int x,int y,int r,unsigned char c)1969 void DrawCircle(int x, int y, int r, unsigned char c)
1970 {
1971 	int circ_y;
1972 
1973 	int len_x, outer_len_x, inner_len_x;
1974 
1975 	int inner_r = r - 10;
1976 	if (inner_r < 1) inner_r = 1;
1977 
1978 	if (r < 1) return;
1979 	// a^2 + b^2 = c^2
1980 	for (circ_y = 0; circ_y < r; circ_y++) {
1981 		if (circ_y < (r-10)) {
1982 			outer_len_x = sqrt(r*r - circ_y*circ_y);
1983 			inner_len_x = sqrt((r-10)*(r-10) - circ_y*circ_y);
1984 			DrawRect(x - outer_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
1985 			DrawRect(x + inner_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
1986 			DrawRect(x - outer_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
1987 			DrawRect(x + inner_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
1988 		} else {
1989 			len_x = sqrt(r*r - circ_y*circ_y);
1990 
1991 			DrawRect(x - len_x, y - circ_y, len_x*2, 1, c);
1992 			DrawRect(x - len_x, y + circ_y, len_x*2, 1, c);
1993 		}
1994 	}
1995 }
1996 
DrawCircleEx(int x,int y,int r,int r2,unsigned char c)1997 void DrawCircleEx(int x, int y, int r, int r2, unsigned char c)
1998 {
1999 	int circ_y;
2000 
2001 	int len_x, outer_len_x, inner_len_x;
2002 
2003 	int inner_r = r2;
2004 	int diffi = r-r2;
2005 	if (inner_r < 1) inner_r = 1;
2006 
2007 
2008 
2009 	if (r < 1) return;
2010 	// a^2 + b^2 = c^2
2011 	for (circ_y = 0; circ_y < r; circ_y++) {
2012 		if (circ_y < (r-diffi)) {
2013 			outer_len_x = sqrt(r*r - circ_y*circ_y);
2014 			inner_len_x = sqrt((r-diffi)*(r-diffi) - circ_y*circ_y);
2015 			DrawRect(x - outer_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
2016 			DrawRect(x + inner_len_x, y - circ_y, (outer_len_x - inner_len_x), 1, c);
2017 			DrawRect(x - outer_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
2018 			DrawRect(x + inner_len_x, y + circ_y, (outer_len_x - inner_len_x), 1, c);
2019 		} else {
2020 			len_x = sqrt(r*r - circ_y*circ_y);
2021 
2022 			DrawRect(x - len_x, y - circ_y, len_x*2, 1, c);
2023 			DrawRect(x - len_x, y + circ_y, len_x*2, 1, c);
2024 		}
2025 	}
2026 }
2027 
DrawShield()2028 void DrawShield()
2029 {
2030 	static int t=0;
2031 	int s_size;
2032 	int belts = 0;
2033 	int i, bpos;
2034 	t++;
2035 
2036 	if (player_shield == 0) return;
2037 	if (shield_hp == 0) return;
2038 
2039 	s_size = shield_hp;
2040 	if (s_size > 15) {
2041 		belts = s_size - 15;
2042 		s_size = 15;
2043 	}
2044 	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));
2045 
2046 	for (i = 0; i < belts; i++) {
2047 		bpos = 13 + (30 * (i+1) / (belts+1));
2048 		DrawCircleEx(320, 240, bpos + 1, bpos - 1, ((i+t)%6*12));
2049 	}
2050 }
2051 
ST_Teleport()2052 void ST_Teleport()
2053 {
2054 }
2055 
UpgradePrice(int t)2056 int UpgradePrice(int t)
2057 {
2058 	int price = 0;
2059 	switch (t) {
2060 		case 0:
2061 			price = (100 - training*50) * player_shield + (5<<player_shield) * (5 - training*2);
2062 			break;
2063 		case 1:
2064 			price = (80 - training*40) * circuit_fillrate + (5<<circuit_fillrate) * (4 - training*2);
2065 			break;
2066 		case 2:
2067 			price = (80 - training*40) * circuit_recoverrate + (5<<circuit_recoverrate) * (4 - training*2);
2068 			break;
2069 		default:
2070 			price = 123;
2071 			break;
2072 	}
2073 
2074 	return price;
2075 }
2076 
RoomTreasure(int room,int typ)2077 void RoomTreasure(int room, int typ)
2078 {
2079 	int treasure;
2080 	int given_treasure = 0;
2081 
2082 	if (typ == 0) {
2083 		// Treasure
2084 		treasure = rooms[room].room_param;
2085 		artifacts[treasure] = 1;
2086 		specialmessage = treasure + 1;
2087 		specialmessagetimer = 30;
2088 		SND_Pos("/usr/local/share/meritous/a/crystal2.wav", 128, 0);
2089 	}
2090 	if (typ == 1) {
2091 		// Reward
2092 		while (!given_treasure) {
2093 			treasure = rand() % 4;
2094 
2095 			switch (treasure) {
2096 				case 0:
2097 					specialmessage = 20;
2098 					player_gems += rand()%((1 << (rooms[room].s_dist / 7)) * 1500);
2099 					given_treasure = 1;
2100 					SND_Pos("/usr/local/share/meritous/a/tone.wav", 128, 0);
2101 					break;
2102 				case 1:
2103 					if (player_shield < 25) {
2104 						specialmessage = 10;
2105 						player_shield += 1;
2106 						given_treasure = 1;
2107 						SND_Pos("/usr/local/share/meritous/a/tone.wav", 128, 0);
2108 					}
2109 					break;
2110 				case 2:
2111 					if (circuit_fillrate < 25) {
2112 						specialmessage = 11;
2113 						circuit_fillrate += 1;
2114 						given_treasure = 1;
2115 						SND_Pos("/usr/local/share/meritous/a/tone.wav", 128, 0);
2116 					}
2117 					break;
2118 				case 3:
2119 					if (circuit_recoverrate < 25) {
2120 						specialmessage = 12;
2121 						circuit_recoverrate += 1;
2122 						given_treasure = 1;
2123 						SND_Pos("/usr/local/share/meritous/a/tone.wav", 128, 0);
2124 					}
2125 					break;
2126 				default:
2127 					break;
2128 			}
2129 		}
2130 		specialmessagetimer = 30;
2131 	}
2132 }
2133 
GetNearestCheckpoint(int nx,int ny)2134 int GetNearestCheckpoint(int nx, int ny)
2135 {
2136 	int i;
2137 	int nearest_checkpoint = -1;
2138 	int nearest_dist = 10000000;
2139 	int cp_x, cp_y, cp_dist;
2140 	int room_chk[3000] = {0};
2141 	int x, y, rx, ry;
2142 
2143 	i = GetRoom(nx/32, ny/32);
2144 	if (i != -1) {
2145 		room_chk[i] = 1;
2146 		if ((rooms[i].checkpoint != 0)&&(rooms[i].visited!=0)) {
2147 			nearest_checkpoint = i;
2148 		}
2149 	}
2150 	if (nearest_checkpoint == -1) {
2151 
2152 		for (y = 0; y < 54;) {
2153 			for (x = 0; x < 54;) {
2154 				rx = nx/32 - 27 + x;
2155 				ry = ny/32 - 27 + y;
2156 
2157 				i = GetRoom(rx, ry);
2158 				if (i != -1) {
2159 					if (room_chk[i] == 0) {
2160 						room_chk[i] = 1;
2161 						if ((rooms[i].checkpoint != 0)&&(rooms[i].visited!=0)) {
2162 							cp_x = rooms[i].x * 32 + rooms[i].w * 16;
2163 							cp_y = rooms[i].y * 32 + rooms[i].h * 16;
2164 							cp_dist = dist(cp_x, cp_y, nx, ny);
2165 							if (cp_dist < nearest_dist) {
2166 								nearest_dist = cp_dist;
2167 								nearest_checkpoint = i;
2168 							}
2169 						}
2170 					}
2171 				}
2172 				x += 2;
2173 			}
2174 			y += 2;
2175 		}
2176 
2177 	}
2178 
2179 	return nearest_checkpoint;
2180 }
2181 
TeleportPlayerToRoom(int c_room)2182 void TeleportPlayerToRoom(int c_room)
2183 {
2184 	if (c_room == 0) {
2185 		player_x = 8232;
2186 		player_y = 8108;
2187 	} else {
2188 		player_x = rooms[c_room].x * 32 + (rooms[c_room].w / 2 * 32) + 8;
2189 		player_y = rooms[c_room].y * 32 + (rooms[c_room].h / 2 * 32) + 4;
2190 	}
2191 	c_scroll_x = player_x;
2192 	c_scroll_y = player_y;
2193 	scroll_home = 1;
2194 }
2195 
2196 
TeleportPlayerToNextRoom()2197 void TeleportPlayerToNextRoom()
2198 {
2199 	int c_room;
2200 	c_room = (player_room + 1) % 3000;
2201 	while (! ((rooms[c_room].checkpoint!=0)&&(rooms[c_room].visited!=0))) {
2202 		c_room = (c_room + 1) % 3000;
2203 	}
2204 
2205 	if (c_room == 0) {
2206 		player_x = 8232;
2207 		player_y = 8108;
2208 	} else {
2209 		player_x = rooms[c_room].x * 32 + (rooms[c_room].w / 2 * 32) + 8;
2210 		player_y = rooms[c_room].y * 32 + (rooms[c_room].h / 2 * 32) + 4;
2211 	}
2212 	c_scroll_x = player_x;
2213 	c_scroll_y = player_y;
2214 	scroll_home = 1;
2215 }
2216 
ActivateTile(unsigned char tile,int x,int y)2217 void ActivateTile(unsigned char tile, int x, int y)
2218 {
2219 	int c_room;
2220 
2221 	enter_pressed = 0;
2222 	switch (tile) {
2223 		case 25:
2224 			if (artifacts[11]) break;
2225 
2226 			c_room = GetNearestCheckpoint(c_scroll_x, c_scroll_y);
2227 			if (tele_select) {
2228 				if (c_room != -1) {
2229 					if (c_room == player_room) {
2230 						TeleportPlayerToNextRoom();
2231 					} else {
2232 						TeleportPlayerToRoom(c_room);
2233 					}
2234 				}
2235 			} else {
2236 				map_enabled = 1;
2237 				game_paused = 1;
2238 				tele_select = 1;
2239 
2240 				c_scroll_x = player_x;
2241 				c_scroll_y = player_y;
2242 			}
2243 
2244 			break;
2245 		case 26:
2246 			RoomTreasure(GetRoom(x, y), (x+y)%2);
2247 			Put(x, y, 27, GetRoom(x, y));
2248 			break;
2249 		case 28:
2250 			if (player_shield >= 24) return;
2251 			if (player_gems >= UpgradePrice(0)) {
2252 				player_gems -= UpgradePrice(0);
2253 				player_shield += 1;
2254 				SND_Pos("/usr/local/share/meritous/a/crystal.wav", 128, 0);
2255 			}
2256 			break;
2257 		case 29:
2258 			if (circuit_fillrate >= 24) return;
2259 			if (player_gems >= UpgradePrice(1)) {
2260 				player_gems -= UpgradePrice(1);
2261 				circuit_fillrate += 1;
2262 				SND_Pos("/usr/local/share/meritous/a/crystal.wav", 128, 0);
2263 			}
2264 			break;
2265 		case 30:
2266 			if (circuit_recoverrate >= 24) return;
2267 			if (player_gems >= UpgradePrice(2)) {
2268 				player_gems -= UpgradePrice(2);
2269 				circuit_recoverrate += 1;
2270 				SND_Pos("/usr/local/share/meritous/a/crystal.wav", 128, 0);
2271 			}
2272 			break;
2273 		case 31:
2274 			DoSaveGame();
2275 			break;
2276 		case 32:
2277 			CrystalSummon();
2278 			SND_Pos("/usr/local/share/meritous/a/crystal.wav", 80, 0);
2279 			break;
2280 		default:
2281 			break;
2282 	}
2283 }
2284 
CompassPoint()2285 void CompassPoint()
2286 {
2287 	int nearest = 1000000;
2288 	int n_room = -1;
2289 	int i;
2290 	int loc_x, loc_y;
2291 	int cdist;
2292 	int rplx, rply;
2293 	int bosses_defeated = current_boss;
2294 	float pdir_1 = 0;
2295 	float pdir_2 = 0;
2296 	int pdir_1t = 0, pdir_2t = 0;
2297 
2298 	rplx = player_x + PLAYERW/2;
2299 	rply = player_y + PLAYERH/2;
2300 	// Find the nearest SIGNIFICANT LOCATION for the player
2301 
2302 	// Look at the three artifacts
2303 	// Unless the player is going for the place of power
2304 
2305 	if (current_boss < 3) {
2306 		for (i = 0; i < 3; i++) {
2307 			// Has the player got this artifact already?
2308 			if (artifacts[8+i] == 0) { // no
2309 				// Has the player already destroyed the boss?
2310 				if (rooms[i * 1000 + 999].room_type == 2) { // no
2311 					// Can the player get the artifact?
2312 					if (CanGetArtifact()) {
2313 						// Point player to this artifact room, if it is the nearest
2314 						loc_x = rooms[i * 1000 + 499].x * 32 + rooms[i * 1000 + 499].w * 16;
2315 						loc_y = rooms[i * 1000 + 499].y * 32 + rooms[i * 1000 + 499].h * 16;
2316 						cdist = dist(rplx, rply, loc_x, loc_y);
2317 						if (cdist < nearest) {
2318 							nearest = cdist;
2319 							n_room = i * 1000 + 499;
2320 						}
2321 					}
2322 				}
2323 			} else { // has artifact
2324 				// Has the player already destroyed the boss?
2325 				if (rooms[i * 1000 + 999].room_type == 2) { // no
2326 					// Point player to the boss room, if it is the nearest
2327 					loc_x = rooms[i * 1000 + 999].x * 32 + rooms[i * 1000 + 999].w * 16;
2328 					loc_y = rooms[i * 1000 + 999].y * 32 + rooms[i * 1000 + 999].h * 16;
2329 					cdist = dist(rplx, rply, loc_x, loc_y);
2330 					if (cdist < nearest) {
2331 						nearest = cdist;
2332 						n_room = i * 1000 + 999;
2333 					}
2334 				} else { // yes
2335 					bosses_defeated++;
2336 				}
2337 			}
2338 		}
2339 	}
2340 	// If, on the other hand, the player has destroyed all three bosses, point them towards the
2341 	// PLACE OF POWER
2342 	if (bosses_defeated == 3) {
2343 		// If the player already has the seal, point them to home
2344 		if (artifacts[11] == 1) {
2345 			loc_x = rooms[0].x * 32 + rooms[0].w * 16;
2346 			loc_y = rooms[0].y * 32 + rooms[0].h * 16;
2347 			cdist = dist(rplx, rply, loc_x, loc_y);
2348 			if (cdist < nearest) {
2349 				nearest = cdist;
2350 				n_room = 0;
2351 			}
2352 		} else {
2353 			// Can the player touch the seal?
2354 			if (CanGetArtifact()) {
2355 				loc_x = rooms[place_of_power].x * 32 + rooms[place_of_power].w * 16;
2356 				loc_y = rooms[place_of_power].y * 32 + rooms[place_of_power].h * 16;
2357 				cdist = dist(rplx, rply, loc_x, loc_y);
2358 				if (cdist < nearest) {
2359 					nearest = cdist;
2360 					n_room = place_of_power;
2361 				}
2362 			}
2363 		}
2364 	}
2365 
2366 	// Did we find a room? If so, point to it
2367 
2368 	if (n_room != -1) {
2369 		loc_x = rooms[n_room].x * 32 + rooms[n_room].w * 16;
2370 		loc_y = rooms[n_room].y * 32 + rooms[n_room].h * 16;
2371 
2372 		pdir_1 = PlayerDir(loc_x, loc_y) + M_PI;
2373 		pdir_1t = 1;
2374 
2375 		n_room = -1;
2376 	}
2377 
2378 	nearest = 1000000;
2379 	// Find the nearest uncleared artifact room
2380 	for (i = 0; i < 3000; i++) {
2381 		if (rooms[i].room_type == 3) {
2382 			loc_x = rooms[i].x * 32 + rooms[i].w * 16;
2383 			loc_y = rooms[i].y * 32 + rooms[i].h * 16;
2384 			cdist = dist(rplx, rply, loc_x, loc_y);
2385 			if (cdist < nearest) {
2386 				nearest = cdist;
2387 				n_room = i;
2388 			}
2389 		}
2390 	}
2391 
2392 	if (n_room != -1) {
2393 		loc_x = rooms[n_room].x * 32 + rooms[n_room].w * 16;
2394 		loc_y = rooms[n_room].y * 32 + rooms[n_room].h * 16;
2395 
2396 		pdir_2 = PlayerDir(loc_x, loc_y) + M_PI;
2397 		pdir_2t = 1;
2398 
2399 		n_room = -1;
2400 	}
2401 
2402 	// Did we find at least one thing to point to? If not, abort
2403 	if (!(pdir_1t || pdir_2t))
2404 		return;
2405 
2406 	DrawCircleEx(rplx - scroll_x, rply - scroll_y, 200, 190, 255);
2407 	if (pdir_1t)
2408 		DrawCircleEx(rplx - scroll_x + cos(pdir_1) * 170, rply - scroll_y + sin(pdir_1) * 170, 30, 20, 255);
2409 	if (pdir_2t)
2410 		DrawCircleEx(rplx - scroll_x + cos(pdir_2) * 170, rply - scroll_y + sin(pdir_2) * 170, 30, 20, 195);
2411 
2412 	for (i = 0; i < 50; i++) {
2413 		if (pdir_1t)
2414 			DrawCircle(rplx - scroll_x + cos(pdir_1) * (25 + i * 4), rply - scroll_y + sin(pdir_1) * (25 + i * 4), 5, 255);
2415 		if (pdir_2t)
2416 			DrawCircle(rplx - scroll_x + cos(pdir_2) * (25 + i * 4), rply - scroll_y + sin(pdir_2) * (25 + i * 4), 5, 195);
2417 	}
2418 	DrawCircleEx(rplx - scroll_x, rply - scroll_y, 30, 20, 255);
2419 
2420 	DrawCircleEx(rplx - scroll_x, rply - scroll_y, 197, 193, 128);
2421 	if (pdir_1t)
2422 		DrawCircleEx(rplx - scroll_x + cos(pdir_1) * 170, rply - scroll_y + sin(pdir_1) * 170, 27, 23, 128);
2423 	if (pdir_2t)
2424 		DrawCircleEx(rplx - scroll_x + cos(pdir_2) * 170, rply - scroll_y + sin(pdir_2) * 170, 27, 23, 78);
2425 
2426 	for (i = 0; i < 50; i++) {
2427 		if (pdir_1t)
2428 			DrawCircle(rplx - scroll_x + cos(pdir_1) * (25 + i * 4), rply - scroll_y + sin(pdir_1) * (25 + i * 4), 3, 128);
2429 		if (pdir_2t)
2430 			DrawCircle(rplx - scroll_x + cos(pdir_2) * (25 + i * 4), rply - scroll_y + sin(pdir_2) * (25 + i * 4), 3, 78);
2431 	}
2432 	DrawCircleEx(rplx - scroll_x, rply - scroll_y, 27, 23, 128);
2433 }
2434 
SpecialTile(int x,int y)2435 void SpecialTile(int x, int y)
2436 {
2437 	static int otext = 0;
2438 	static int t = 0;
2439 	unsigned char tile;
2440 	char message[100] = "";
2441 
2442 	tile = Get(x, y);
2443 	switch (tile) {
2444 		case 25:
2445 			if (artifacts[11]) {
2446 				sprintf(message, "This is a checkpoint, but it doesn't seem to be working");
2447 				break;
2448 			}
2449 			if (checkpoints_found <= 1) {
2450 				sprintf(message, "This is a checkpoint. You will return here when you die.");
2451 			} else {
2452 				sprintf(message, "Press ENTER to teleport between checkpoints.");
2453 			}
2454 			break;
2455 		case 26:
2456 			sprintf(message, "Press ENTER to open the storage chest");
2457 			break;
2458 		case 28:
2459 			if (player_shield >= 25) {
2460 				sprintf(message, "Your shield is already at full efficiency");
2461 			} else {
2462 				sprintf(message, "Press ENTER to upgrade shields (%d crystals)", UpgradePrice(0));
2463 			}
2464 			break;
2465 		case 29:
2466 			if (circuit_fillrate >= 25) {
2467 				sprintf(message, "Your circuit charge rate is already at its highest");
2468 			} else {
2469 				sprintf(message, "Press ENTER to upgrade circuit charge (%d crystals)", UpgradePrice(1));
2470 			}
2471 			break;
2472 		case 30:
2473 			if (circuit_recoverrate >= 25) {
2474 				sprintf(message, "Your circuit refill rate is already at its highest");
2475 			} else {
2476 				sprintf(message, "Press ENTER to upgrade circuit refill (%d crystals)", UpgradePrice(2));
2477 			}
2478 			break;
2479 		case 31:
2480 			sprintf(message, "Press ENTER to record your progress");
2481 			break;
2482 		case 32:
2483 			if (total_gems == 0) {
2484 				sprintf(message, "This is a crystal device. It isn't working at the moment.");
2485 			} else {
2486 				sprintf(message, "Press ENTER to activate the crystal device");
2487 			}
2488 			break;
2489 		case 42:
2490 			if (rooms[player_room].room_type == 5) {
2491 				if (CanGetArtifact(rooms[player_room].room_param)) {
2492 
2493 				} else {
2494 					sprintf(message, "The artifact is tainted with shadow. You must slay more of the shadow first.");
2495 				}
2496 			}
2497 			break;
2498 		case 53:
2499 			CompassPoint();
2500 			break;
2501 		default:
2502 			if (first_game) {
2503 				if (otext < 60) {
2504 					sprintf(message, "Press H to read the help file");
2505 					otext++;
2506 				}
2507 			}
2508 			break;
2509 	}
2510 
2511 	if (message[0] == 0) {
2512 		if (specialmessage != 0) {
2513 			switch (specialmessage) {
2514 				case 1: sprintf(message, "Ancient artifact: Complete Map"); break;
2515 				case 2: sprintf(message, "Ancient artifact: Shield boost"); break;
2516 				case 3: sprintf(message, "Ancient artifact: Extra crystal efficiency"); break;
2517 				case 4: sprintf(message, "Ancient artifact: Circuit booster"); break;
2518 				case 5: sprintf(message, "Ancient artifact: Metabolism increase"); break;
2519 				case 6: sprintf(message, "Ancient artifact: Dodge enhancer"); break;
2520 				case 7: sprintf(message, "Ancient artifact: Ethereal Monocle"); break;
2521 				case 8: sprintf(message, "Ancient artifact: Crystal gatherer"); break;
2522 
2523 				case 10: sprintf(message, "Enhancement: Shield upgrade"); break;
2524 				case 11: sprintf(message, "Enhancement: Circuit charge upgrade"); break;
2525 				case 12: sprintf(message, "Enhancement: Circuit refill upgrade"); break;
2526 
2527 				case 20: sprintf(message, "Reward: Psi crystals"); break;
2528 
2529 				case 30: sprintf(message, "Holy Sword 'Balmung' answers your call"); break;
2530 				case 31: sprintf(message, "Mystic Halberd 'Amenonuhoko' answers your call"); break;
2531 				case 32: sprintf(message, "Divine Bow 'Gandiva' answers your call"); break;
2532 				case 33: sprintf(message, "You capture the cursed seal. Return to the entrance"); break;
2533 
2534 				case 40: sprintf(message, "Balmung will remain here, where the ley lines are strong"); break;
2535 				case 41: sprintf(message, "Amenonuhoko will remain here, where the ley lines are strong"); break;
2536 				case 42: sprintf(message, "Gandiva will remain here, where the ley lines are strong"); break;
2537 
2538 				case 50: sprintf(message, ". . . . . .   retrieved 'Agate Knife'"); break;
2539 
2540 				default: sprintf(message, "ERROR: NO MESSAGE VALUE GIVEN"); break;
2541 			}
2542 			specialmessagetimer--;
2543 			if (specialmessagetimer <= 0) {
2544 				specialmessage = 0;
2545 			}
2546 		}
2547 	}
2548 
2549 	if (message[0] == 0) return;
2550 
2551 	DrawRect(320 - strlen(message)*8 / 2 - 20, 100, strlen(message)*8+40, 48, 200);
2552 	DrawRect(320 - strlen(message)*8 / 2 - 15, 105, strlen(message)*8+30, 38, 32);
2553 	DrawRect(320 - strlen(message)*8 / 2 - 10, 110, strlen(message)*8+20, 28, 64);
2554 
2555 	draw_text(320 - strlen(message)*8 / 2, 120, message, t%16<8 ? 255 : 192);
2556 	t++;
2557 	if (enter_pressed) {
2558 		ActivateTile(tile, x, y);
2559 	}
2560 }
2561 
ScrollTo(int x,int y)2562 void ScrollTo(int x, int y)
2563 {
2564 	static int scrollspeed_x = 1, scrollspeed_y = 1;
2565 	if (scroll_home == 0) {
2566 		scroll_x = x;
2567 		scroll_y = y;
2568 		return;
2569 	}
2570 
2571 	if (scroll_home == 1) {
2572 		scrollspeed_x = (x - scroll_x)/20;
2573 		scrollspeed_y = (y - scroll_y)/20;
2574 		scroll_home = 2;
2575 	}
2576 
2577 	if (scroll_home == 2) {
2578 		scroll_x += (x - scroll_x)/2;
2579 		scroll_y += (y - scroll_y)/2;
2580 
2581 		if ((abs(scroll_x-x)<2)&&(abs(scroll_y-y)<2)) {
2582 			scroll_x = x;
2583 			scroll_y = y;
2584 			scroll_home = 0;
2585 		}
2586 	}
2587 }
2588 
DrawArtifacts()2589 void DrawArtifacts()
2590 {
2591 	int i;
2592 	SDL_Rect from, to;
2593 
2594 	if (artifact_spr == NULL) {
2595 		artifact_spr = IMG_Load("/usr/local/share/meritous/i/artifacts.png");
2596 		SDL_SetColorKey(artifact_spr, SDL_SRCCOLORKEY | SDL_RLEACCEL, 0);
2597 	}
2598 
2599 	for (i = 0; i < 12; i++) {
2600 		if (artifacts[i]) {
2601 			from.x = i * 32;
2602 			from.y = 0;
2603 			from.w = 32;
2604 			from.h = 32;
2605 
2606 			to.x = 608;
2607 			to.y = 47 + i * 35;
2608 			SDL_BlitSurface(artifact_spr, &from, screen, &to);
2609 		}
2610 	}
2611 }
2612 
Swap(int * a,int * b)2613 void Swap(int *a, int *b)
2614 {
2615 	*a ^= *b ^= *a ^= *b;
2616 }
2617 
ThinLine(SDL_Surface * scr,int x1,int y1,int x2,int y2,Uint8 col)2618 void ThinLine(SDL_Surface *scr, int x1, int y1, int x2, int y2, Uint8 col)
2619 {
2620 	int dx, dy, dm;
2621 	int i, j;
2622 
2623 	dx = (x2 - x1);
2624 	dy = (y2 - y1);
2625 
2626 	dm = abs(dx) > abs(dy) ? dx : dy;
2627 
2628 	if (dm == 0) return;
2629 
2630 	if (dm < 0) {
2631 		Swap(&x1, &x2);
2632 		Swap(&y1, &y2);
2633 		dx = (x2 - x1);
2634 		dy = (y2 - y1);
2635 
2636 		dm = dm * -1;
2637 	}
2638 
2639 	if (dm == dx) {
2640 		if (dy == 0) {
2641 			DrawRect(x1, y1, x2-x1+1, 1, col);
2642 			return;
2643 		}
2644 		for (i = 0; i < dm; i++) {
2645 			j = (dy * i / dm);
2646 			DrawRect(i+x1, j+y1, 1, 1, col);
2647 		}
2648 	}
2649 	if (dm == dy) {
2650 		if (dx == 0) {
2651 			DrawRect(x1, y1, 1, y2-y1+1, col);
2652 			return;
2653 		}
2654 		for (i = 0; i < dm; i++) {
2655 			j = (dx * i / dm);
2656 			DrawRect(j+x1, i+y1, 1, 1, col);
2657 		}
2658 	}
2659 }
2660