1 /* $NetBSD: interplayer.c,v 1.11 2009/08/12 08:21:41 dholland Exp $ */
4 * interplayer.c - player to player routines for Phantasia
14 #include "phantdefs.h"
15 #include "phantstruct.h"
16 #include "phantglobs.h"
17 #include "pathnames.h"
22 static long allocvoid(void);
23 static void battleplayer(long);
24 static void myturn(void);
25 static void tampered(int, double, double);
30 long foeloc
= 0L; /* location in file of person to fight */
33 fseek(Playersfp
, 0L, SEEK_SET
);
35 while (fread((char *) &Other
, SZ_PLAYERSTRUCT
, 1, Playersfp
) == 1) {
36 if (Other
.p_status
!= S_OFF
37 && Other
.p_status
!= S_NOTUSED
38 && Other
.p_status
!= S_HUNGUP
39 && (Other
.p_status
!= S_CLOAKED
|| Other
.p_specialtype
!= SC_VALAR
))
40 /* player is on and not a cloaked valar */
44 if (Player
.p_x
== Other
.p_x
45 && Player
.p_y
== Other
.p_y
46 /* same coordinates */
49 && Player
.p_status
== S_PLAYING
50 && (Other
.p_status
== S_PLAYING
|| Other
.p_status
== S_INBATTLE
)
51 /* both are playing */
52 && Other
.p_specialtype
!= SC_VALAR
53 && Player
.p_specialtype
!= SC_VALAR
)
54 /* neither is valar */
60 foeloc
+= SZ_PLAYERSTRUCT
;
65 battleplayer(long foeplace
)
67 double dtemp
; /* for temporary calculations */
68 double oldhits
= 0.0; /* previous damage inflicted by foe */
69 int loop
; /* for timing out */
71 short oldtampered
; /* old value of foe's p_tampered */
75 mvaddstr(4, 0, "Preparing for battle!\n");
82 /* set up variables, file, etc. */
83 Player
.p_status
= S_INBATTLE
;
84 Shield
= Player
.p_energy
;
86 /* if p_tampered is not 0, someone else may try to change it (king,
88 Player
.p_tampered
= oldtampered
= 1;
89 Player
.p_1scratch
= 0.0;
90 Player
.p_istat
= I_OFF
;
92 readrecord(&Other
, foeplace
);
93 if (fabs(Player
.p_level
- Other
.p_level
) > 20.0)
94 /* see if players are greatly mismatched */
96 dtemp
= (Player
.p_level
- Other
.p_level
) / MAX(Player
.p_level
, Other
.p_level
);
98 /* foe outweighs this one */
99 Player
.p_speed
*= 2.0;
101 writerecord(&Player
, Fileloc
); /* write out all our info */
103 if (Player
.p_blindness
)
104 Enemyname
= "someone";
106 Enemyname
= Other
.p_name
;
108 mvprintw(6, 0, "You have encountered %s Level: %.0f\n", Enemyname
, Other
.p_level
);
111 for (loop
= 0; Other
.p_status
!= S_INBATTLE
&& loop
< 30; ++loop
)
112 /* wait for foe to respond */
114 readrecord(&Other
, foeplace
);
118 if (Other
.p_status
!= S_INBATTLE
)
119 /* foe did not respond */
121 mvprintw(5, 0, "%s is not responding.\n", Enemyname
);
124 /* else, we are ready to battle */
130 * determine who is first master
131 * if neither player is faster, check level
132 * if neither level is greater, battle is not allowed
133 * (this should never happen, but we have to handle it)
135 if (Player
.p_speed
> Other
.p_speed
)
138 if (Other
.p_speed
> Player
.p_speed
)
141 if (Player
.p_level
> Other
.p_level
)
144 if (Other
.p_level
> Player
.p_level
)
147 /* no one is faster */
149 printw("You can't fight %s yet.", Enemyname
);
156 mvprintw(1, 26, "%20.0f", Shield
); /* overprint energy */
159 /* take action against foe */
162 /* wait for foe to take action */
164 mvaddstr(4, 0, "Waiting...\n");
168 for (loop
= 0; loop
< 20; ++loop
)
169 /* wait for foe to act */
171 readrecord(&Other
, foeplace
);
172 if (Other
.p_1scratch
!= oldhits
)
173 /* p_1scratch changes to indicate
177 /* wait and try again */
185 if (Other
.p_1scratch
== oldhits
) {
187 mvaddstr(22, 0, "Timeout: waiting for response. Do you want to wait ? ");
188 ch
= getanswer("NY", FALSE
);
196 /* foe took action */
198 switch (Other
.p_istat
) {
199 case I_RAN
: /* foe ran away */
200 mvprintw(Lines
++, 0, "%s ran away!", Enemyname
);
203 case I_STUCK
: /* foe tried to run, but
205 mvprintw(Lines
++, 0, "%s tried to run away.", Enemyname
);
208 case I_BLEWIT
: /* foe tried to luckout, but
210 mvprintw(Lines
++, 0, "%s tried to luckout!", Enemyname
);
214 dtemp
= Other
.p_1scratch
- oldhits
;
215 mvprintw(Lines
++, 0, "%s hit you %.0f times!", Enemyname
, dtemp
);
220 oldhits
= Other
.p_1scratch
; /* keep track of old
223 if (Other
.p_tampered
!= oldtampered
)
224 /* p_tampered changes to relinquish
227 oldtampered
= Other
.p_tampered
;
233 /* decide what happens next */
235 if (Lines
> LINES
- 2) {
240 if (Other
.p_istat
== I_KILLED
|| Shield
< 0.0)
243 Shield
= -2.0; /* insure this value is negative */
246 if (Player
.p_istat
== I_KILLED
)
247 /* we killed foe; award treasre */
249 mvprintw(Lines
++, 0, "You killed %s!", Enemyname
);
250 Player
.p_experience
+= Other
.p_experience
;
251 Player
.p_crowns
+= (Player
.p_level
< 1000.0) ? Other
.p_crowns
: 0;
252 Player
.p_amulets
+= Other
.p_amulets
;
253 Player
.p_charms
+= Other
.p_charms
;
254 collecttaxes(Other
.p_gold
, Other
.p_gems
);
255 Player
.p_sword
= MAX(Player
.p_sword
, Other
.p_sword
);
256 Player
.p_shield
= MAX(Player
.p_shield
, Other
.p_shield
);
257 Player
.p_quksilver
= MAX(Player
.p_quksilver
, Other
.p_quksilver
);
258 if (Other
.p_virgin
&& !Player
.p_virgin
) {
259 mvaddstr(Lines
++, 0, "You have rescued a virgin. Will you be honorable ? ");
260 if ((ch
= getanswer("YN", FALSE
)) == 'Y')
261 Player
.p_virgin
= TRUE
;
264 Player
.p_experience
+= 8000.0;
267 sleep(3); /* give other person time to die */
270 if (Player
.p_istat
== I_RAN
|| Other
.p_istat
== I_RAN
)
271 /* either player ran away */
276 /* clean up things and leave */
277 writerecord(&Player
, Fileloc
); /* update a final time */
278 altercoordinates(0.0, 0.0, A_NEAR
); /* move away from battle site */
279 Player
.p_energy
= Shield
; /* set energy to actual value */
280 Player
.p_tampered
= T_OFF
; /* clear p_tampered */
282 more(Lines
); /* pause */
285 clrtobot(); /* clear bottom area of screen */
287 if (Player
.p_energy
< 0.0)
289 death("Interterminal battle");
295 double dtemp
; /* for temporary calculations */
298 mvaddstr(7, 0, "1:Fight 2:Run Away! 3:Power Blast ");
302 addstr("4:Luckout ");
310 dtemp
= ROLL(2.0, Player
.p_might
);
312 mvprintw(Lines
++, 0, "You hit %s %.0f times!", Enemyname
, dtemp
);
314 Player
.p_1scratch
+= dtemp
;
315 Player
.p_istat
= I_OFF
;
318 case '2': /* run away */
319 Player
.p_1scratch
-= 1.0; /* change this to indicate
321 if (drandom() > 0.25) {
322 mvaddstr(Lines
++, 0, "You got away!");
323 Player
.p_istat
= I_RAN
;
325 mvprintw(Lines
++, 0, "%s is still after you!", Enemyname
);
326 Player
.p_istat
= I_STUCK
;
330 case '3': /* power blast */
331 dtemp
= MIN(Player
.p_mana
, Player
.p_level
* 5.0);
332 Player
.p_mana
-= dtemp
;
333 dtemp
*= (drandom() + 0.5) * Player
.p_magiclvl
* 0.2 + 2.0;
334 mvprintw(Lines
++, 0, "You blasted %s !", Enemyname
);
337 case '4': /* luckout */
338 if (Luckout
|| drandom() > 0.1) {
340 mvaddstr(Lines
++, 0, "You already tried that!");
342 mvaddstr(Lines
++, 0, "Not this time . . .");
346 Player
.p_1scratch
-= 1.0;
347 Player
.p_istat
= I_BLEWIT
;
349 mvaddstr(Lines
++, 0, "You just lucked out!");
350 Player
.p_1scratch
= Other
.p_energy
* 1.1;
356 Player
.p_1scratch
= floor(Player
.p_1scratch
); /* clean up any mess */
358 if (Player
.p_1scratch
> Other
.p_energy
)
359 Player
.p_istat
= I_KILLED
;
361 if (drandom() * Player
.p_speed
< drandom() * Other
.p_speed
)
362 /* relinquish control */
367 writerecord(&Player
, Fileloc
); /* let foe know what we did */
373 long loc
= 0L; /* location in energy void file */
375 /* first check for energy voids */
376 fseek(Energyvoidfp
, 0L, SEEK_SET
);
377 while (fread((char *) &Enrgyvoid
, SZ_VOIDSTRUCT
, 1, Energyvoidfp
) == 1)
378 if (Enrgyvoid
.ev_active
379 && Enrgyvoid
.ev_x
== Player
.p_x
380 && Enrgyvoid
.ev_y
== Player
.p_y
)
384 /* not the holy grail; inactivate energy void */
386 Enrgyvoid
.ev_active
= FALSE
;
387 writevoid(&Enrgyvoid
, loc
);
388 tampered(T_NRGVOID
, 0.0, 0.0);
390 if (Player
.p_status
!= S_CLOAKED
)
392 tampered(T_GRAIL
, 0.0, 0.0);
395 loc
+= SZ_VOIDSTRUCT
;
397 /* now check for other things */
398 readrecord(&Other
, Fileloc
);
399 if (Other
.p_tampered
!= T_OFF
)
400 tampered(Other
.p_tampered
, Other
.p_1scratch
, Other
.p_2scratch
);
404 tampered(int what
, double arg1
, double arg2
)
406 long loc
; /* location in file of other players */
411 Player
.p_tampered
= T_OFF
; /* no longer tampered with */
415 addstr("You've hit an energy void !\n");
416 Player
.p_mana
/= 3.0;
417 Player
.p_energy
/= 2.0;
418 Player
.p_gold
= floor(Player
.p_gold
/ 1.25) + 0.1;
419 altercoordinates(0.0, 0.0, A_NEAR
);
423 addstr("The king transported you ! ");
424 if (Player
.p_charms
> 0) {
425 addstr("But your charm saved you. . .\n");
428 altercoordinates(0.0, 0.0, A_FAR
);
434 printw("The king has bestowed %.0f gold pieces on you !\n", arg1
);
435 Player
.p_gold
+= arg1
;
439 addstr("You've been cursed ! ");
440 if (Player
.p_blessing
) {
441 addstr("But your blessing saved you. . .\n");
442 Player
.p_blessing
= FALSE
;
445 Player
.p_poison
+= 2.0;
446 Player
.p_energy
= 10.0;
447 Player
.p_maxenergy
*= 0.95;
448 Player
.p_status
= S_PLAYING
; /* no longer cloaked */
453 addstr("You have been vaporized!\n");
455 death("Vaporization");
459 addstr("The Valar zapped you with a monster!\n");
461 encounter((int) arg1
);
465 addstr("The Valar has blessed you!\n");
466 Player
.p_energy
= (Player
.p_maxenergy
*= 1.05) + Player
.p_shield
;
467 Player
.p_mana
+= 500.0;
468 Player
.p_strength
+= 0.5;
469 Player
.p_brains
+= 0.5;
470 Player
.p_magiclvl
+= 0.5;
471 Player
.p_poison
= MIN(0.5, Player
.p_poison
);
475 addstr("You've been relocated. . .\n");
476 altercoordinates(arg1
, arg2
, A_FORCED
);
480 addstr("You've been healed!\n");
481 Player
.p_poison
-= 0.25;
482 Player
.p_energy
= Player
.p_maxenergy
+ Player
.p_shield
;
486 addstr("You are no longer Valar!\n");
487 Player
.p_specialtype
= SC_COUNCIL
;
491 addstr("You have found The Holy Grail!!\n");
492 if (Player
.p_specialtype
< SC_COUNCIL
)
493 /* must be council of wise to behold grail */
495 addstr("However, you are not experienced enough to behold it.\n");
496 Player
.p_sin
*= Player
.p_sin
;
497 Player
.p_mana
+= 1000;
499 if (Player
.p_specialtype
== SC_VALAR
500 || Player
.p_specialtype
== SC_EXVALAR
) {
501 addstr("You have made it to the position of Valar once already.\n");
502 addstr("The Grail is of no more use to you now.\n");
504 addstr("It is now time to see if you are worthy to behold it. . .\n");
508 if (drandom() / 2.0 < Player
.p_sin
) {
509 addstr("You have failed!\n");
516 Player
.p_experience
=
517 Player
.p_quickness
= 1.0;
519 altercoordinates(1.0, 1.0, A_FORCED
);
520 Player
.p_level
= 0.0;
522 addstr("You made to position of Valar!\n");
523 Player
.p_specialtype
= SC_VALAR
;
525 fseek(Playersfp
, 0L, SEEK_SET
);
527 while (fread((char *) &Other
, SZ_PLAYERSTRUCT
, 1, Playersfp
) == 1)
528 /* search for existing valar */
529 if (Other
.p_specialtype
== SC_VALAR
530 && Other
.p_status
!= S_NOTUSED
)
531 /* found old valar */
533 Other
.p_tampered
= T_EXVALAR
;
534 writerecord(&Other
, loc
);
537 loc
+= SZ_PLAYERSTRUCT
;
541 /* move grail to new location */
542 Enrgyvoid
.ev_active
= TRUE
;
543 Enrgyvoid
.ev_x
= ROLL(-1.0e6
, 2.0e6
);
544 Enrgyvoid
.ev_y
= ROLL(-1.0e6
, 2.0e6
);
545 writevoid(&Enrgyvoid
, 0L);
553 userlist(phbool ingameflag
)
555 int numusers
= 0; /* number of users on file */
557 if (ingameflag
&& Player
.p_blindness
) {
558 mvaddstr(8, 0, "You cannot see anyone.\n");
561 fseek(Playersfp
, 0L, SEEK_SET
);
563 "Name X Y Lvl Type Login Status\n");
565 while (fread((char *) &Other
, SZ_PLAYERSTRUCT
, 1, Playersfp
) == 1) {
566 if (Other
.p_status
== S_NOTUSED
567 /* record is unused */
568 || (Other
.p_specialtype
== SC_VALAR
&& Other
.p_status
== S_CLOAKED
))
572 /* wizard can see everything on file */
578 /* must be playing for the rest of these conditions */
579 (Player
.p_specialtype
>= SC_KING
580 /* kings and higher can see others */
581 || Other
.p_specialtype
>= SC_KING
582 /* kings and higher can be seen by others */
583 || Circle
>= CIRCLE(Other
.p_x
, Other
.p_y
)
584 /* those nearer the origin can be seen */
585 || Player
.p_palantir
)
586 /* palantir enables one to see others */
587 && (Other
.p_status
!= S_CLOAKED
588 || (Player
.p_specialtype
== SC_VALAR
&& Player
.p_palantir
))
589 /* not cloaked; valar can see through cloak with a palantir */
590 && Other
.p_specialtype
!= SC_VALAR
)
592 /* coordinates should be printed */
593 printw("%-20s %8.0f %8.0f ",
594 Other
.p_name
, Other
.p_x
, Other
.p_y
);
596 /* cannot see player's coordinates */
597 printw("%-20s %19.19s ",
598 Other
.p_name
, descrlocation(&Other
, TRUE
));
600 printw("%6.0f %s %-9.9s%s\n", Other
.p_level
, descrtype(&Other
, TRUE
),
601 Other
.p_login
, descrstatus(&Other
));
603 if ((numusers
% (LINES
- 10)) == 0) {
610 printw("Total players on file = %d\n", numusers
);
617 FILE *fp
; /* to clear energy voids */
618 long loc
= 0L; /* location of old king in player file */
620 if (Player
.p_specialtype
< SC_KING
)
621 /* not already king -- assumes crown */
623 fseek(Playersfp
, 0L, SEEK_SET
);
624 while (fread((char *) &Other
, SZ_PLAYERSTRUCT
, 1, Playersfp
) == 1)
625 if (Other
.p_specialtype
== SC_KING
&& Other
.p_status
!= S_NOTUSED
)
628 if (Other
.p_status
!= S_OFF
)
629 /* old king is playing */
631 mvaddstr(4, 0, "The king is playing, so you cannot steal his throne\n");
632 altercoordinates(0.0, 0.0, A_NEAR
);
636 /* old king is not playing - remove
639 Other
.p_specialtype
= SC_NONE
;
642 writerecord(&Other
, loc
);
646 loc
+= SZ_PLAYERSTRUCT
;
648 /* make player new king */
650 Player
.p_specialtype
= SC_KING
;
651 mvaddstr(4, 0, "You have become king!\n");
653 /* let everyone else know */
654 fp
= fopen(_PATH_MESS
, "w");
655 fprintf(fp
, "All hail the new king!");
658 /* clear all energy voids; retain location of holy grail */
659 fseek(Energyvoidfp
, 0L, SEEK_SET
);
660 fread((char *) &Enrgyvoid
, SZ_VOIDSTRUCT
, 1, Energyvoidfp
);
661 fp
= fopen(_PATH_VOID
, "w");
662 fwrite((char *) &Enrgyvoid
, SZ_VOIDSTRUCT
, 1, fp
);
665 mvaddstr(6, 0, "0:Decree ");
671 short tamper
; /* value for tampering with other players */
672 const char *option
; /* pointer to option description */
673 double temp1
= 0.0, temp2
= 0.0; /* other tampering values */
675 long loc
; /* location in energy void file */
676 FILE *fp
; /* for opening gold file */
680 if (Player
.p_specialtype
< SC_COUNCIL
&& !Wizard
)
683 addstr("1:Transport 2:Curse 3:Energy Void 4:Bestow 5:Collect Taxes ");
685 ch
= getanswer(" ", TRUE
);
690 case '1': /* transport someone */
691 tamper
= T_TRANSPORT
;
692 option
= "transport";
695 case '2': /* curse another */
700 case '3': /* create energy void */
701 if ((loc
= allocvoid()) > 20L * (long)SZ_VOIDSTRUCT
)
702 /* can only have 20 void active at once */
703 mvaddstr(5, 0, "Sorry, void creation limit reached.\n");
705 addstr("Enter the X Y coordinates of void ? ");
706 getstring(Databuf
, SZ_DATABUF
);
707 sscanf(Databuf
, "%lf %lf", &temp1
, &temp2
);
708 Enrgyvoid
.ev_x
= floor(temp1
);
709 Enrgyvoid
.ev_y
= floor(temp2
);
710 Enrgyvoid
.ev_active
= TRUE
;
711 writevoid(&Enrgyvoid
, loc
);
712 mvaddstr(5, 0, "It is done.\n");
716 case '4': /* bestow gold to subject */
718 addstr("How much gold to bestow ? ");
720 if (temp1
> Player
.p_gold
|| temp1
< 0) {
721 mvaddstr(5, 0, "You don't have that !\n");
724 /* adjust gold after we are sure it will be given to
726 option
= "give gold to";
729 case '5': /* collect accumulated taxes */
730 if ((fp
= fopen(_PATH_GOLD
, "r+")) != NULL
)
733 fread((char *) &temp1
, sizeof(double), 1, fp
);
734 fseek(fp
, 0L, SEEK_SET
);
735 /* clear out value */
737 fwrite((char *) &temp2
, sizeof(double), 1, fp
);
740 mvprintw(4, 0, "You have collected %.0f in gold.\n", temp1
);
741 Player
.p_gold
+= floor(temp1
);
747 /* end of king options */
749 /* council of wise, valar, wizard options */
752 if (Player
.p_palantir
|| Wizard
)
753 addstr("2:Seek Grail ");
754 if (Player
.p_specialtype
== SC_VALAR
|| Wizard
)
755 addstr("3:Throw Monster 4:Relocate 5:Bless ");
757 addstr("6:Vaporize ");
759 ch
= getanswer(" ", TRUE
);
761 if (ch
> '2' && Player
.p_specialtype
!= SC_VALAR
) {
765 if (Player
.p_mana
< MM_INTERVENE
) {
766 mvaddstr(5, 0, "No mana left.\n");
769 Player
.p_mana
-= MM_INTERVENE
;
772 case '1': /* heal another */
777 case '2': /* seek grail */
778 if (Player
.p_palantir
)
779 /* need a palantir to seek */
781 fseek(Energyvoidfp
, 0L, SEEK_SET
);
782 fread((char *) &Enrgyvoid
, SZ_VOIDSTRUCT
, 1, Energyvoidfp
);
783 temp1
= distance(Player
.p_x
, Enrgyvoid
.ev_x
, Player
.p_y
, Enrgyvoid
.ev_y
);
784 temp1
+= ROLL(-temp1
/ 10.0, temp1
/ 5.0); /* add some error */
785 mvprintw(5, 0, "The palantir says the Grail is about %.0f away.\n", temp1
);
788 mvaddstr(5, 0, "You need a palantir to seek the Grail.\n");
791 case '3': /* lob monster at someone */
792 mvaddstr(4, 0, "Which monster [0-99] ? ");
794 temp1
= MAX(0.0, MIN(99.0, temp1
));
796 option
= "throw a monster at";
799 case '4': /* move another player */
800 mvaddstr(4, 0, "New X Y coordinates ? ");
801 getstring(Databuf
, SZ_DATABUF
);
802 sscanf(Databuf
, "%lf %lf", &temp1
, &temp2
);
807 case '5': /* bless a player */
812 case '6': /* kill off a player */
814 tamper
= T_VAPORIZED
;
824 /* adjust age after we are sure intervention will be done */
825 /* end of valar, etc. options */
829 /* prompt for player to affect */
831 mvprintw(4, 0, "Who do you want to %s ? ", option
);
832 getstring(Databuf
, SZ_DATABUF
);
833 truncstring(Databuf
);
835 if (Databuf
[0] == '\0')
841 if (strcmp(Player
.p_name
, Databuf
) != 0)
842 /* name other than self */
844 if ((loc
= findname(Databuf
, &Other
)) >= 0L) {
845 if (Other
.p_tampered
!= T_OFF
) {
846 mvaddstr(5, 0, "That person has something pending already.\n");
849 if (tamper
== T_RELOCATE
850 && CIRCLE(temp1
, temp2
) < CIRCLE(Other
.p_x
, Other
.p_y
)
852 mvaddstr(5, 0, "Cannot move someone closer to the Lord's Chamber.\n");
854 if (tamper
== T_BESTOW
)
855 Player
.p_gold
-= floor(temp1
);
856 if (!Wizard
&& (tamper
== T_HEAL
|| tamper
== T_MONSTER
||
857 tamper
== T_RELOCATE
|| tamper
== T_BLESSED
))
858 Player
.p_age
+= N_AGE
; /* age penalty */
859 Other
.p_tampered
= tamper
;
860 Other
.p_1scratch
= floor(temp1
);
861 Other
.p_2scratch
= floor(temp2
);
862 writerecord(&Other
, loc
);
863 mvaddstr(5, 0, "It is done.\n");
868 /* player not found */
869 mvaddstr(5, 0, "There is no one by that name.\n");
872 mvaddstr(5, 0, "You may not do it to yourself!\n");
876 writevoid(struct energyvoid
*vp
, long loc
)
879 fseek(Energyvoidfp
, loc
, SEEK_SET
);
880 fwrite((char *) vp
, SZ_VOIDSTRUCT
, 1, Energyvoidfp
);
881 fflush(Energyvoidfp
);
882 fseek(Energyvoidfp
, 0L, SEEK_SET
);
888 long loc
= 0L; /* location of new energy void */
890 fseek(Energyvoidfp
, 0L, SEEK_SET
);
891 while (fread((char *) &Enrgyvoid
, SZ_VOIDSTRUCT
, 1, Energyvoidfp
) == 1)
892 if (Enrgyvoid
.ev_active
)
893 loc
+= SZ_VOIDSTRUCT
;