Freeciv-3.3
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.) */
44
45/************************************************************************/
51static void calc_activity(struct actcalc *calc, const struct tile *ptile,
52 const struct unit *pmodunit,
54 const struct extra_type *new_tgt)
55{
56 /* This temporary working state is a bit big to allocate on the stack */
57 struct {
64 } *t;
65
66 t = fc_calloc(1, sizeof(*t));
67
68 /* Contributions from real units */
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) {
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) {
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 }
101
102 /* Hypothetical contribution from pmodunit, if it changed to specified
103 * activity/target */
104 if (pmodunit) {
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 }
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 */
134 int remains, turns;
135
136 if (is_build_activity(act)) {
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;
156 } else if (is_clean_activity(act)) {
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;
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 }
194
195 free(t);
196}
197
198/************************************************************************/
204int turns_to_activity_done(const struct tile *ptile,
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/************************************************************************/
237const 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
246
248 if (is_build_activity(i)) {
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 }
257 calc->extra_turns[ei][i]);
259 }
261 } else if (is_clean_activity(i)) {
263
264 switch (i) {
265 case ACTIVITY_PILLAGE:
267 break;
268 case ACTIVITY_CLEAN:
270 break;
271 default:
273 break;
274 };
275
276 if (rmcause != ERM_NONE) {
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]);
289 }
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]);
300 }
301 }
303
304 free(calc);
305
306 return astr_str(&str);
307}
308
309/************************************************************************/
312void 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
321 bool found = FALSE;
322
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. */
333 def_chance = MIN(def, def_chance);
334 }
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"),
341 }
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 =
353
354 if (veteran_name != NULL) {
355 astr_add(str, " (%s)", veteran_name);
356 }
357 }
358}
void astr_add_line(struct astring *astr, const char *format,...)
Definition astring.c:283
void astr_clear(struct astring *astr)
Definition astring.c:201
void astr_add(struct astring *astr, const char *format,...)
Definition astring.c:271
#define str
Definition astring.c:76
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
#define ASTRING_INIT
Definition astring.h:44
int turns_to_activity_done(const struct tile *ptile, Activity_type_id act, const struct extra_type *tgt, const struct unit *pmodunit)
void combat_odds_to_astr(struct astring *str, struct unit_list *punits, const struct tile *ptile, const struct unit *punit, const char *pct_str)
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
const char * concat_tile_activity_text(struct tile *ptile)
double unit_win_chance(const struct civ_map *nmap, const struct unit *attacker, const struct unit *defender, const struct action *paction)
Definition combat.c:480
char * incite_cost
Definition comments.c:76
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
const char * extra_name_translation(const struct extra_type *pextra)
Definition extras.c:194
#define extra_type_iterate(_p)
Definition extras.h:315
#define extra_type_iterate_end
Definition extras.h:321
#define extra_type_by_rmcause_iterate_end
Definition extras.h:358
#define extra_index(_e_)
Definition extras.h:183
#define extra_type_by_rmcause_iterate(_rmcause, _extra)
Definition extras.h:353
enum unit_activity Activity_type_id
Definition fc_types.h:238
#define MAX_EXTRA_TYPES
Definition fc_types.h:50
#define ERM_NONE
Definition fc_types.h:844
#define _(String)
Definition fcintl.h:67
struct world wld
Definition game.c:62
#define fc_assert(condition)
Definition log.h:177
#define fc_calloc(n, esz)
Definition mem.h:38
#define fc_malloc(sz)
Definition mem.h:34
#define MIN(x, y)
Definition shared.h:55
#define FC_INFINITY
Definition shared.h:36
int rmextra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST]
Definition clientutils.c:41
int activity_turns[ACTIVITY_LAST]
Definition clientutils.c:42
int extra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST]
Definition clientutils.c:40
Definition tile.h:50
struct unit_list * units
Definition tile.h:58
Definition unit.h:140
enum unit_activity activity
Definition unit.h:159
int hp
Definition unit.h:153
struct extra_type * activity_target
Definition unit.h:167
int activity_count
Definition unit.h:165
int veteran
Definition unit.h:154
struct civ_map map
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
int tile_activity_time(enum unit_activity activity, const struct tile *ptile, const struct extra_type *tgt)
Definition tile.c:418
bool is_tile_activity(enum unit_activity activity)
Definition unit.c:1641
int get_activity_rate_this_turn(const struct unit *punit)
Definition unit.c:550
int get_activity_rate(const struct unit *punit)
Definition unit.c:519
bool is_build_activity(enum unit_activity activity)
Definition unit.c:1596
const char * get_activity_text(enum unit_activity activity)
Definition unit.c:638
bool is_clean_activity(enum unit_activity activity)
Definition unit.c:1612
#define unit_owner(_pu)
Definition unit.h:403
#define activity_type_iterate(_act_)
Definition unit.h:287
#define activity_type_iterate_end
Definition unit.h:292
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33
const char * utype_veteran_name_translation(const struct unit_type *punittype, int level)
Definition unittype.c:2616
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123