Freeciv-3.2: /fast/freeciv/nightly/S3_2/common/clientutils.c Source File

Freeciv-3.2

Loading...
Searching...
No Matches
clientutils.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 "astring.h"
20
21/* common */
22#include "combat.h"
23#include "extras.h"
24#include "fc_types.h"
25#include "game.h" /* FIXME it's extra_type_iterate that needs this really */
26#include "tile.h"
27#include "world_object.h"
28
29#include "clientutils.h"
30
31/* This module contains functions that would belong to the client,
32 * except that in case of freeciv-web, server does handle these
33 * for the web client. */
34
35/* Stores the expected completion time for all activities on a tile.
36 * (If multiple activities can create/remove an extra, they will
37 * proceed in parallel and the first to complete will win, so they
38 * are accounted separately here.) */
39 struct actcalc {
40 int extra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST];
41 int rmextra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST];
42 int activity_turns[ACTIVITY_LAST];
43};
44
45/************************************************************************/
51 static void calc_activity(struct actcalc *calc, const struct tile *ptile,
52 const struct unit *pmodunit,
53 Activity_type_id new_act,
54 const struct extra_type *new_tgt)
55{
56 /* This temporary working state is a bit big to allocate on the stack */
57 struct {
58 int extra_total[MAX_EXTRA_TYPES][ACTIVITY_LAST];
59 int extra_units[MAX_EXTRA_TYPES][ACTIVITY_LAST];
60 int rmextra_total[MAX_EXTRA_TYPES][ACTIVITY_LAST];
61 int rmextra_units[MAX_EXTRA_TYPES][ACTIVITY_LAST];
62 int activity_total[ACTIVITY_LAST];
63 int activity_units[ACTIVITY_LAST];
64 } *t;
65
66 t = fc_calloc(1, sizeof(*t));
67
68 /* Contributions from real units */
69 unit_list_iterate(ptile->units, punit) {
70 Activity_type_id act = punit->activity;
71
72 if (punit == pmodunit) {
73 /* We'll account for this one later */
74 continue;
75 }
76
77 /* Client needs check for activity_target even when the
78 * activity is a build activity, and SHOULD have target.
79 * Server may still be sending more information about tile or
80 * unit activity changes, and client data is not yet consistent. */
81 if (is_build_activity(act)
82 && punit->activity_target != NULL) {
83 int eidx = extra_index(punit->activity_target);
84
85 t->extra_total[eidx][act] += punit->activity_count;
86 t->extra_total[eidx][act] += get_activity_rate_this_turn(punit);
87 t->extra_units[eidx][act] += get_activity_rate(punit);
88 } else if (is_clean_activity(act)
89 && punit->activity_target != NULL) {
90 int eidx = extra_index(punit->activity_target);
91
92 t->rmextra_total[eidx][act] += punit->activity_count;
93 t->rmextra_total[eidx][act] += get_activity_rate_this_turn(punit);
94 t->rmextra_units[eidx][act] += get_activity_rate(punit);
95 } else {
96 t->activity_total[act] += punit->activity_count;
97 t->activity_total[act] += get_activity_rate_this_turn(punit);
98 t->activity_units[act] += get_activity_rate(punit);
99 }
100 } unit_list_iterate_end;
101
102 /* Hypothetical contribution from pmodunit, if it changed to specified
103 * activity/target */
104 if (pmodunit) {
105 if (is_build_activity(new_act)) {
106 int eidx = extra_index(new_tgt);
107
108 if (new_act == pmodunit->changed_from
109 && new_tgt == pmodunit->changed_from_target) {
110 t->extra_total[eidx][new_act] += pmodunit->changed_from_count;
111 }
112 t->extra_total[eidx][new_act] += get_activity_rate_this_turn(pmodunit);
113 t->extra_units[eidx][new_act] += get_activity_rate(pmodunit);
114 } else if (is_clean_activity(new_act)) {
115 int eidx = extra_index(new_tgt);
116
117 if (new_act == pmodunit->changed_from
118 && new_tgt == pmodunit->changed_from_target) {
119 t->rmextra_total[eidx][new_act] += pmodunit->changed_from_count;
120 }
121 t->rmextra_total[eidx][new_act] += get_activity_rate_this_turn(pmodunit);
122 t->rmextra_units[eidx][new_act] += get_activity_rate(pmodunit);
123 } else {
124 if (new_act == pmodunit->changed_from) {
125 t->activity_total[new_act] += pmodunit->changed_from_count;
126 }
127 t->activity_total[new_act] += get_activity_rate_this_turn(pmodunit);
128 t->activity_units[new_act] += get_activity_rate(pmodunit);
129 }
130 }
131
132 /* Turn activity counts into turn estimates */
133 activity_type_iterate(act) {
134 int remains, turns;
135
136 if (is_build_activity(act)) {
137 extra_type_iterate(ep) {
138 int ei = extra_index(ep);
139 int units_total = t->extra_units[ei][act];
140
141 if (units_total > 0) {
142 remains
143 = tile_activity_time(act, ptile, ep)- t->extra_total[ei][act];
144 if (remains > 0) {
145 turns = 1 + (remains + units_total - 1) / units_total;
146 } else {
147 /* Extra will be finished this turn */
148 turns = 1;
149 }
150 } else {
151 turns = 0;
152 }
153
154 calc->extra_turns[ei][act] = turns;
155 } extra_type_iterate_end;
156 } else if (is_clean_activity(act)) {
157 extra_type_iterate(ep) {
158 int ei = extra_index(ep);
159 int units_total = t->rmextra_units[ei][act];
160
161 if (units_total > 0) {
162 remains
163 = tile_activity_time(act, ptile, ep) - t->rmextra_total[ei][act];
164 if (remains > 0) {
165 turns = 1 + (remains + units_total - 1) / units_total;
166 } else {
167 /* Extra will be removed this turn */
168 turns = 1;
169 }
170 } else {
171 turns = 0;
172 }
173
174 calc->rmextra_turns[ei][act] = turns;
175 } extra_type_iterate_end;
176 } else {
177 int units_total = t->activity_units[act];
178
179 if (units_total > 0) {
180 remains = tile_activity_time(act, ptile, NULL) - t->activity_total[act];
181 if (remains > 0) {
182 turns = 1 + (remains + units_total - 1) / units_total;
183 } else {
184 /* Activity will be finished this turn */
185 turns = 1;
186 }
187 } else {
188 turns = 0;
189 }
190
191 calc->activity_turns[act] = turns;
192 }
193 } activity_type_iterate_end;
194
195 free(t);
196}
197
198/************************************************************************/
204 int turns_to_activity_done(const struct tile *ptile,
205 Activity_type_id act,
206 const struct extra_type *tgt,
207 const struct unit *pmodunit)
208{
209 struct actcalc *calc = malloc(sizeof(struct actcalc));
210 int turns;
211
212 /* Calculate time for _all_ tile activities */
213 /* XXX: this is quite expensive */
214 calc_activity(calc, ptile, pmodunit, act, tgt);
215
216 /* ...and extract just the one we want. */
217 if (is_build_activity(act)) {
218 int tgti = extra_index(tgt);
219
220 turns = calc->extra_turns[tgti][act];
221 } else if (is_clean_activity(act)) {
222 int tgti = extra_index(tgt);
223
224 turns = calc->rmextra_turns[tgti][act];
225 } else {
226 turns = calc->activity_turns[act];
227 }
228
229 free(calc);
230
231 return turns;
232}
233
234/************************************************************************/
237 const char *concat_tile_activity_text(struct tile *ptile)
238{
239 struct actcalc *calc = fc_malloc(sizeof(struct actcalc));
240 int num_activities = 0;
241 static struct astring str = ASTRING_INIT;
242
243 astr_clear(&str);
244
245 calc_activity(calc, ptile, NULL, ACTIVITY_LAST, NULL);
246
247 activity_type_iterate(i) {
248 if (is_build_activity(i)) {
249 extra_type_iterate(ep) {
250 int ei = extra_index(ep);
251
252 if (calc->extra_turns[ei][i] > 0) {
253 if (num_activities > 0) {
254 astr_add(&str, "/");
255 }
256 astr_add(&str, "%s(%d)", extra_name_translation(ep),
257 calc->extra_turns[ei][i]);
258 num_activities++;
259 }
260 } extra_type_iterate_end;
261 } else if (is_clean_activity(i)) {
262 enum extra_rmcause rmcause = ERM_NONE;
263
264 switch (i) {
265 case ACTIVITY_PILLAGE:
266 rmcause = ERM_PILLAGE;
267 break;
268 case ACTIVITY_CLEAN:
269 rmcause = ERM_CLEAN;
270 break;
271 default:
272 fc_assert(rmcause != ERM_NONE);
273 break;
274 };
275
276 if (rmcause != ERM_NONE) {
277 extra_type_by_rmcause_iterate(rmcause, ep) {
278 int ei = extra_index(ep);
279
280 if (calc->rmextra_turns[ei][i] > 0) {
281 if (num_activities > 0) {
282 astr_add(&str, "/");
283 }
284 astr_add(&str,
285 rmcause == ERM_PILLAGE ? _("Pillage %s(%d)")
286 : _("Clean %s(%d)"),
287 extra_name_translation(ep), calc->rmextra_turns[ei][i]);
288 num_activities++;
289 }
290 } extra_type_by_rmcause_iterate_end;
291 }
292 } else if (is_tile_activity(i)) {
293 if (calc->activity_turns[i] > 0) {
294 if (num_activities > 0) {
295 astr_add(&str, "/");
296 }
297 astr_add(&str, "%s(%d)",
298 get_activity_text(i), calc->activity_turns[i]);
299 num_activities++;
300 }
301 }
302 } activity_type_iterate_end;
303
304 free(calc);
305
306 return astr_str(&str);
307}
308
309/************************************************************************/
312 void combat_odds_to_astr(struct astring *str, struct unit_list *punits,
313 const struct tile *ptile, const struct unit *punit,
314 const char *pct_str)
315{
316 const struct unit_type *ptype = unit_type_get(punit);
317 struct civ_map *nmap = &(wld.map);
318
319 unit_list_iterate(punits, pfocus) {
320 int att_chance = FC_INFINITY, def_chance = FC_INFINITY;
321 bool found = FALSE;
322
323 unit_list_iterate(ptile->units, tile_unit) {
324 if (unit_owner(tile_unit) != unit_owner(pfocus)) {
325 int att = unit_win_chance(nmap, pfocus, tile_unit, NULL) * 100;
326 int def = (1.0 - unit_win_chance(nmap, tile_unit, pfocus,
327 NULL)) * 100;
328
329 found = TRUE;
330
331 /* Presumably the best attacker and defender will be used. */
332 att_chance = MIN(att, att_chance);
333 def_chance = MIN(def, def_chance);
334 }
335 } unit_list_iterate_end;
336
337 if (found) {
338 /* TRANS: "Chance to win: A:95% D:46%" - "%s" are just the percent signs. */
339 astr_add_line(str, _("Chance to win: A:%d%s D:%d%s"),
340 att_chance, pct_str, def_chance, pct_str);
341 }
342 } unit_list_iterate_end;
343
344 /* TRANS: A is attack power, D is defense power, FP is firepower,
345 * HP is hitpoints (current and max). */
346 astr_add_line(str, _("A:%d D:%d FP:%d HP:%d/%d"),
347 ptype->attack_strength, ptype->defense_strength,
348 ptype->firepower, punit->hp, ptype->hp);
349
350 {
351 const char *veteran_name =
352 utype_veteran_name_translation(ptype, punit->veteran);
353
354 if (veteran_name != NULL) {
355 astr_add(str, " (%s)", veteran_name);
356 }
357 }
358}
astr_add_line
void astr_add_line(struct astring *astr, const char *format,...)
Definition astring.c:299
astr_clear
void astr_clear(struct astring *astr)
Definition astring.c:205
astr_add
void astr_add(struct astring *astr, const char *format,...)
Definition astring.c:287
str
#define str
Definition astring.c:76
astring.h
astr_str
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
ASTRING_INIT
#define ASTRING_INIT
Definition astring.h:44
turns_to_activity_done
int turns_to_activity_done(const struct tile *ptile, Activity_type_id act, const struct extra_type *tgt, const struct unit *pmodunit)
Definition clientutils.c:204
combat_odds_to_astr
void combat_odds_to_astr(struct astring *str, struct unit_list *punits, const struct tile *ptile, const struct unit *punit, const char *pct_str)
Definition clientutils.c:312
calc_activity
static void calc_activity(struct actcalc *calc, const struct tile *ptile, const struct unit *pmodunit, Activity_type_id new_act, const struct extra_type *new_tgt)
Definition clientutils.c:51
concat_tile_activity_text
const char * concat_tile_activity_text(struct tile *ptile)
Definition clientutils.c:237
clientutils.h
unit_win_chance
double unit_win_chance(const struct civ_map *nmap, const struct unit *attacker, const struct unit *defender, const struct action *paction)
Definition combat.c:478
combat.h
incite_cost
char * incite_cost
Definition comments.c:74
punit
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 * punit
Definition dialogs_g.h:74
extra_name_translation
const char * extra_name_translation(const struct extra_type *pextra)
Definition extras.c:194
extras.h
extra_type_iterate
#define extra_type_iterate(_p)
Definition extras.h:315
extra_type_iterate_end
#define extra_type_iterate_end
Definition extras.h:321
extra_type_by_rmcause_iterate_end
#define extra_type_by_rmcause_iterate_end
Definition extras.h:358
extra_index
#define extra_index(_e_)
Definition extras.h:183
extra_type_by_rmcause_iterate
#define extra_type_by_rmcause_iterate(_rmcause, _extra)
Definition extras.h:353
fc_types.h
Activity_type_id
enum unit_activity Activity_type_id
Definition fc_types.h:382
MAX_EXTRA_TYPES
#define MAX_EXTRA_TYPES
Definition fc_types.h:50
ERM_NONE
#define ERM_NONE
Definition fc_types.h:1137
_
#define _(String)
Definition fcintl.h:67
wld
struct world wld
Definition game.c:63
game.h
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_calloc
#define fc_calloc(n, esz)
Definition mem.h:38
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
MIN
#define MIN(x, y)
Definition shared.h:55
FC_INFINITY
#define FC_INFINITY
Definition shared.h:36
actcalc
Definition clientutils.c:39
actcalc::rmextra_turns
int rmextra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST]
Definition clientutils.c:41
actcalc::activity_turns
int activity_turns[ACTIVITY_LAST]
Definition clientutils.c:42
actcalc::extra_turns
int extra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST]
Definition clientutils.c:40
astring
Definition astring.h:36
civ_map
Definition map_types.h:71
extra_type
Definition extras.h:88
tile
Definition tile.h:50
tile::units
struct unit_list * units
Definition tile.h:58
unit_type
Definition unittype.h:500
unit
Definition unit.h:138
unit::activity
enum unit_activity activity
Definition unit.h:157
unit::hp
int hp
Definition unit.h:151
unit::activity_target
struct extra_type * activity_target
Definition unit.h:164
unit::activity_count
int activity_count
Definition unit.h:162
unit::veteran
int veteran
Definition unit.h:152
world::map
struct civ_map map
Definition world_object.h:38
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
tile_activity_time
int tile_activity_time(enum unit_activity activity, const struct tile *ptile, const struct extra_type *tgt)
Definition tile.c:418
tile.h
is_tile_activity
bool is_tile_activity(enum unit_activity activity)
Definition unit.c:1600
get_activity_rate_this_turn
int get_activity_rate_this_turn(const struct unit *punit)
Definition unit.c:522
get_activity_rate
int get_activity_rate(const struct unit *punit)
Definition unit.c:494
is_build_activity
bool is_build_activity(enum unit_activity activity)
Definition unit.c:1555
get_activity_text
const char * get_activity_text(enum unit_activity activity)
Definition unit.c:610
is_clean_activity
bool is_clean_activity(enum unit_activity activity)
Definition unit.c:1571
unit_owner
#define unit_owner(_pu)
Definition unit.h:389
activity_type_iterate
#define activity_type_iterate(_act_)
Definition unit.h:284
activity_type_iterate_end
#define activity_type_iterate_end
Definition unit.h:289
unit_list_iterate
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
unit_list_iterate_end
#define unit_list_iterate_end
Definition unitlist.h:33
utype_veteran_name_translation
const char * utype_veteran_name_translation(const struct unit_type *punittype, int level)
Definition unittype.c:2598
unit_type_get
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
world_object.h