Freeciv-3.4
Loading...
Searching...
No Matches
achievements.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18/* utility */
19#include "fcintl.h"
20#include "log.h"
21#include "rand.h"
22#include "shared.h"
23
24/* common */
25#include "citizens.h"
26#include "city.h"
27#include "culture.h"
28#include "game.h"
29#include "map.h"
30#include "player.h"
31#include "spaceship.h"
32
33#include "achievements.h"
34
36
37/************************************************************************/
41{
42 int i;
43
44 for (i = 0; i < ARRAY_SIZE(achievements); i++) {
45 achievements[i].id = i;
47 achievements[i].first = nullptr;
48 achievements[i].value = 0;
51 achievements[i].first_msg = nullptr;
52 achievements[i].cons_msg = nullptr;
53 }
54}
55
56/************************************************************************/
60{
61 int i;
62
63 for (i = 0; i < ARRAY_SIZE(achievements); i++) {
64 if (achievements[i].first_msg != nullptr) {
66 }
67 if (achievements[i].cons_msg != nullptr) {
69 }
70 }
71}
72
73/**********************************************************************/
77{
78 fc_assert_ret_val(pach != nullptr, -1);
79
80 return pach->id;
81}
82
83/**********************************************************************/
87{
88 fc_assert_ret_val(pach != nullptr, -1);
89
90 return pach - achievements;
91}
92
93/**********************************************************************/
97{
99 nullptr);
100
101 return &achievements[id];
102}
103
104/**********************************************************************/
108{
109 return name_translation_get(&pach->name);
110}
111
112/**********************************************************************/
116{
117 return rule_name_get(&pach->name);
118}
119
120/**********************************************************************/
125{
126 const char *qs = Qn_(name);
127
130 return pach;
131 }
133
134 return nullptr;
135}
136
137/**********************************************************************/
142 struct player_list *achievers)
143{
144 struct player *credited = nullptr;
145
146 players_iterate(pplayer) {
147 if (achievement_check(ach, pplayer)) {
148 if (!ach->unique) {
149 pplayer->history += ach->culture;
150 BV_SET(ach->achievers, player_index(pplayer));
151 }
152 player_list_append(achievers, pplayer);
153 }
155
156 if (ach->first != nullptr) {
157 /* Already have first one credited. */
158 return nullptr;
159 }
160
161 if (player_list_size(achievers) > 0) {
162 /* If multiple players achieved at the same turn, randomly select one
163 * as the one who won the race. */
164 credited = player_list_get(achievers, fc_rand(player_list_size(achievers)));
165
166 ach->first = credited;
167
168 if (ach->unique) {
169 /* For !ach->unique achievements culture was already added above. */
170 credited->history += ach->culture;
171 }
172
173 /* Mark the selected player as the only one having the achievement */
175 }
176
177 return credited;
178}
179
180/**********************************************************************/
183bool achievement_check(struct achievement *ach, struct player *pplayer)
184{
185 if ((ach->unique && ach->first != nullptr)
186 || (BV_ISSET(ach->achievers, player_index(pplayer)))) {
187 /* It was already achieved */
188 return FALSE;
189 }
190
191 switch (ach->type) {
193 return pplayer->spaceship.state == SSHIP_LAUNCHED;
194 case ACHIEVEMENT_MAP:
195 {
196 int max_unknown;
197 int required;
198 int total;
199 int known = 0;
200 int unknown = 0;
201
202 /* We calculate max_unknown first for getting the
203 * rounding correctly.
204 * Consider 50 tile map from which we want 25% known.
205 * 50 * 25% = 12.5. Would we round that number of tiles
206 * down, we would get < 25% that's minimum requirement.
207 * Instead we round down (50 - 12.5 = 37.5) -> 37 and then
208 * get the minimum number of full tiles as 50 - 37 = 13. */
209 total = map_num_tiles();
210 max_unknown = (total * (100 - ach->value)) / 100;
211 required = total - max_unknown;
212
213 whole_map_iterate(&(wld.map), ptile) {
214 bool this_is_known = FALSE;
215
216 if (is_server()) {
217 if (dbv_isset(&pplayer->tile_known, tile_index(ptile))) {
219 }
220 } else {
221 /* Client */
222 if (ptile->terrain != T_UNKNOWN) {
224 }
225 }
226
227 if (this_is_known) {
228 known++;
229 if (known >= required) {
230 return TRUE;
231 }
232 } else {
233 unknown++;
234 if (unknown >= max_unknown) {
235 return FALSE;
236 }
237 }
239 }
240
241 return FALSE;
243 {
245 int count = 0;
246
248
249 city_list_iterate(pplayer->cities, pcity) {
250 citizens_iterate(pcity, pslot, pnat) {
251 int idx = player_index(player_slot_get_player(pslot));
252
253 if (!BV_ISSET(seen_citizens, idx)) {
254 BV_SET(seen_citizens, idx);
255 count++;
256 if (count >= ach->value) {
257 /* There's at least value different nationalities. */
258 return TRUE;
259 }
260 }
263 }
264
265 return FALSE;
267 city_list_iterate(pplayer->cities, pcity) {
268 if (city_culture(pcity) >= ach->value) {
269 return TRUE;
270 }
272
273 return FALSE;
275 if (player_culture(pplayer) >= ach->value) {
276 return TRUE;
277 }
278
279 return FALSE;
281 return ((int)fc_rand(10000) < ach->value);
282 case ACHIEVEMENT_HUTS:
283 return pplayer->server.huts >= ach->value;
285 city_list_iterate(pplayer->cities, pcity) {
286 if (city_size_get(pcity) >= ach->value) {
287 return TRUE;
288 }
290
291 return FALSE;
293 return get_literacy(pplayer) >= ach->value;
295 {
296 bool *seen = fc_calloc(wld.map.num_continents, sizeof(bool));
297 int count = 0;
298
299 whole_map_iterate(&(wld.map), ptile) {
300 bool this_is_known = FALSE;
301
302 if (is_server()) {
303 if (dbv_isset(&pplayer->tile_known, tile_index(ptile))) {
305 }
306 } else {
307 /* Client */
308 if (ptile->terrain != T_UNKNOWN) {
310 }
311 }
312
313 if (this_is_known) {
314 /* FIXME: This makes the assumption that fogged tiles belonged
315 * to their current continent when they were last seen. */
316 if (ptile->continent > 0 && !seen[ptile->continent - 1]) {
317 if (++count >= ach->value) {
318 free(seen);
319 return TRUE;
320 }
321 seen[ptile->continent - 1] = TRUE;
322 }
323 }
325
326 free(seen);
327 return FALSE;
328 }
330 return pplayer->score.units_killed >= ach->value;
331 case ACHIEVEMENT_RICH:
332 return pplayer->economic.gold >= ach->value;
334 break;
335 }
336
337 log_error("achievement_check(): Illegal achievement type %d", ach->type);
338
339 return FALSE;
340}
341
342/**********************************************************************/
346{
347 fc_assert(pach->first_msg != nullptr);
348
349 return _(pach->first_msg);
350}
351
352/**********************************************************************/
356{
357 fc_assert(pach->cons_msg != nullptr);
358
359 return _(pach->cons_msg);
360}
361
362/**********************************************************************/
366 const struct player *pplayer)
367{
368 if (pplayer == nullptr) {
369 return FALSE;
370 }
371
372 return BV_ISSET(pach->achievers, player_index(pplayer));
373}
374
375/**********************************************************************/
379{
380 return pach->first != nullptr;
381}
382
383/**********************************************************************/
387int get_literacy(const struct player *pplayer)
388{
389 int pop = pplayer->score.population;
390
391 if (pop <= 0) {
392 return 0;
393 } else if (pop >= 10000) {
394 return pplayer->score.literacy / (pop / 100);
395 } else {
396 return (pplayer->score.literacy * 100) / pop;
397 }
398}
bool achievement_check(struct achievement *ach, struct player *pplayer)
void achievements_free(void)
bool achievement_player_has(const struct achievement *pach, const struct player *pplayer)
static struct achievement achievements[MAX_ACHIEVEMENT_TYPES]
int achievement_index(const struct achievement *pach)
struct player * achievement_plr(struct achievement *ach, struct player_list *achievers)
struct achievement * achievement_by_number(int id)
int get_literacy(const struct player *pplayer)
const char * achievement_later_msg(struct achievement *pach)
int achievement_number(const struct achievement *pach)
const char * achievement_first_msg(struct achievement *pach)
const char * achievement_rule_name(struct achievement *pach)
struct achievement * achievement_by_rule_name(const char *name)
const char * achievement_name_translation(struct achievement *pach)
void achievements_init(void)
bool achievement_claimed(const struct achievement *pach)
#define achievements_iterate_end
#define achievements_iterate(_ach_)
bool dbv_isset(const struct dbv *pdbv, int bit)
Definition bitvector.c:120
#define BV_CLR_ALL(bv)
Definition bitvector.h:103
#define BV_SET(bv, bit)
Definition bitvector.h:89
#define BV_ISSET(bv, bit)
Definition bitvector.h:86
#define citizens_iterate_end
Definition citizens.h:54
#define citizens_iterate(_pcity, _pslot, _nationality)
Definition citizens.h:48
#define city_list_iterate(citylist, pcity)
Definition city.h:508
static citizens city_size_get(const struct city *pcity)
Definition city.h:570
#define city_list_iterate_end
Definition city.h:510
char * incite_cost
Definition comments.c:77
int city_culture(const struct city *pcity)
Definition culture.c:29
int player_culture(const struct player *plr)
Definition culture.c:49
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int const struct action *paction struct unit struct city * pcity
Definition dialogs_g.h:78
int int id
Definition editgui_g.h:28
static bool is_server(void)
#define MAX_ACHIEVEMENT_TYPES
Definition fc_types.h:53
#define _(String)
Definition fcintl.h:67
#define Qn_(String)
Definition fcintl.h:89
struct civ_game game
Definition game.c:62
struct world wld
Definition game.c:63
const char * name
Definition inputfile.c:127
#define fc_assert(condition)
Definition log.h:177
#define fc_assert_ret_val(condition, val)
Definition log.h:195
#define log_error(message,...)
Definition log.h:104
int map_num_tiles(void)
Definition map.c:1161
#define whole_map_iterate(_map, _tile)
Definition map.h:582
#define whole_map_iterate_end
Definition map.h:591
#define fc_calloc(n, esz)
Definition mem.h:38
#define FC_FREE(ptr)
Definition mem.h:41
static const char * rule_name_get(const struct name_translation *ptrans)
static const char * name_translation_get(const struct name_translation *ptrans)
int player_index(const struct player *pplayer)
Definition player.c:818
struct player * player_slot_get_player(const struct player_slot *pslot)
Definition player.c:432
#define players_iterate_end
Definition player.h:552
#define players_iterate(_pplayer)
Definition player.h:547
#define fc_rand(_size)
Definition rand.h:56
#define ARRAY_SIZE(x)
Definition shared.h:85
@ SSHIP_LAUNCHED
Definition spaceship.h:85
char * first_msg
enum achievement_type type
struct player * first
bv_player achievers
char * cons_msg
bool ruledit_disabled
struct packet_ruleset_control control
Definition game.h:83
Continent_id num_continents
Definition map_types.h:83
int units_killed
Definition player.h:105
int population
Definition player.h:96
int literacy
Definition player.h:100
enum spaceship_state state
Definition spaceship.h:108
struct city_list * cities
Definition player.h:281
struct dbv tile_known
Definition player.h:310
int huts
Definition player.h:349
struct player::@73::@75 server
struct player_economic economic
Definition player.h:284
struct player_spaceship spaceship
Definition player.h:286
struct player_score score
Definition player.h:283
int history
Definition player.h:316
struct civ_map map
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define T_UNKNOWN
Definition terrain.h:62
#define tile_index(_pt_)
Definition tile.h:89