/
score.c
314 lines (278 loc) · 8.92 KB
/
score.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#include "game/utils/score.h"
#include "game/utils/formatting.h"
#include "video/surface.h"
#include "utils/log.h"
#include <stdio.h>
#include <math.h>
#define TEXT_COLOR color_create(186,250,250,255)
#define SLIDER_DISTANCE 50
#define SLIDER_HANG_TIME 25
typedef struct score_text_t {
char *text;
float position; // Position of text between middle of screen and (x,y). 1.0 at middle, 0.0 at end
vec2i start;
int points;
int age;
} score_text;
int base_scores[] = {
800,
1200,
2800,
100000,
100000,
100000,
};
float multipliers[] = {
0.4,
0.8,
1.2,
1.6,
2.0,
3.0,
4.0
};
vec2i interpolate(vec2i start, vec2i end, float fraction) {
int nx = start.x+(end.x - start.x)*fraction;
int ny = start.y+(end.y - start.y)*fraction;
return vec2i_create(nx, ny);
}
void chr_score_create(chr_score *score, float multiplier) {
score->multiplier = multiplier;
score->x = 0;
score->y = 0;
score->direction = OBJECT_FACE_RIGHT;
list_create(&score->texts);
chr_score_reset(score, 1);
chr_score_reset_wins(score);
}
void chr_score_reset(chr_score *score, int wipe) {
iterator it;
score_text *t;
if (wipe) {
score->score = 0;
}
score->rounds = 0;
score->done = 0;
score->consecutive_hits = 0;
score->consecutive_hit_score = 0;
score->combo_hits = 0;
score->combo_hit_score = 0;
score->scrap = 0;
score->destruction = 0;
list_iter_begin(&score->texts, &it);
while((t = iter_next(&it)) != NULL) {
free(t->text);
list_delete(&score->texts, &it);
}
}
void chr_score_reset_wins(chr_score *score) {
score->wins = 0;
}
void chr_score_set_pos(chr_score *score, int x, int y, int direction) {
score->x = x;
score->y = y;
score->direction = direction;
}
unsigned int chr_score_get_num_texts(chr_score *score) {
return list_size(&score->texts);
}
int chr_score_onscreen(chr_score *score) {
return list_size(&score->texts) > 0;
}
void chr_score_free(chr_score *score) {
iterator it;
score_text *t;
list_iter_begin(&score->texts, &it);
while((t = iter_next(&it)) != NULL) {
free(t->text);
}
list_free(&score->texts);
}
void chr_score_tick(chr_score *score) {
iterator it;
score_text *t;
int lastage = -1;
list_iter_begin(&score->texts, &it);
while((t = iter_next(&it)) != NULL) {
// don't allow them to get too close together, if a bunch are added at once
if (lastage > 0 && (lastage - t->age) < SLIDER_DISTANCE) {
break;
}
if (t->age > SLIDER_HANG_TIME) {
t->position -= 0.01f;
}
lastage = t->age++;
if(t->position < 0.0f) {
score->score += t->points;
free(t->text);
list_delete(&score->texts, &it);
}
}
}
void chr_score_render(chr_score *score) {
// Render all texts in list to right spot
char tmp[50];
score_format(score->score, tmp);
if (score->direction == OBJECT_FACE_RIGHT) {
font_render_shadowed(&font_small, tmp, score->x, score->y, TEXT_COLOR, TEXT_SHADOW_RIGHT|TEXT_SHADOW_BOTTOM);
} else {
int s2len = strlen(tmp) * font_small.w;
font_render_shadowed(&font_small, tmp, score->x-s2len, score->y, TEXT_COLOR, TEXT_SHADOW_RIGHT|TEXT_SHADOW_BOTTOM);
}
iterator it;
score_text *t;
int lastage = -1;
vec2i pos;
list_iter_begin(&score->texts, &it);
while((t = iter_next(&it)) != NULL) {
if (lastage > 0 && (lastage - t->age) < SLIDER_DISTANCE) {
break;
}
pos = interpolate(vec2i_create(score->x, score->y), t->start, t->position);
if (score->direction == OBJECT_FACE_LEFT) {
pos = interpolate(vec2i_create(score->x-(strlen(t->text)*font_small.w), score->y), t->start, t->position);
}
font_render_shadowed(&font_small, t->text, pos.x, pos.y, TEXT_COLOR, TEXT_SHADOW_RIGHT|TEXT_SHADOW_BOTTOM);
lastage = t->age;
}
}
void chr_score_add(chr_score *score, char *text, int points, vec2i pos, float position) {
// Create texture
// Add texture to list, set position to 1.0f, set points
score_text s;
s.text = text;
s.points = points;
s.start = pos;
// center correctly initially, but end up justified
s.start.x -= ((strlen(s.text)*font_small.w)/2);
s.position = position;
s.age = 0;
list_append(&score->texts, &s, sizeof(score_text));
}
void chr_score_hit(chr_score *score, int points) {
score->score += points;
score->consecutive_hits++;
score->consecutive_hit_score += points;
score->combo_hits++;
score->combo_hit_score += points;
}
void chr_score_victory(chr_score *score, int health) {
// Add texts for scrap bonus, perfect round, whatever
score->wins++;
score->health = health;
char *text;
if (health == 100) {
text = malloc(64);
int len = sprintf(text, "perfect round ");
score_format(40000, text+len);
// XXX hardcode the y coordinate for now
chr_score_add(score, text, 40000, vec2i_create(160, 100), 1.0f);
}
text = malloc(64);
int len = sprintf(text, "vitality ");
score_format(trunc(40000 * (health / 100.0f)), text+len);
// XXX hardcode the y coordinate for now
chr_score_add(score, text, 40000 * (health / 100), vec2i_create(160, 100), 1.0f);
}
void chr_score_scrap(chr_score *score) {
score->scrap = 1;
}
void chr_score_destruction(chr_score *score) {
score->destruction = 1;
}
void chr_score_done(chr_score *score) {
if (!score->done) {
score->done = 1;
if (score->destruction) {
char *text = malloc(64);
int len = sprintf(text, "destruction bonus ");
score_format(40000, text+len);
// XXX hardcode the y coordinate for now
chr_score_add(score, text, 40000, vec2i_create(160, 100), 1.0f);
score->destruction = 0;
} else if (score->scrap) {
char *text = malloc(64);
int len = sprintf(text, "scrap bonus ");
score_format(20000, text+len);
// XXX hardcode the y coordinate for now
chr_score_add(score, text, 20000, vec2i_create(160, 100), 1.0f);
score->scrap = 0;
}
}
}
void chr_score_clear_done(chr_score *score) {
score->done = 0;
}
int chr_score_interrupt(chr_score *score, vec2i pos) {
// Enemy interrupted somehow, show consecutive hits or whatevera
int ret = 0;
if (score->consecutive_hits > 3) {
char *text = malloc(64);
ret = 1;
int len = sprintf(text, "%d consecutive hits ", score->consecutive_hits);
score_format(score->consecutive_hit_score, text+len);
// XXX hardcode the y coordinate for now
chr_score_add(score, text, score->consecutive_hit_score, vec2i_create(pos.x, 130), 1.0f);
}
score->consecutive_hits = 0;
score->consecutive_hit_score = 0;
return ret;
}
int chr_score_end_combo(chr_score *score, vec2i pos) {
// enemy recovered control, end any combos
int ret = 0;
if (score->combo_hits > 1) {
char *text = malloc(64);
ret = 1;
int len = sprintf(text, "%d hit combo ", score->combo_hits);
score_format(score->combo_hit_score*4, text+len);
// XXX hardcode the y coordinate for now
chr_score_add(score, text, score->combo_hit_score*4, vec2i_create(pos.x, 130), 1.0f);
}
score->combo_hits = 0;
score->combo_hit_score = 0;
return ret;
}
void chr_score_serialize(chr_score *score, serial *ser) {
serial_write_int32(ser, score->score);
serial_write_int32(ser, score->done);
serial_write_int32(ser, score->scrap);
serial_write_int32(ser, score->destruction);
serial_write_int8(ser, score->texts.size);
iterator it;
score_text *t;
list_iter_begin(&score->texts, &it);
while((t = iter_next(&it)) != NULL) {
serial_write_int8(ser, strlen(t->text)+1);
serial_write(ser, t->text, strlen(t->text)+1);
serial_write_float(ser, t->position);
serial_write_int16(ser, t->start.x);
serial_write_int16(ser, t->start.y);
serial_write_int32(ser, t->points);
}
}
void chr_score_unserialize(chr_score *score, serial *ser) {
score->score = serial_read_int32(ser);
score->done = serial_read_int32(ser);
score->scrap = serial_read_int32(ser);
score->destruction = serial_read_int32(ser);
uint8_t count = serial_read_int8(ser);
uint16_t text_len;
char *text;
float pos;
int x, y;
int points;
// clean it out
chr_score_free(score);
list_create(&score->texts);
for (int i = 0; i < count; i++) {
text_len = serial_read_int8(ser);
text = malloc(text_len);
serial_read(ser, text, text_len);
pos = serial_read_float(ser);
x = serial_read_int16(ser);
y = serial_read_int16(ser);
points = serial_read_int32(ser);
chr_score_add(score, text, points, vec2i_create(x, y), pos);
}
}