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