Freeciv-3.1
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 "extras.h"
23#include "fc_types.h"
24#include "game.h" /* FIXME it's extra_type_iterate that needs this really */
25#include "tile.h"
26#include "world_object.h"
27
28#include "clientutils.h"
29
30/* This module contains functions that would belong to the client,
31 * except that in case of freeciv-web, server does handle these
32 * for the web client. */
33
34/* Stores the expected completion time for all activities on a tile.
35 * (If multiple activities can create/remove an extra, they will
36 * proceed in parallel and the first to complete will win, so they
37 * are accounted separately here.) */
38struct actcalc {
39 int extra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST];
40 int rmextra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST];
41 int activity_turns[ACTIVITY_LAST];
42};
43
44/************************************************************************/
50static void calc_activity(struct actcalc *calc, const struct tile *ptile,
51 const struct unit *pmodunit,
52 Activity_type_id new_act,
53 const struct extra_type *new_tgt)
54{
55 /* This temporary working state is a bit big to allocate on the stack */
56 struct {
57 int extra_total[MAX_EXTRA_TYPES][ACTIVITY_LAST];
58 int extra_units[MAX_EXTRA_TYPES][ACTIVITY_LAST];
59 int rmextra_total[MAX_EXTRA_TYPES][ACTIVITY_LAST];
60 int rmextra_units[MAX_EXTRA_TYPES][ACTIVITY_LAST];
61 int activity_total[ACTIVITY_LAST];
62 int activity_units[ACTIVITY_LAST];
63 } *t;
64
65 t = fc_calloc(1, sizeof(*t));
66
67 /* Contributions from real units */
70
71 if (punit == pmodunit) {
72 /* We'll account for this one later */
73 continue;
74 }
75
76 /* Client needs check for activity_target even when the
77 * activity is a build activity, and SHOULD have target.
78 * Server may still be sending more information about tile or
79 * unit activity changes, and client data is not yet consistent. */
80 if (is_build_activity(act)
81 && punit->activity_target != NULL) {
83
84 t->extra_total[eidx][act] += punit->activity_count;
85 t->extra_total[eidx][act] += get_activity_rate_this_turn(punit);
86 t->extra_units[eidx][act] += get_activity_rate(punit);
87 } else if (is_clean_activity(act)
88 && punit->activity_target != NULL) {
90
91 t->rmextra_total[eidx][act] += punit->activity_count;
92 t->rmextra_total[eidx][act] += get_activity_rate_this_turn(punit);
93 t->rmextra_units[eidx][act] += get_activity_rate(punit);
94 } else {
95 t->activity_total[act] += punit->activity_count;
96 t->activity_total[act] += get_activity_rate_this_turn(punit);
97 t->activity_units[act] += get_activity_rate(punit);
98 }
100
101 /* Hypothetical contribution from pmodunit, if it changed to specified
102 * activity/target */
103 if (pmodunit) {
104 if (is_build_activity(new_act)) {
105 int eidx = extra_index(new_tgt);
106
107 if (new_act == pmodunit->changed_from
108 && new_tgt == pmodunit->changed_from_target) {
109 t->extra_total[eidx][new_act] += pmodunit->changed_from_count;
110 }
111 t->extra_total[eidx][new_act] += get_activity_rate_this_turn(pmodunit);
112 t->extra_units[eidx][new_act] += get_activity_rate(pmodunit);
113 } else if (is_clean_activity(new_act)) {
114 int eidx = extra_index(new_tgt);
115
116 if (new_act == pmodunit->changed_from
117 && new_tgt == pmodunit->changed_from_target) {
118 t->rmextra_total[eidx][new_act] += pmodunit->changed_from_count;
119 }
120 t->rmextra_total[eidx][new_act] += get_activity_rate_this_turn(pmodunit);
121 t->rmextra_units[eidx][new_act] += get_activity_rate(pmodunit);
122 } else {
123 if (new_act == pmodunit->changed_from) {
124 t->activity_total[new_act] += pmodunit->changed_from_count;
125 }
126 t->activity_total[new_act] += get_activity_rate_this_turn(pmodunit);
127 t->activity_units[new_act] += get_activity_rate(pmodunit);
128 }
129 }
130
131 /* Turn activity counts into turn estimates */
133 int remains, turns;
134
135 if (is_build_activity(act)) {
137 int ei = extra_index(ep);
138 int units_total = t->extra_units[ei][act];
139
140 if (units_total > 0) {
141 remains
142 = tile_activity_time(act, ptile, ep)- t->extra_total[ei][act];
143 if (remains > 0) {
144 turns = 1 + (remains + units_total - 1) / units_total;
145 } else {
146 /* Extra will be finished this turn */
147 turns = 1;
148 }
149 } else {
150 turns = 0;
151 }
152
153 calc->extra_turns[ei][act] = turns;
155 } else if (is_clean_activity(act)) {
157 int ei = extra_index(ep);
158 int units_total = t->rmextra_units[ei][act];
159
160 if (units_total > 0) {
161 remains
162 = tile_activity_time(act, ptile, ep) - t->rmextra_total[ei][act];
163 if (remains > 0) {
164 turns = 1 + (remains + units_total - 1) / units_total;
165 } else {
166 /* Extra will be removed this turn */
167 turns = 1;
168 }
169 } else {
170 turns = 0;
171 }
172
173 calc->rmextra_turns[ei][act] = turns;
175 } else {
176 int units_total = t->activity_units[act];
177
178 if (units_total > 0) {
179 remains = tile_activity_time(act, ptile, NULL) - t->activity_total[act];
180 if (remains > 0) {
181 turns = 1 + (remains + units_total - 1) / units_total;
182 } else {
183 /* Activity will be finished this turn */
184 turns = 1;
185 }
186 } else {
187 turns = 0;
188 }
189
190 calc->activity_turns[act] = turns;
191 }
193
194 free(t);
195}
196
197/************************************************************************/
203int turns_to_activity_done(const struct tile *ptile,
205 const struct extra_type *tgt,
206 const struct unit *pmodunit)
207{
208 struct actcalc *calc = malloc(sizeof(struct actcalc));
209 int turns;
210
211 /* Calculate time for _all_ tile activities */
212 /* XXX: this is quite expensive */
213 calc_activity(calc, ptile, pmodunit, act, tgt);
214
215 /* ...and extract just the one we want. */
216 if (is_build_activity(act)) {
217 int tgti = extra_index(tgt);
218
219 turns = calc->extra_turns[tgti][act];
220 } else if (is_clean_activity(act)) {
221 int tgti = extra_index(tgt);
222
223 turns = calc->rmextra_turns[tgti][act];
224 } else {
225 turns = calc->activity_turns[act];
226 }
227
228 free(calc);
229
230 return turns;
231}
232
233/************************************************************************/
236const char *concat_tile_activity_text(struct tile *ptile)
237{
238 struct actcalc *calc = fc_malloc(sizeof(struct actcalc));
239 int num_activities = 0;
240 static struct astring str = ASTRING_INIT;
241
242 astr_clear(&str);
243
244 calc_activity(calc, ptile, NULL, ACTIVITY_LAST, NULL);
245
247 if (is_build_activity(i)) {
249 int ei = extra_index(ep);
250
251 if (calc->extra_turns[ei][i] > 0) {
252 if (num_activities > 0) {
253 astr_add(&str, "/");
254 }
255 astr_add(&str, "%s(%d)", extra_name_translation(ep),
256 calc->extra_turns[ei][i]);
257 num_activities++;
258 }
260 } else if (is_clean_activity(i)) {
261 enum extra_rmcause rmcause = ERM_NONE;
262
263 switch (i) {
264 case ACTIVITY_PILLAGE:
265 rmcause = ERM_PILLAGE;
266 break;
267 case ACTIVITY_POLLUTION:
268 rmcause = ERM_CLEANPOLLUTION;
269 break;
270 case ACTIVITY_FALLOUT:
271 rmcause = ERM_CLEANFALLOUT;
272 break;
273 default:
274 fc_assert(rmcause != ERM_NONE);
275 break;
276 };
277
278 if (rmcause != ERM_NONE) {
279 extra_type_by_rmcause_iterate(rmcause, ep) {
280 int ei = extra_index(ep);
281
282 if (calc->rmextra_turns[ei][i] > 0) {
283 if (num_activities > 0) {
284 astr_add(&str, "/");
285 }
286 astr_add(&str,
287 rmcause == ERM_PILLAGE ? _("Pillage %s(%d)")
288 : _("Clean %s(%d)"),
289 extra_name_translation(ep), calc->rmextra_turns[ei][i]);
290 num_activities++;
291 }
293 }
294 } else if (is_tile_activity(i)) {
295 if (calc->activity_turns[i] > 0) {
296 if (num_activities > 0) {
297 astr_add(&str, "/");
298 }
299 astr_add(&str, "%s(%d)",
300 get_activity_text(i), calc->activity_turns[i]);
301 num_activities++;
302 }
303 }
305
306 free(calc);
307
308 return astr_str(&str);
309}
void astr_clear(struct astring *astr)
Definition astring.c:205
void astr_add(struct astring *astr, const char *format,...)
Definition astring.c:287
#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)
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:50
const char * concat_tile_activity_text(struct tile *ptile)
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:73
const char * extra_name_translation(const struct extra_type *pextra)
Definition extras.c:186
#define extra_type_iterate(_p)
Definition extras.h:291
#define extra_type_iterate_end
Definition extras.h:297
#define extra_type_by_rmcause_iterate_end
Definition extras.h:334
#define extra_index(_e_)
Definition extras.h:177
#define extra_type_by_rmcause_iterate(_rmcause, _extra)
Definition extras.h:329
enum unit_activity Activity_type_id
Definition fc_types.h:349
#define MAX_EXTRA_TYPES
Definition fc_types.h:50
#define ERM_NONE
Definition fc_types.h:992
#define _(String)
Definition fcintl.h:67
#define fc_assert(condition)
Definition log.h:176
#define fc_calloc(n, esz)
Definition mem.h:38
#define fc_malloc(sz)
Definition mem.h:34
int rmextra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST]
Definition clientutils.c:40
int activity_turns[ACTIVITY_LAST]
Definition clientutils.c:41
int extra_turns[MAX_EXTRA_TYPES][ACTIVITY_LAST]
Definition clientutils.c:39
Definition tile.h:49
struct unit_list * units
Definition tile.h:57
Definition unit.h:138
enum unit_activity activity
Definition unit.h:157
struct extra_type * changed_from_target
Definition unit.h:170
struct extra_type * activity_target
Definition unit.h:164
int activity_count
Definition unit.h:162
enum unit_activity changed_from
Definition unit.h:168
int changed_from_count
Definition unit.h:169
int tile_activity_time(enum unit_activity activity, const struct tile *ptile, const struct extra_type *tgt)
Definition tile.c:412
bool is_tile_activity(enum unit_activity activity)
Definition unit.c:1606
int get_activity_rate_this_turn(const struct unit *punit)
Definition unit.c:505
int get_activity_rate(const struct unit *punit)
Definition unit.c:474
bool is_build_activity(enum unit_activity activity)
Definition unit.c:1560
const char * get_activity_text(enum unit_activity activity)
Definition unit.c:625
bool is_clean_activity(enum unit_activity activity)
Definition unit.c:1576
#define activity_type_iterate(_act_)
Definition unit.h:288
#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