Reissue 1.18 - same code, corrected metadata.
[open-adventure.git] / score.c
1 /*
2  * Scoring and wrap-up.
3  *
4  * SPDX-FileCopyrightText: (C) 1977, 2005 by Will Crowther and Don Woods
5  * SPDX-License-Identifier: BSD-2-Clause
6  */
7 #include "advent.h"
8 #include "dungeon.h"
9 #include <stdlib.h>
10
11 static int mxscor; /* ugh..the price for having score() not exit. */
12
13 int score(enum termination mode) {
14         /* mode is 'scoregame' if scoring, 'quitgame' if quitting, 'endgame' if
15          * died or won */
16         int score = 0;
17
18         /*  The present scoring algorithm is as follows:
19          *     Objective:          Points:        Present total possible:
20          *  Getting well into cave   25                    25
21          *  Each treasure < chest    12                    60
22          *  Treasure chest itself    14                    14
23          *  Each treasure > chest    16                   224
24          *  Surviving             (MAX-NUM)*10             30
25          *  Not quitting              4                     4
26          *  Reaching "game.closng"   25                    25
27          *  "Closed": Quit/Killed    10
28          *            Klutzed        25
29          *            Wrong way      30
30          *            Success        45                    45
31          *  Came to Witt's End        1                     1
32          *  Round out the total       2                     2
33          *                                       TOTAL:   430
34          *  Points can also be deducted for using hints or too many turns, or
35          * for saving intermediate positions. */
36
37         /*  First tally up the treasures.  Must be in building and not broken.
38          *  Give the poor guy 2 points just for finding each treasure. */
39         mxscor = 0;
40         for (int i = 1; i <= NOBJECTS; i++) {
41                 if (!objects[i].is_treasure) {
42                         continue;
43                 }
44                 if (objects[i].inventory != 0) {
45                         int k = 12;
46                         if (i == CHEST) {
47                                 k = 14;
48                         }
49                         if (i > CHEST) {
50                                 k = 16;
51                         }
52                         if (!PROP_IS_STASHED(i) && !PROP_IS_NOTFOUND(i)) {
53                                 score += 2;
54                         }
55                         if (game.objects[i].place == LOC_BUILDING &&
56                             PROP_IS_FOUND(i)) {
57                                 score += k - 2;
58                         }
59                         mxscor += k;
60                 }
61         }
62
63         /*  Now look at how he finished and how far he got.  NDEATHS and
64          *  game.numdie tell us how well he survived.  game.dflag will tell us
65          *  if he ever got suitably deep into the cave.  game.closng still
66          *  indicates whether he reached the endgame.  And if he got as far as
67          *  "cave closed" (indicated by "game.closed"), then bonus is zero for
68          *  mundane exits or 133, 134, 135 if he blew it (so to speak). */
69         score += (NDEATHS - game.numdie) * 10;
70         mxscor += NDEATHS * 10;
71         if (mode == endgame) {
72                 score += 4;
73         }
74         mxscor += 4;
75         if (game.dflag != 0) {
76                 score += 25;
77         }
78         mxscor += 25;
79         if (game.closng) {
80                 score += 25;
81         }
82         mxscor += 25;
83         if (game.closed) {
84                 if (game.bonus == none) {
85                         score += 10;
86                 }
87                 if (game.bonus == splatter) {
88                         score += 25;
89                 }
90                 if (game.bonus == defeat) {
91                         score += 30;
92                 }
93                 if (game.bonus == victory) {
94                         score += 45;
95                 }
96         }
97         mxscor += 45;
98
99         /* Did he come to Witt's End as he should? */
100         if (game.objects[MAGAZINE].place == LOC_WITTSEND) {
101                 score += 1;
102         }
103         mxscor += 1;
104
105         /* Round it off. */
106         score += 2;
107         mxscor += 2;
108
109         /* Deduct for hints/turns/saves. Hints < 4 are special; see database
110          * desc. */
111         for (int i = 0; i < NHINTS; i++) {
112                 if (game.hints[i].used) {
113                         score = score - hints[i].penalty;
114                 }
115         }
116         if (game.novice) {
117                 score -= 5;
118         }
119         if (game.clshnt) {
120                 score -= 10;
121         }
122         score = score - game.trnluz - game.saved;
123
124         /* Return to score command if that's where we came from. */
125         if (mode == scoregame) {
126                 rspeak(GARNERED_POINTS, score, mxscor, game.turns, game.turns);
127         }
128
129         return score;
130 }
131
132 void terminate(enum termination mode) {
133         /* End of game.  Let's tell him all about it. */
134         int points = score(mode);
135 #if defined ADVENT_AUTOSAVE
136         autosave();
137 #endif
138
139         if (points + game.trnluz + 1 >= mxscor && game.trnluz != 0) {
140                 rspeak(TOOK_LONG);
141         }
142         if (points + game.saved + 1 >= mxscor && game.saved != 0) {
143                 rspeak(WITHOUT_SUSPENDS);
144         }
145         rspeak(TOTAL_SCORE, points, mxscor, game.turns, game.turns);
146         for (int i = 1; i <= (int)NCLASSES; i++) {
147                 if (classes[i].threshold >= points) {
148                         speak(classes[i].message);
149                         if (i < (int)NCLASSES) {
150                                 int nxt = classes[i].threshold + 1 - points;
151                                 rspeak(NEXT_HIGHER, nxt, nxt);
152                         } else {
153                                 rspeak(NO_HIGHER);
154                         }
155                         exit(EXIT_SUCCESS);
156                 }
157         }
158         rspeak(OFF_SCALE);
159         exit(EXIT_SUCCESS);
160 }
161
162 /* end */