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