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