1 #include "map.h"
2 #include "char.h"
3 #include "game.h"
4 
5 static char const *attacks[] = {
6 	"Chop!",
7 	"Clang!",
8 	"Ouch!",
9 	"Thud",
10 	"Clink!",
11 	"Shriek!",
12 	"Slash!",
13 	"Ugh!",
14 	"Claw!",
15 	"Crunch!",
16 	"Gnarl!",
17 	"Growl!",
18 	"Shred!",
19 	"Thump!"
20 };
21 
22 
23 static int pass_key=FALSE;
24 
25 /* C64: (Healing equation?)
26 
27     4 poke198,0:gd=0:p1=0:l1=0:b1=0:r1=50:s=20-l:gosub208:pokev3,0:ifs<1thens=1
28 
29    62 ifht<0then114
30    63 sp=sp+1:ifht<thandsp>ht/th*r1thenht=ht+1:print"(home)         ":sp=0
31 */
32 
player_health_add(int id,int health)33 static void player_health_add(int id, int health)
34 {
35 	list[id].hit+=health;
36 
37 	if(list[id].hit>list[id].maxhit)
38 		list[id].hit=list[id].maxhit;
39 
40 	update_stats ();
41 }
42 
43 
44 static void
healing(int id)45 healing (int id)
46 {
47 	int rate, multiplier;
48 	if (list[id].fighting || list[id].hit < 0 || paused)
49 		return;
50 
51 	list[id].healing_time++;
52 
53 	multiplier = map_get_spot (list[id].x, list[id].y) == SPOT_TEMPLE ? 1 : 0;
54 	multiplier += list[id].amulets_of_healing;
55 	multiplier = 1 << (list[id].spells[SPELL_REGENERATION].active + multiplier);
56 	rate = 10 * FPS * list[id].hit / (list[id].maxhit * multiplier);
57 
58 	if (list[id].hit < list[id].maxhit && list[id].healing_time > rate)
59 	{
60 		list[id].healing_time = 0;
61 		player_health_add(id, 1);
62 	}
63 }
64 
65 
66 /* C64: healing potion
67    60 hp=hp-1:x=int(20*rnd(1)+3*l):ht=ht+x:ifht>ththenht=th
68    61 gosub113:print"(home)healing potion taken!":gosub182:goto40
69 
70 */
drink_potion(int id)71 static int drink_potion(int id)
72 {
73 	if (list[id].potions && list[id].hit < list[id].maxhit)
74 	{
75 		list[id].potions--;
76 		player_health_add(id, rnd(0, 19)+3*list[id].current_level);
77 
78 		message (FPS * 2, potion, "Healing potion taken!");
79 		return TRUE;
80 	}
81 
82 	return FALSE;
83 }
84 
try_lose_map(int id)85 static void try_lose_map(int id)
86 {
87 	int r = rnd (1, 4);
88 	(void) id;
89 
90 	if (r == 1)
91 	{
92 		message (FPS * 2, NULL, "Lost your map!");
93 		map_hide_completely ();
94 	}
95 }
96 
97 static void
monster_step_back(int e)98 monster_step_back (int e)
99 {
100 	/* Step back in overlapping mode */
101 	int dx[] = {-1, -1,  0,  1, 1, 1,  0, -1};
102 	int dy[] = { 0, -1, -1, -1, 0, 1,  1,  1};
103 	static int d[] = {0, 1, 2, 3, 4, 5, 6, 7};
104 	int remaining = 8;
105 	/* Restore overlapped player. */
106 	map_put_char (list[e].x, list[e].y, 1);
107 	while (remaining)
108 	{
109 		int r = rnd (0, remaining - 1);
110 		int rd = d[r];
111 		int x = list[e].x + dx[rd];
112 		int y = list[e].y + dy[rd];
113 		if (map_get_spot (x, y) != SPOT_WALL && !map_get_char (x, y))
114 		{
115 			list[e].x += dx[rd];
116 			list[e].y += dy[rd];
117 			break;
118 		}
119 		remaining--;
120 		d[r] = d[remaining];
121 		d[remaining] = rd;
122 	}
123 	map_put_char (list[e].x, list[e].y, e);
124 }
125 
126 void
cancel_fighting(int id)127 cancel_fighting (int id)
128 {
129 	if (list[id].fighting)
130 	{
131 		int e = list[id].fighting;
132 		/* Weak monsters bring less XP! */
133 		list[e].maxhit = list[e].hit;
134 
135 		list[e].fighting = 0;
136 		list[e].attacked = 0;
137 		list[id].fighting = 0;
138 		list[id].attacked = 0;
139 		list[id].spells[SPELL_SHIELD].active = 0;
140 
141 		if (!extensions_overlapfight)
142 			map_put_char (list[e].x, list[e].y, e);
143 	}
144 }
145 
146 void
player_won(int id)147 player_won (int id)
148 {
149 	int e = list[id].fighting;
150 	// 298 s1=0:e=e+(s%+h1)*l:bs=bs+int(5*rnd(1)+1):mk=mk+1:k=32
151 	// 299 m%=0:gosub113:print"(home)you vanquished "x$:gosub112
152 	// or
153 	// 346 v1=0:s1=0:pokeo,a:e=e+(s%+h1)*l:bs=bs+int(5*rnd(1)+1):mk=mk+1
154 	// 347 print"(home)you have slain "x$:gosub300:w%=1:gosub175
155 
156 	list[id].exp += (list[e].dex + list[e].maxhit)*list[id].current_level;
157 	//rnd (m_bs / p_bs, 3 * m_bs / p_bs)
158 	if (extensions_balance)
159 	{
160 		list[id].dex+=rnd(((float)list[e].dex/list[id].dex),
161 		4*((float)list[e].dex/list[id].dex))+1;
162 	}
163 	else
164 	{
165  		list[id].dex+=rnd(1, 5);
166 	}
167 
168 	list[id].slain_foes[0]++;
169 	list[id].slain_foes[list[e].type]++;
170 
171 	if (list[id].attacked)
172 	{
173 		message (FPS * 2, victory, "You vanquished %s %s!",
174 			char_prefixes[list[e].type][list[e].subtype],
175 			char_names[list[e].type]);
176 	}
177 	else
178 	{
179 		message (FPS * 2, victory, "You have slain %s %s!",
180 			char_prefixes[list[e].type][list[e].subtype],
181 			char_names[list[e].type]);
182 	}
183 
184 	if (list[e].gold)
185 	{
186 	//  350 gosub113:print"(home)found your"g(v)"gold!!":t=t+g(v):goto274
187 		list[id].gold += list[e].gold;
188 		if(extensions_monsteraction)
189 		{
190 			message (FPS / 2, NULL, "Found %i gold!!", list[e].gold);
191 		}
192 		else
193 		{
194 			message (FPS / 2, NULL, "Found your %i gold!!", list[e].gold);
195 		}
196 	}
197 
198 	{
199 		int s;
200 		int got_stuff = 0;
201 		for (s = 0; s < 6; s++)
202 		{
203 			if (list[e].spells[s].amount)
204 			{
205 				got_stuff = 1;
206 				list[id].spells[s].amount += list[e].spells[s].amount;
207 			}
208 		}
209 		if (got_stuff)
210 			message (FPS / 2, NULL, "Found your spells!!");
211 	}
212 
213 	if (list[e].exp)
214 	{
215 		list[id].exp += list[e].exp;
216 		message (FPS / 2, NULL, "Regained your experience!!");
217 	}
218 
219 	monster_die (e);
220 	cancel_fighting (id);
221 
222 	if (!extensions_overlapfight)
223 		map_put_char (list[id].x, list[id].y, id);
224 }
225 
226 
fight_action(int e)227 static void fight_action(int e)
228 {
229 	int random_sound = rnd (0, 6);
230 	if (list[e].type >= CHAR_DIREWOLF)
231 	{
232 		message_ex(FPS * 1.25, creature[random_sound], 0, 50, 0, "%s",
233 			attacks[7 + random_sound]);
234 	}
235 	else
236 	{
237 		message_ex(FPS * 1.25, human[random_sound], 0, 50, 0, "%s",
238 			attacks[random_sound]);
239 	}
240 }
241 
242 
243 static void
player_fight(int id)244 player_fight (int id)
245 {
246 	int e = list[id].fighting;
247 	int my_attack, monster_attack;
248 	int max_damage;
249 	float skill_ratio;
250 
251 	update_stats ();
252 
253 	/* Assassin is visible during fight. */
254 	if (list[e].type == CHAR_ASSASSIN)
255 	{
256 		list[e].spells[SPELL_INVISIBILITY].active = 0;
257 		/* Redraw */
258 		map_put_char (list[e].x, list[e].y, e);
259 	}
260 
261 	if (!list[e].dex)
262 	{
263 		// 307 print"(home)the mage takes your magic spells!!":iv=0:rg=0:tp=0:sh=0:fa=0:lg=0:goto309
264 		// 308 print"(home)the demon drains your experience level!!":e=int(e/2):ifel>1thenel=el-1
265 		if (list[e].type >= CHAR_DIREWOLF)
266 		{
267 			message (FPS, NULL, "The demon drains your experience level!!");
268 			list[e].exp = list[id].exp / 2;
269 			list[id].exp -= list[e].exp;
270 
271 			if(!extensions_monsteraction)
272 				if (list[id].lev > 1)
273 					list[id].lev--;
274 
275 			list[e].trapped = 1;
276 			list[e].dex++;
277 		}
278 		else
279 		{
280 			int s;
281 			message (FPS, NULL, "The mage takes your magic spells!!");
282 			for (s = 0; s < 6; s++)
283 			{
284 				list[e].spells[s].amount = list[id].spells[s].amount;
285 				list[id].spells[s].amount = 0;
286 			}
287 			list[e].trapped = 1;
288 			list[e].dex++;
289 		}
290 
291 		//  309 m%=0:gosub112:gosub300:return
292 		if (extensions_monsteraction)
293 		{
294 			monster_teleport (e);
295 			if (!extensions_overlapfight)
296 				map_put_char (list[id].x, list[id].y, id);
297 		}
298 		else
299 			monster_die (e);
300 
301 		cancel_fighting (id);
302 		return;
303 	}
304 
305 	// C64: 286 x2=s%/bs:h1=h%
306 	skill_ratio=(float)list[id].dex/(list[e].dex);
307 	//290 h%=h%-int(1/x2*4*l*rnd(1)+1+pl):ifh%<0then298
308 	max_damage = (float)(skill_ratio) * 4 * list[id].current_level;
309 	my_attack = rnd (1, max_damage) + list[id].weapon;
310 
311 	// C64: 288 ht=ht-int(x2*4*l*rnd(1)+1)
312 	skill_ratio=(float)list[e].dex/(list[id].dex);
313 	max_damage = (float)skill_ratio * 4 * list[id].current_level;
314 	monster_attack = rnd (1, max_damage);
315 
316 	/* We are merely defending ourselves. */
317 	if (list[id].attacked)
318 	{
319 		// 286 x2=s%/bs:h1=h%
320 		// 287 ifs1=1then289
321 		// 288 ht=ht-int(x2*4*l*rnd(1)+1)
322 		if (!list[id].spells[SPELL_SHIELD].active)
323 		{
324 			player_health_add(id, -monster_attack);
325 			add_hit (list[id].x, list[id].y, -monster_attack);
326 		}
327 
328 		fight_action(e);
329 
330 		// 289 ifd=1andt>0orsf=1thenifx2<.5orx2>1orc=42then294
331 		if (list[e].type < CHAR_DIREWOLF && (list[id].gold || list[id].sword))
332 		{
333 			if (list[e].dex > list[id].dex || list[e].dex * 2 < list[id].dex ||
334 				list[e].type == CHAR_ROGUE)
335 			{
336 				// 294 gosub113:ifsf=1thensf=0:print"(home)the sword is stolen!!":gosub112:goto296
337             	// 295 d=-1:p=a:print"(home)your gold is stolen!!":gosub112:g(j)=t:t=0:goto386
338 
339 				if (list[id].sword)
340 				{
341 					list[e].sword = list[id].sword;
342 					list[id].sword = 0;
343 					message (FPS * 2, NULL, "The sword is stolen!!");
344 					list[e].trapped = 1;
345 					if (list[id].current_level == swordlev)
346 					{
347 						map_put_spot (19, 12, SPOT_SWORD);
348 					}
349 				}
350 				else
351 				{
352 					message (FPS * 2, NULL, "Your gold is stolen!!");
353 					list[e].gold = list[id].gold;
354 					list[id].gold = 0;
355 					list[e].trapped = 1;
356 				}
357 
358 				if (!extensions_overlapfight)
359 					monster_step_back (e);
360 
361 				cancel_fighting (id);
362 			}
363 		}
364 
365 		if (list[id].fighting)
366 		{
367 			// 290 h%=h%-int(1/x2*4*l*rnd(1)+1+pl):ifh%<0then298
368 			list[e].hit -= my_attack;
369 			add_hit (list[e].x, list[e].y, my_attack);
370 
371 			if (list[e].hit < 0)
372 				player_won (id);
373 			//  291 ifht<-5thengosub113:print"(home)slain by "x$:goto426
374 			else if (list[id].hit < -5)
375 			{
376 				player_die (id);
377 
378 				message (FPS, slain, "Slain by %s %s",
379 					char_prefixes[list[e].type][list[e].subtype],
380 					char_names[list[e].type]);
381 
382 				cancel_fighting(id);
383 			}
384 		}
385 	}
386 	else /* We are attacking. */
387 	{
388 		// 340 h%=h%-int(1/x*4*l*rnd(1)+1+pl):ifh%<0then346
389 		list[e].hit -= my_attack;
390 		if (list[e].dex)
391 		{
392 			add_hit (list[e].x, list[e].y, my_attack);
393 		}
394 
395 		if (list[e].hit < 0)
396 		{
397 			player_won (id);
398 		}
399 		else
400 		{
401 		// 341 ifs1=1then344
402 		// 342 ht=ht-int(x*4*l*rnd(1)+1)
403 		// 343 ifht<-5thenprint"(home)(rvon) (rvof) thou art slain!":goto426
404 
405 			fight_action(e);
406 
407 			if (!list[id].spells[SPELL_SHIELD].active)
408 			{
409 				player_health_add(id, -monster_attack);
410 				add_hit (list[id].x, list[id].y, -monster_attack);
411 
412 				if (list[id].hit < -5)
413 				{
414 					player_die (id);
415 					message (FPS, slain, "Thou art slain!");
416 					cancel_fighting (id);
417 				}
418 			}
419 		}
420 	}
421 }
422 
423 void
player_roll(int * health,int * skill)424 player_roll (int *health, int *skill)
425 {
426 	int i;
427 	/*
428 	- Hah! I new it! Initial roll for the player's stats (3d6):
429 
430 			443 fori=1to3:ht=ht+int(6*rnd(1)+1):bs=bs+int(6*rnd(1)+1):next
431 			444 sr=1:th=ht:ep=200:k=32:hp=1:tp=1:t1=100:ql=int(5*rnd(1)+15)
432 	- Quest Level is assigned in 'ql' above
433 	*/
434 	*health = 0;
435 	*skill = 0;
436 	for (i = 0; i < 3; i++)
437 	{
438 		*health += rnd (1, 6);
439 		*skill += rnd (1, 6);
440 	}
441 }
442 
443 int
player_create(int x,int y,int health,int skill)444 player_create (int x, int y, int health, int skill)
445 {
446 	int id = char_create (x, y);
447 
448 	list[id].type = CHAR_HERO;
449 	list[id].hit = health;
450 	list[id].dex = skill;
451 	list[id].maxhit = list[id].hit;
452 	list[id].next = 200;
453 	list[id].potions = 1;
454 	list[id].spells[SPELL_TELEPORT].amount = 1;
455 
456 	return id;
457 }
458 
459 static void
player_treasure(int id)460 player_treasure (int id)
461 {
462 	//  227 r=int(9*rnd(1)+1):onrgoto236,243,228,245,247,247,247,247,247
463 	int w = rnd (1, 9);
464 	int x = list[id].x;
465 	int y = list[id].y;
466 
467 	map_put_spot (x, y, SPOT_FLOOR);
468 
469 	switch (w)
470 	{
471 		case 1:
472 			// 236 p1=0:pokev3,peek(v3)and254:print"(home)pit!!...you fell!"
473 			// 237 h1=int(10*rnd(1)+l):k=61:pokem,k:pokeo,k:cl=1:gosub148:goto262
474 			// 238 p$="down":p1=1:p2=k:k=62:pt=int(4*rnd(1)+2)
475 			// 239 z=pt*p1:l=l+z:pokeo,p2:gosub113:print"(home)climbing the pit...";
476 			message (FPS, pit, "Pit!!... You fell!");
477 			map_put_spot (x, y, SPOT_PIT);
478 			map_put_info(x, y, rnd(2, 5));
479 			list[id].trapped = SPOT_PIT;
480 			break;
481 		case 2:
482 			//  243 pokev3,peek(v3)and254:print"(home)ceiling trap!"
483 			//  244 h1=int(10*rnd(1)+l):k=59:pokem,k:pokeo,k:gosub156:cl=1:goto262
484 			message (FPS, pit, "Ceiling trap!");
485 			map_put_spot (x, y, SPOT_CEILING);
486 			list[id].trapped = SPOT_CEILING;
487 			break;
488 		case 3:
489 			//  228 print"(home)explosion!!":pokes5,10:pokes6,42:pokes3,1:pokeso,12:pokes5+7,10:pokes6+7,42
490 			message (FPS, boom, "Explosion!!");
491 
492 			if (list[id].spells[SPELL_SHIELD].active)
493 			{
494 				//  234 s1=0:print"(home)shielded from blast!":gosub112
495 				list[id].spells[SPELL_SHIELD].active--;
496 				message (FPS, NULL, "Shielded from blast!");
497 			}
498 			else
499 			{
500 				// C64: 233 next:ifs1=0thenht=ht-int(15*rnd(1)+l):cl=1:goto235
501 				int h = rnd (0, 14)+list[1].current_level;
502 
503 				player_health_add(id, -h);
504 				add_hit (list[id].x, list[id].y, -h);
505 				try_lose_map(id);
506 			}
507 			break;
508 		case 4:
509 			//  245 print"(home)teleport...":k=32:pokem,k:pokeo,k:gosub144:o=n-d%:pokeo,a:pokeo+cm,1
510 			message (FPS, teleport, "Teleport...");
511 			char_teleport (id);
512 			try_lose_map(id);
513 			break;
514 		case 5:
515 		case 6:
516 		case 7:
517 		case 8:
518 		case 9:
519 		{
520 			//  247 w%=2:gosub175:e=e+int(50*rnd(1)+l):k=32:pokem,k:x=int(15*rnd(1)+1)
521 			//  248 onxgoto250,251,250,249,251,252,257,253,254,255,259,252,257,258,260
522 			list[id].exp += rnd (0, 49) + list[id].current_level;
523 			w = rnd (1, 15);
524 			switch (w)
525 			{
526 				case 1:
527 				case 2:
528 					//  250 print"(home)healing potion!!":hp=hp+1:goto274
529 					message (FPS, item, "Healing potion!!");
530 					list[id].potions++;
531 					break;
532 				case 3:
533 				case 4:
534 					//  251 print"(home)magic sack!!":bg=bg+1:t1=t1+100:goto274
535 					message (FPS, item, "Magic sack!!");
536 					list[id].sacks++;
537 					break;
538 				case 5:
539 					/* Played some more, and still spent time in the temple
540 					   healing in level 8. So now you can get amulets, at most
541 					   one after every 8 levels, and only a 1:2 chance instead
542 					   of a regeneration spell. The effect is just like a
543 					   permanent regeneration spell. */
544 					if (extensions_balance &&
545 						list[id].current_level > 8 * (1 + list[id].amulets_of_healing) &&
546 						!rnd (0, 2))
547 					{
548 						message (FPS, item, "Amulet of Healing!!");
549 						list[id].amulets_of_healing++;
550 					}
551 					else
552 					{
553 						//  249 print"(home)regeneration spell!!":rg=rg+1:goto274
554 						message (FPS, item, "Regeneration spell!!");
555 						list[id].spells[SPELL_REGENERATION].amount++;
556 					}
557 					break;
558 				case 6:
559 				case 7:
560 					//  252 print"(home)shield spell!!":sh=sh+1:goto274
561 					message (FPS, item, "Shield spell!!");
562 					list[id].spells[SPELL_SHIELD].amount++;
563 					break;
564 				case 8:
565 				case 9:
566 					//  257 print"(home)teleport spell!!":tp=tp+1:goto274
567 					message (FPS, item, "Teleport spell!!");
568 					list[id].spells[SPELL_TELEPORT].amount++;
569 					break;
570 				case 10:
571 					/* Since I added a healing amulet, thought could as well
572 					   add a light amulet. This is very unlikely to obtain right
573 					   now though (one per 15 levels, and 25% chance instead of
574 					   a spell. The effect is a permanent light spell. */
575 					if (extensions_balance &&
576 						list[id].current_level > 15 * (1 + list[id].amulets_of_light) &&
577 						!rnd (0, 3))
578 					{
579 						message (FPS, item, "Amulet of Light!!");
580 						list[id].amulets_of_light++;
581 					}
582 					else
583 					{
584 						//   253 print"(home)light spell!!":lg=lg+1:goto274
585 						message (FPS, item, "Light spell!!");
586 						list[id].spells[SPELL_LIGHT].amount++;
587 					}
588 					break;
589 				case 11:
590 					//  254 print"(home)enchanted weapon!!":pl=pl+1:bs=bs+int(10*rnd(1)+5):goto274
591 					message (FPS, item, "Enchanted weapon!!");
592 					list[id].weapon++;
593 					list[id].dex+=rnd(0, 9)+5;
594 					break;
595 				case 12:
596 					//  255 x=int(8*rnd(1)+l+3):print"(home)map to"x"th level!!"
597 					//  256 tm=tm+1:t%(tm)=x:goto274
598 					{
599 						int m = list[id].current_level + rnd (3, 10);
600 
601 						if(m==list[id].current_level)
602 						{
603 							message(FPS, item, "Treasure Map!!");
604 							map_seen (20, 12, 20);
605 						}
606 						else
607 						{
608 							message (FPS, item, "Map to %ith level!!!", m);
609 							list[id].map |= (1 << m);
610 						}
611 						break;
612 					}
613 				case 13:
614 					//  259 print"(home)invisibility spell!!":iv=iv+1:goto274
615 					message (FPS, item, "Invisibility spell!!");
616 					list[id].spells[SPELL_INVISIBILITY].amount++;
617 					break;
618 				case 14:
619 					//  258 print"(home)drift spell!!":fa=fa+1:goto274
620 					message (FPS, item, "Drift spell!!");
621 					list[id].spells[SPELL_DRIFT].amount++;
622 					break;
623 				case 15:
624 					//   260 print"(home)beacon!!":be=be+1:goto274
625 					message (FPS, item, "Beacon!!");
626 					list[id].beacons++;
627 					break;
628 			}
629 			break;
630 		}
631 	}
632 }
633 
634 
climb_pit(int id)635 static void climb_pit(int id)
636 {
637 	int x = list[id].x;
638 	int y = list[id].y;
639 
640 	int downsteps = map_get_info (x, y);
641 
642 	/* C64:
643 	238 p$="down":p1=1:p2=k:k=62:pt=int(4*rnd(1)+2)
644 	239 z=pt*p1:l=l+z:pokeo,p2:gosub113:print"(home)climbing the pit...";
645 	240 pokev3,peek(v3)and254:w1=int(2*rnd(1)+1):gosub171:y=int(2*rnd(1))
646 	241 ify=1thenprint"you fell!":h1=int(10*rnd(1)+3*pt+l):gosub148:goto261
647 	*/
648 
649 	list[id].current_level += downsteps;
650 	message (FPS, climb, "Climbing the pit...");
651 	if (!rnd (0, 1))
652 	{
653 		list[id].trapped = SPOT_PIT;
654 		message (0, pit, NULL);
655 	}
656 	map_enter (SPOT_ROPE, downsteps);
657 }
658 
659 
660 static void
player_action(int id)661 player_action (int id)
662 {
663 	int x = list[id].x;
664 	int y = list[id].y;
665 	int spot;
666 
667 	/*
668 		During fighting, try to teleport away.
669 		302 iftp>0then305
670 		303 ifsh>0ands1=0thensh=sh-1:s1=1:gosub113:print"(home)thy shield is in
671 		- This is only if attacked
672 		- Shield will be used if there's no teleport
673 	*/
674 	if (list[id].attacked)
675 	{
676 		if(!spell_cast (id, SPELL_TELEPORT))
677 		{
678 			if(!spell_cast(id, SPELL_SHIELD))
679 			{
680 				play_sample (ding, 250, 128, 1000, 0);
681 				return;
682 			}
683 		}
684 		else
685 		{
686 			// So that we can't cast both spells by accident
687 			list[id].attacked=0;
688 		}
689 
690 		return;
691 	}
692 
693 	if (list[id].trapped==SPOT_PIT)
694 	{
695 		if(!spell_cast (id, SPELL_DRIFT))
696 			play_sample (ding, 250, 128, 1000, 0);
697 		return;
698 	}
699 	else if (list[id].trapped==SPOT_CEILING)
700 	{
701 		if(!spell_cast (id, SPELL_TELEPORT))
702 			play_sample (ding, 250, 128, 1000, 0);
703 		return;
704 	}
705 
706 	spot=map_get_spot (x, y);
707 
708 	if(paused)
709 	{
710 		if(spot==SPOT_FLOOR)
711 		{
712 			play_sample (ding, 250, 128, 1000, 0);
713 			pass_key=TRUE;
714 		}
715 		return;
716 	}
717 
718 	switch (spot)
719 	{
720 		default:
721 			play_sample (ding, 250, 128, 1000, 0);
722 			pass_key=TRUE;
723 			break;
724 
725 		case SPOT_DOWN:
726 
727 			list[id].current_level++;
728 			message (FPS, down, "You go down the stairs.");
729 			map_enter (SPOT_UP, 1);
730 			break;
731 		case SPOT_UP:
732 			if (list[id].current_level == 1)
733 			{
734 				if (swordrun && list[id].sword)
735 				{
736 					// 111 print"(clr)(down)(down)(down)(down)(down)(down)(down)(down)(down)(down)        your quest is complete!!":gosub201:goto412
737 					message (FPS * 4, intro, "Your quest is complete!!");
738 					won = 1;
739 				}
740 				else
741 				{
742 					message (FPS, NULL, "Not without the Sword of Fargoal!");
743 				}
744 			}
745 			else
746 			{
747 				list[id].current_level--;
748 				message (FPS, up, "You go up the stairs.");
749 				map_enter (SPOT_DOWN, 1);
750 			}
751 			break;
752 		case SPOT_ROPE:
753 		{
754 			int upsteps = map_get_info (x, y);
755 
756 			list[id].current_level -= upsteps;
757 			message (FPS, climb, "Climbing the rope...");
758 			map_enter (SPOT_PIT, upsteps);
759 			break;
760 		}
761 		case SPOT_PIT:
762 		{
763 			climb_pit(id);
764 			break;
765 		}
766 		case SPOT_BEACON:
767 			//   92 ifk=44thenpokeo,k:k=38:o=b3:pokeo,a:pokeo+cm,1:gosub108:gosub146:gosub113:goto117
768 			message (FPS, teleport, NULL);
769 			char_transfer_to (id, temple_x, temple_y);
770 			break;
771 
772 		case SPOT_TREASURE:
773 			player_treasure (id);
774 			break;
775 	}
776 }
777 
778 static void
player_in_trap(int id)779 player_in_trap (int id)
780 {
781 	int x = list[id].x;
782 	int y = list[id].y;
783 	int s = map_get_spot (x, y);
784 	if (s == SPOT_PIT || s == SPOT_ROPE)
785 	{
786 		if (!list[id].spells[SPELL_DRIFT].active)
787 		{
788 			int h;
789 
790 			if (s == SPOT_PIT)
791 			{
792 				//  237 h1=int(10*rnd(1)+l):k=61:pokem,k:pokeo,k:cl=1:gosub148:goto262
793 				h = rnd(0, 9)+list[id].current_level;
794 				message (FPS, human[0], NULL);
795 			}
796 			else
797 			{
798 				//  241 ify=1thenprint"you fell!":h1=int(10*rnd(1)+3*pt+l):gosub148:goto261
799 				int upsteps = map_get_info (x, y);
800 				h = rnd (0, 9) + 3 * upsteps + list[id].current_level;
801 				message (FPS, human[0], "You fell!");
802 			}
803 
804 			player_health_add(id, -h);
805 			add_hit (list[id].x, list[id].y, -h);
806 		}
807 		else
808 		{
809 			list[id].spells[SPELL_DRIFT].active--;
810 			message (FPS, NULL, "like a feather...");
811 		}
812 	}
813 	/* Crushing ceiling. */
814 	if (s == SPOT_CEILING)
815 	{
816 		if (!list[id].spells[SPELL_TELEPORT].active)
817 		{
818 			/* C64:
819 				244 h1=int(10*rnd(1)+l):k=59:pokem,k:pokeo,k:
820 					gosub156:cl=1:goto262
821 			*/
822 
823 			int h = rnd (0, 9)+list[id].current_level;
824 
825 			message (FPS, crunch, NULL);
826 			player_health_add(id, -h);
827 			add_hit (list[id].x, list[id].y, -h);
828 
829 			try_lose_map(id);
830 		}
831 		else
832 		{
833 			list[id].spells[SPELL_TELEPORT].active--;
834 			char_teleport (1);
835 			message (FPS, NULL, "Teleport to safety!");
836 		}
837 	}
838 }
839 
840 void
player_try_levelup(int id)841 player_try_levelup (int id)
842 {
843 	/* C64: Level up
844 	   119 ep=ep*2:el=el+1:th=th+int(15*rnd(1)+5):bs=bs+int(10*rnd(1)+1)
845 	   - Implemented
846 	 */
847 	if (list[id].exp >= list[id].next)
848 	{
849 		float percentage = (float)list[id].hit / (float)list[id].maxhit;
850 		list[id].lev++;
851 		list[id].maxhit += rnd (1, 15)+4;
852 		list[id].dex += rnd (1, 10);
853 		if (extensions_balance)
854 			list[id].hit = percentage * list[id].maxhit + 0.5;
855 
856 		list[id].next *= 2;
857 		message (FPS, levelup, "Gained a level!");
858 		//printf ("maxhit = %i skill = %i\n", list[id].maxhit, list[id].dex);
859 	}
860 }
861 
862 void
player_die(int id)863 player_die (int id)
864 {
865 	(void) id;
866 	gameover = 1;
867 	spiral_map = MAP_W * MAP_H / 2;
868 }
869 
870 void
player_process(int id)871 player_process (int id)
872 {
873 	int x = list[id].x;
874 	int y = list[id].y;
875 	int i;
876 
877 	/* Keyboard state. */
878 	int dir_x = 0;
879 	int dir_y = 0;
880 
881 #if defined(_DEBUG) || defined(DEBUGMODE)
882 
883 	if (key[KEY_0])
884 	{
885 		player_health_add(id, -list[id].hit);;
886 	}
887 
888 	if (key[KEY_1])
889 	{
890 		list[id].spells[SPELL_SHIELD].amount=1;
891 		list[id].spells[SPELL_TELEPORT].amount=1;
892 		list[id].spells[SPELL_DRIFT].amount=1;
893 		list[id].spells[SPELL_LIGHT].amount=1;
894 		list[id].spells[SPELL_REGENERATION].amount=1;
895 		list[id].spells[SPELL_INVISIBILITY].amount=1;
896 		list[id].beacons++;
897 		list[id].potions++;
898 		list[id].gold+=50;
899 		list[id].dex=400;
900 		list[id].maxhit++;
901 		list[id].hit=list[id].maxhit;
902 		update_stats();
903 	}
904 
905 	if (key[KEY_2])
906 	{
907 		list[id].current_level=20;
908 		list[id].hit=list[id].maxhit;
909 		update_stats();
910 	}
911 
912 	if (key[KEY_3])
913 	{
914 		map_seen (20, 12, 20);
915 	}
916 
917 	if (key[KEY_4])
918 	{
919 		list[id].sword = 1;
920 		swordrun = SWORD_TIME;
921 	}
922 
923 	if (key[KEY_5])
924 	{
925 		list[id].amulets_of_healing = 1;
926 		list[id].amulets_of_light = 1;
927 		update_stats();
928 	}
929 
930 	if (key[KEY_6])
931 	{
932 		list[id].amulets_of_healing = 0;
933 		list[id].amulets_of_light = 0;
934 		update_stats();
935 	}
936 
937 #endif
938 
939 
940 	if (check_key_ex(KEY_LEFT, TRUE))
941 	{
942 		dir_x = -1;
943 	}
944 	if (check_key_ex(KEY_RIGHT, TRUE))
945 	{
946 		dir_x = 1;
947 	}
948 	if (check_key_ex(KEY_UP, TRUE))
949 	{
950 		dir_y = -1;
951 	}
952 	if (check_key_ex(KEY_DOWN, TRUE))
953 	{
954 		dir_y = 1;
955 	}
956 
957 	/* Check spell keys. */
958 	for (i = 0; i < 6; i++)
959 	{
960 		static int spellkeys[] = { KEY_I, KEY_R, KEY_T, KEY_S, KEY_L, KEY_D };
961 
962 		if (check_key (spellkeys[i]))
963 		{
964 			if (!spell_cast (id, i))
965 				play_sample (ding, 250, 128, 1000, 0);
966 		}
967 	}
968 
969 	if (check_key (KEY_B))
970 	{
971 		//  54 ifa$="+"andbe>0andb1=0thenbe=be-1:b1=1:k=44:b2=o:pokeo+d%,k:gosub113:print"(home)thy beacon is placed!":gosub150:goto40
972 		if (list[id].beacons && list[id].beaconx == 0 && list[id].beacony == 0)
973 		{
974 			if (map_get_spot (x, y) == SPOT_FLOOR)
975 			{
976 				map_put_spot (x, y, SPOT_BEACON);
977 				list[id].spells[SPELL_INVISIBILITY].active++;
978 				list[id].beacons--;
979 				list[id].beaconx = x;
980 				list[id].beacony = y;
981 				message (FPS, beacon, "Thy beacon is placed!");
982 			}
983 			else
984 			{
985 				message (FPS, ding, "Cannot place beacon here");
986 			}
987 		}
988 		else
989 			play_sample (ding, 250, 128, 1000, 0);
990 	}
991 
992 	if (check_key (KEY_H))
993 	{
994 		if (!drink_potion(id))
995 		{
996 			play_sample (ding, 250, 128, 1000, 0);
997 		}
998 
999 	}
1000 
1001 	if (check_key (KEY_LCONTROL) || check_key (KEY_RCONTROL) ||
1002 		check_key (KEY_SPACE) || check_key (KEY_ENTER))
1003 	{
1004 		player_action (id);
1005 	}
1006 
1007 	if (check_key (KEY_O))
1008 	{
1009 		//  121 gosub113:ifl1=1thenl1=2:print"(home)light off":gosub112:goto42
1010   		//  122 l1=1:gosub211:print"(home)light on":gosub112:goto42
1011 		if (list[id].spells[SPELL_LIGHT].active)
1012 		{
1013 			list[id].spells[SPELL_LIGHT].active = -list[id].spells[SPELL_LIGHT].active;
1014 			if (list[id].spells[SPELL_LIGHT].active > 0)
1015 				message (FPS, NULL, "Light on");
1016 			if (list[id].spells[SPELL_LIGHT].active < 0)
1017 				message (FPS, NULL, "Light off");
1018 		}
1019 		else
1020 			play_sample (ding, 250, 128, 1000, 0);
1021 	}
1022 
1023 	if (check_key (KEY_G))
1024 	{
1025 		//  124 ifgd>9ork<>32then41
1026 		//  125 gd=gd+1:k=60:pokeo+d%,k:g%(gd)=t:l%(gd)=o:gosub113
1027 		//  126 print"(home)hiding"t"gold pieces":t=0:gosub112:goto42
1028 		if (list[id].gold)
1029 		{
1030 			if (map_get_spot (x, y) == SPOT_FLOOR)
1031 			{
1032 				message (FPS, NULL, "Hiding %i gold pieces", list[id].gold);
1033 				map_put_spot (x, y, SPOT_STASH);
1034 				map_put_info (x, y, list[id].gold);
1035 				list[id].gold = 0;
1036 			}
1037 			else
1038 			{
1039 				message (FPS, ding, "Cannot bury gold here");
1040 			}
1041 		}
1042 		else
1043 			play_sample (ding, 250, 128, 1000, 0);
1044 	}
1045 
1046 	healing (id);
1047 
1048 	/* Game is currently paused. */
1049 	if (paused)
1050 	{
1051 		paused--;
1052 		char_move (id, 0, 0);
1053 
1054 		if (paused == 0)
1055 		{
1056 			if (list[id].trapped)
1057 			{
1058 				player_in_trap(id);
1059 				list[id].trapped = 0;
1060 			}
1061 		}
1062 	}
1063 	else						/* Not paused. */
1064 	{
1065 		if (!extensions_nomonsterpause)
1066 		{
1067 			if(!global_steps)
1068 			{
1069 				dir_x = dir_y = 0;
1070 			}
1071 		}
1072 
1073 		// See if player is trying to escape, and was not attacked
1074 		if (!list[id].attacked)
1075 		{
1076 			char_move (id, dir_x, dir_y);
1077 		}
1078 
1079 		if (!paused && !list[id].step)
1080 		{
1081 			// 114 ifhp>0then60
1082   			// 115 gosub113:print"(home)(rvon) (rvof) you died!!":goto426
1083 
1084 			/* Teleport spell? */
1085 			if (list[id].spells[SPELL_TELEPORT].active)
1086 			{
1087 				char_teleport (id);
1088 				cancel_fighting (id);
1089 				list[id].spells[SPELL_TELEPORT].active--;
1090 			}
1091 
1092 			/* Dead? */
1093 			if (list[id].hit < 0)
1094 			{
1095 				if (!drink_potion(id))
1096 				{
1097 					player_die (id);
1098 					message (FPS, slain, "You died!!");
1099 					return;
1100 				}
1101 			}
1102 
1103 			if (list[id].fighting)
1104 				player_fight (id);
1105 		}
1106 
1107 		player_try_levelup (id);
1108 	}
1109 }
1110 
1111 
1112 void
player_leave(int id)1113 player_leave (int id)
1114 {
1115 	int x = list[id].x;
1116 	int y = list[id].y;
1117 
1118 	switch (map_get_spot (x, y))
1119 	{
1120 		default:
1121 			break;
1122 		case SPOT_BEACON:
1123 		  list[id].spells[SPELL_INVISIBILITY].active--;
1124 		  update_stats();
1125 		break;
1126 	}
1127 }
1128 
1129 void
player_change_position(int id)1130 player_change_position (int id)
1131 {
1132 	int x = list[id].x;
1133 	int y = list[id].y;
1134 	int r = 1 + list[id].spells[SPELL_LIGHT].active + list[id].amulets_of_light;
1135 	int spot;
1136 
1137 	if (r < 1)
1138 		r = 1;
1139 
1140 	map_seen (x, y, r);
1141 
1142 	play_sample (step, 250, 128, 1000, 0);
1143 
1144 	if (extensions_nomonsterpause && global_steps)
1145 	{
1146 		global_steps--;
1147 		stepcount = (extensions_speed ? FPS : FPS*2);
1148 	}
1149 
1150 	spot=map_get_spot (x, y);
1151 
1152 	// TODO: if Pass key, clear key and return
1153 	if(pass_key&&spot!=SPOT_FLOOR&&spot!=SPOT_VOID)
1154 	{
1155 		pass_key=FALSE;
1156 		return;
1157 	}
1158 
1159 	switch (spot)
1160 	{
1161 		default:
1162 			break;
1163 
1164 		case SPOT_TREASURE:
1165 			if(!extensions_controls)
1166 				player_treasure (id);
1167 			break;
1168 
1169 		case SPOT_DOWN:
1170 			message (FPS / 2, down, "Stairs going down");
1171 			break;
1172 		case SPOT_UP:
1173 			message (FPS / 2, up, "Stairs going up");
1174 			break;
1175 
1176 		case SPOT_PIT:
1177 			if(extensions_controls)
1178 				message (FPS / 2, NULL, "Pit!");
1179 			else
1180 				climb_pit(id);
1181 			break;
1182 
1183 		case SPOT_ROPE:
1184 			message (FPS / 2, NULL, "Climbable pit above!");
1185 			break;
1186 		case SPOT_CEILING:
1187 			message (FPS / 2, NULL, "hole in the ceiling!");
1188 			break;
1189 		case SPOT_BEACON:
1190 			message (FPS * 2, beacon, "Swirling mists surround you!");
1191 		    /* Get invisible on beacon. */
1192 		    list[id].spells[SPELL_INVISIBILITY].active++;
1193 			break;
1194 		case SPOT_SWORD:
1195 			//   94 gosub113:print"(home)the sword of fargoal!!":gosub201:sf=1:k=32:pokem,k:ift2=0thene=e*2:t2=ti
1196    			//   95 goto274
1197 			list[id].sword++;
1198 			if (swordrun == 0)
1199 			{
1200 				list[id].exp *= 2;
1201 				swordrun = SWORD_TIME;
1202 			}
1203 			message (FPS * 4, intro, "The Sword of Fargoal!!");
1204 			map_put_spot (x, y, SPOT_FLOOR);
1205 			break;
1206 		case SPOT_GOLD:
1207 		{
1208 			// 216 y=int(20*rnd(1)+10*l):print"(home)treasure: "y"gp's":gosub165:ift+y>t1then218
1209 			// 217 t=t+y:k=32:pokem,k:goto40
1210 			// 218 ifgd>9then40
1211 			// 219 gd=gd+1:k=60:pokem,k:g%(gd)=t+y-t1:l%(gd)=o:ift=t1then221
1212 			// 220 t=t1:print"(home)can't carry more gold":goto274
1213 			// 221 print"(home)hiding the gold      ":goto274
1214 			int max = 100 + list[id].sacks * 100;
1215 			int g = 10 * list[id].current_level + rnd (0, 19);
1216 
1217 			//if(extensions_controls && max <= list[id].gold)
1218 			//	break;
1219 
1220 			message (FPS, gold, "Treasure: %i GP's", g);
1221 
1222 			if (list[id].gold + g <= max)
1223 			{
1224 				map_put_spot (x, y, SPOT_FLOOR);
1225 				list[id].gold += g;
1226 			}
1227 			else
1228 			{
1229 				map_put_spot (x, y, SPOT_STASH);
1230 				map_put_info (x, y, list[id].gold + g - max);
1231 				if (list[id].gold < max)
1232 				{
1233 					list[id].gold= max;
1234 					message (FPS/2, NULL, "Can't carry more gold");
1235 				}
1236 				else
1237 				{
1238 					message (FPS/2, NULL, "Hiding the gold");
1239 				}
1240 			}
1241 			break;
1242 		}
1243 		case SPOT_STASH:
1244 		{
1245 			//  222 print"(home)hidden treasure!!":gosub165:forj=1togd:ifo=l%(j)thenv=j:j=gd
1246   			//  223 next
1247 			//  224 z=g%(v):ift+z>t1then226
1248 			//  225 t=t+z:k=32:pokem,k:goto40
1249 			//  226 g%(v)=t+z-t1:t=t1:gosub113:print"(home)gold too heavy":goto274
1250 			int max = 100 + list[id].sacks * 100;
1251 			int g = map_get_info (x, y);
1252 
1253 			if(max<=list[id].gold)
1254 				break;
1255 
1256 			message (FPS / 2, gold, "Hidden Treasure!!");
1257 
1258 			if (list[id].gold + g <= max)
1259 			{
1260 				list[id].gold += g;
1261 				map_put_spot (x, y, SPOT_FLOOR);
1262 			}
1263 			else
1264 			{
1265 				map_put_info (x, y, list[id].gold + g - max);
1266 				list[id].gold= max;
1267 				message (FPS/2, NULL, "Gold too heavy");
1268 			}
1269 			break;
1270 		}
1271 		case SPOT_TEMPLE:
1272 			if (list[id].gold)
1273 			{
1274 				message (FPS, sacrifice, "Sacrifice of gold!");
1275 				list[id].exp += list[id].gold;
1276 				if (extensions_balance)
1277 				{
1278 					{
1279 						list[id].sacrificed_gold+=list[id].gold;
1280 						if(list[id].sacrificed_gold>=TEMPLE_GOLD &&
1281 							list[id].hit<list[id].maxhit)
1282 						{
1283 							list[id].sacrificed_gold-=TEMPLE_GOLD;
1284 							player_health_add(id, list[id].maxhit);
1285 							message (FPS, item, "You are blessed!");
1286 						}
1287 
1288 						/*
1289 							PP: I wonder if we should still add faster temple
1290 							healing, perhaps with regeneration... so that
1291 							regen + temple is quite fast
1292 						*/
1293 
1294 					}
1295 				}
1296 				list[id].gold = 0;
1297 			}
1298 			else
1299 			{
1300 				message (FPS/2, NULL, "Temple!");
1301 			}
1302 			break;
1303 	}
1304 }
1305