webperimental: killstack decides stack protects.
[freeciv.git] / server / cityhand.c
blobb6464f992be460ecb6d1cae7d958ec4926dedc50
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
22 /* utility */
23 #include "fcintl.h"
24 #include "log.h"
25 #include "rand.h"
26 #include "support.h"
28 /* common */
29 #include "city.h"
30 #include "events.h"
31 #include "game.h"
32 #include "idex.h"
33 #include "map.h"
34 #include "player.h"
35 #include "specialist.h"
36 #include "unit.h"
37 #include "worklist.h"
39 /* server */
40 #include "citytools.h"
41 #include "cityturn.h"
42 #include "notify.h"
43 #include "plrhand.h"
44 #include "sanitycheck.h"
45 #include "unithand.h"
47 #include "cityhand.h"
49 /**************************************************************************
50 Send city_name_suggestion packet back to requesting conn, with
51 suggested name and with same id which was passed in (either unit id
52 for city builder or existing city id for rename, we don't care here).
53 **************************************************************************/
54 void handle_city_name_suggestion_req(struct player *pplayer, int unit_id)
56 struct unit *punit = player_unit_by_number(pplayer, unit_id);
57 enum city_build_result res;
59 if (NULL == punit) {
60 /* Probably died or bribed. */
61 log_verbose("handle_city_name_suggestion_req() invalid unit %d",
62 unit_id);
63 return;
66 if (action_prob_possible(action_prob_vs_tile(punit, ACTION_FOUND_CITY,
67 unit_tile(punit)))) {
68 log_verbose("handle_city_name_suggest_req(unit_pos (%d, %d))",
69 TILE_XY(unit_tile(punit)));
70 dlsend_packet_city_name_suggestion_info(pplayer->connections, unit_id,
71 city_name_suggestion(pplayer, unit_tile(punit)));
73 /* The rest of this function is error handling. */
74 return;
77 res = city_build_here_test(unit_tile(punit), punit);
79 switch (res) {
80 case CB_OK:
81 /* No action enabler permitted the city to be built. */
82 case CB_BAD_CITY_TERRAIN:
83 case CB_BAD_UNIT_TERRAIN:
84 case CB_BAD_BORDERS:
85 case CB_NO_MIN_DIST:
86 log_verbose("handle_city_name_suggest_req(unit_pos (%d, %d)): "
87 "cannot build there.", TILE_XY(unit_tile(punit)));
89 illegal_action_msg(pplayer, E_BAD_COMMAND, punit, ACTION_FOUND_CITY,
90 unit_tile(punit), NULL, NULL);
91 break;
95 /**************************************************************************
96 Handle request to change specialist type
97 **************************************************************************/
98 void handle_city_change_specialist(struct player *pplayer, int city_id,
99 Specialist_type_id from,
100 Specialist_type_id to)
102 struct city *pcity = player_city_by_number(pplayer, city_id);
104 if (!pcity) {
105 return;
108 if (to < 0 || to >= specialist_count()
109 || from < 0 || from >= specialist_count()
110 || !city_can_use_specialist(pcity, to)
111 || pcity->specialists[from] == 0) {
112 /* This could easily just be due to clicking faster on the specialist
113 * than the server can cope with. */
114 log_verbose("Error in specialist change request from client.");
115 return;
118 pcity->specialists[from]--;
119 pcity->specialists[to]++;
121 city_refresh(pcity);
122 sanity_check_city(pcity);
123 send_city_info(pplayer, pcity);
126 /**************************************************************************
127 Handle request to change city worker in to specialist.
128 **************************************************************************/
129 void handle_city_make_specialist(struct player *pplayer, int city_id,
130 int worker_x, int worker_y)
132 struct tile *ptile;
133 struct tile *pcenter;
134 struct city *pcity = player_city_by_number(pplayer, city_id);
135 int city_radius_sq;
137 if (NULL == pcity) {
138 /* Probably lost. */
139 log_verbose("handle_city_make_specialist() bad city number %d.",
140 city_id);
141 return;
144 city_radius_sq = city_map_radius_sq_get(pcity);
145 if (!is_valid_city_coords(city_radius_sq, worker_x, worker_y)) {
146 log_error("handle_city_make_specialist() invalid city map {%d,%d} "
147 "\"%s\".", worker_x, worker_y, city_name_get(pcity));
148 return;
150 pcenter = city_tile(pcity);
152 if (NULL == (ptile = city_map_to_tile(pcenter, city_radius_sq, worker_x,
153 worker_y))) {
154 log_error("handle_city_make_specialist() unavailable city map {%d,%d} "
155 "\"%s\".", worker_x, worker_y, city_name_get(pcity));
156 return;
159 if (is_free_worked(pcity, ptile)) {
160 auto_arrange_workers(pcity);
161 } else if (tile_worked(ptile) == pcity) {
162 city_map_update_empty(pcity, ptile);
163 pcity->specialists[DEFAULT_SPECIALIST]++;
164 } else {
165 log_verbose("handle_city_make_specialist() not working {%d,%d} \"%s\".",
166 worker_x, worker_y, city_name_get(pcity));
169 city_refresh(pcity);
170 sanity_check_city(pcity);
171 sync_cities();
174 /**************************************************************************
175 Handle request to turn specialist in to city worker. Client cannot
176 tell which kind of specialist is to be taken, but this just makes worker
177 from first available specialist.
178 **************************************************************************/
179 void handle_city_make_worker(struct player *pplayer, int city_id,
180 int worker_x, int worker_y)
182 struct tile *ptile;
183 struct tile *pcenter;
184 struct city *pcity = player_city_by_number(pplayer, city_id);
185 int city_radius_sq = city_map_radius_sq_get(pcity);
187 if (NULL == pcity) {
188 /* Probably lost. */
189 log_verbose("handle_city_make_worker() bad city number %d.",city_id);
190 return;
193 if (!is_valid_city_coords(city_radius_sq, worker_x, worker_y)) {
194 log_error("handle_city_make_worker() invalid city map {%d,%d} "
195 "\"%s\".", worker_x, worker_y, city_name_get(pcity));
196 return;
198 pcenter = city_tile(pcity);
200 if (NULL == (ptile = city_map_to_tile(pcenter, city_radius_sq, worker_x,
201 worker_y))) {
202 log_error("handle_city_make_worker() unavailable city map {%d,%d} "
203 "\"%s\".", worker_x, worker_y, city_name_get(pcity));
204 return;
207 if (is_free_worked(pcity, ptile)) {
208 auto_arrange_workers(pcity);
209 sync_cities();
210 return;
213 if (tile_worked(ptile) == pcity) {
214 log_verbose("handle_city_make_worker() already working {%d,%d} \"%s\".",
215 worker_x, worker_y, city_name_get(pcity));
216 return;
219 if (0 == city_specialists(pcity)) {
220 log_verbose("handle_city_make_worker() no specialists {%d,%d} \"%s\".",
221 worker_x, worker_y, city_name_get(pcity));
222 return;
225 if (!city_can_work_tile(pcity, ptile)) {
226 log_verbose("handle_city_make_worker() cannot work here {%d,%d} \"%s\".",
227 worker_x, worker_y, city_name_get(pcity));
228 return;
231 city_map_update_worker(pcity, ptile);
233 specialist_type_iterate(i) {
234 if (pcity->specialists[i] > 0) {
235 pcity->specialists[i]--;
236 break;
238 } specialist_type_iterate_end;
240 city_refresh(pcity);
241 sanity_check_city(pcity);
242 sync_cities();
245 /**************************************************************************
246 Handle improvement selling request. Caller is responsible to validate
247 input before passing to this function if it comes from untrusted source.
248 **************************************************************************/
249 void really_handle_city_sell(struct player *pplayer, struct city *pcity,
250 struct impr_type *pimprove)
252 enum test_result sell_result;
253 int price;
255 sell_result = test_player_sell_building_now(pplayer, pcity, pimprove);
257 if (sell_result == TR_ALREADY_SOLD) {
258 notify_player(pplayer, pcity->tile, E_BAD_COMMAND, ftc_server,
259 _("You have already sold something here this turn."));
260 return;
263 if (sell_result != TR_SUCCESS) {
264 return;
267 pcity->did_sell=TRUE;
268 price = impr_sell_gold(pimprove);
269 notify_player(pplayer, pcity->tile, E_IMP_SOLD, ftc_server,
270 PL_("You sell %s in %s for %d gold.",
271 "You sell %s in %s for %d gold.", price),
272 improvement_name_translation(pimprove),
273 city_link(pcity), price);
274 do_sell_building(pplayer, pcity, pimprove);
276 city_refresh(pcity);
278 /* If we sold the walls the other players should see it */
279 send_city_info(NULL, pcity);
280 send_player_info_c(pplayer, pplayer->connections);
283 /**************************************************************************
284 Handle improvement selling request. This function does check its
285 parameters as they may come from untrusted source over the network.
286 **************************************************************************/
287 void handle_city_sell(struct player *pplayer, int city_id, int build_id)
289 struct city *pcity = player_city_by_number(pplayer, city_id);
290 struct impr_type *pimprove = improvement_by_number(build_id);
292 if (!pcity || !pimprove) {
293 return;
295 really_handle_city_sell(pplayer, pcity, pimprove);
298 /**************************************************************************
299 Handle buying request. Caller is responsible to validate input before
300 passing to this function if it comes from untrusted source.
301 **************************************************************************/
302 void really_handle_city_buy(struct player *pplayer, struct city *pcity)
304 int cost, total;
306 /* This function corresponds to city_can_buy() in the client. */
308 fc_assert_ret(pcity && player_owns_city(pplayer, pcity));
310 if (pcity->turn_founded == game.info.turn) {
311 notify_player(pplayer, pcity->tile, E_BAD_COMMAND, ftc_server,
312 _("Cannot buy in city created this turn."));
313 return;
316 if (pcity->did_buy) {
317 notify_player(pplayer, pcity->tile, E_BAD_COMMAND, ftc_server,
318 _("You have already bought this turn."));
319 return;
322 if (city_production_has_flag(pcity, IF_GOLD)) {
323 notify_player(pplayer, pcity->tile, E_BAD_COMMAND, ftc_server,
324 _("You don't buy %s!"),
325 improvement_name_translation(pcity->production.value.building));
326 return;
329 if (VUT_UTYPE == pcity->production.kind && pcity->anarchy != 0) {
330 notify_player(pplayer, pcity->tile, E_BAD_COMMAND, ftc_server,
331 _("Can't buy units when city is in disorder."));
332 return;
335 total = city_production_build_shield_cost(pcity);
336 cost = city_production_buy_gold_cost(pcity);
337 if (cost <= 0) {
338 return; /* sanity */
340 if (cost > pplayer->economic.gold) {
341 /* In case something changed while player tried to buy, or player
342 * tried to cheat! */
343 /* Split into two to allow localization of two pluralisations. */
344 char buf[MAX_LEN_MSG];
345 /* TRANS: This whole string is only ever used when included in one
346 * other string (search for this string to find it). */
347 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("%d gold required.",
348 "%d gold required.",
349 cost), cost);
350 notify_player(pplayer, pcity->tile, E_BAD_COMMAND, ftc_server,
351 /* TRANS: %s is a pre-pluralised string:
352 * "%d gold required." */
353 PL_("%s You only have %d gold.",
354 "%s You only have %d gold.", pplayer->economic.gold),
355 buf, pplayer->economic.gold);
356 return;
359 pplayer->economic.gold-=cost;
360 if (pcity->shield_stock < total){
361 /* As we never put penalty on disbanded_shields, we can
362 * fully well add the missing shields there. */
363 pcity->disbanded_shields += total - pcity->shield_stock;
364 pcity->shield_stock=total; /* AI wants this -- Syela */
365 pcity->did_buy = TRUE; /* !PS: no need to set buy flag otherwise */
367 city_refresh(pcity);
369 if (VUT_UTYPE == pcity->production.kind) {
370 notify_player(pplayer, pcity->tile, E_UNIT_BUY, ftc_server,
371 /* TRANS: bought an unit. */
372 Q_("?unit:You bought %s in %s."),
373 utype_name_translation(pcity->production.value.utype),
374 city_name_get(pcity));
375 } else if (VUT_IMPROVEMENT == pcity->production.kind) {
376 notify_player(pplayer, pcity->tile, E_IMP_BUY, ftc_server,
377 /* TRANS: bought an improvement .*/
378 Q_("?improvement:You bought %s in %s."),
379 improvement_name_translation(pcity->production.value.building),
380 city_name_get(pcity));
383 conn_list_do_buffer(pplayer->connections);
384 send_city_info(pplayer, pcity);
385 send_player_info_c(pplayer, pplayer->connections);
386 conn_list_do_unbuffer(pplayer->connections);
389 /**************************************************************************
390 Handle city worklist update request
391 **************************************************************************/
392 void handle_city_worklist(struct player *pplayer, int city_id,
393 const struct worklist *worklist)
395 struct city *pcity = player_city_by_number(pplayer, city_id);
397 if (!pcity) {
398 return;
401 worklist_copy(&pcity->worklist, worklist);
403 send_city_info(pplayer, pcity);
406 /**************************************************************************
407 Handle buying request. This function does properly check its input as
408 it may come from untrusted source over the network.
409 **************************************************************************/
410 void handle_city_buy(struct player *pplayer, int city_id)
412 struct city *pcity = player_city_by_number(pplayer, city_id);
414 if (!pcity) {
415 return;
418 really_handle_city_buy(pplayer, pcity);
421 /**************************************************************************
422 Handle city refresh request
423 **************************************************************************/
424 void handle_city_refresh(struct player *pplayer, int city_id)
426 if (city_id != 0) {
427 struct city *pcity = player_city_by_number(pplayer, city_id);
429 if (!pcity) {
430 return;
433 city_refresh(pcity);
434 send_city_info(pplayer, pcity);
435 } else {
436 city_refresh_for_player(pplayer);
440 /**************************************************************************
441 Handle request to change current production.
442 **************************************************************************/
443 void handle_city_change(struct player *pplayer, int city_id,
444 int production_kind, int production_value)
446 struct universal prod;
447 struct city *pcity = player_city_by_number(pplayer, city_id);
449 if (!universals_n_is_valid(production_kind)) {
450 log_error("[%s] bad production_kind %d.", __FUNCTION__,
451 production_kind);
452 prod.kind = VUT_NONE;
453 return;
454 } else {
455 prod = universal_by_number(production_kind, production_value);
456 if (!universals_n_is_valid(prod.kind)) {
457 log_error("[%s] production_kind %d with bad production_value %d.",
458 __FUNCTION__, production_kind, production_value);
459 prod.kind = VUT_NONE;
460 return;
464 if (!pcity) {
465 return;
468 if (are_universals_equal(&pcity->production, &prod)) {
469 /* The client probably shouldn't send such a packet. */
470 return;
473 if (!can_city_build_now(pcity, &prod)) {
474 return;
476 if (!city_can_change_build(pcity)) {
477 notify_player(pplayer, pcity->tile, E_BAD_COMMAND, ftc_server,
478 _("You have bought this turn, can't change."));
479 return;
482 change_build_target(pplayer, pcity, &prod, E_CITY_PRODUCTION_CHANGED);
484 city_refresh(pcity);
485 sanity_check_city(pcity);
486 send_city_info(pplayer, pcity);
489 /****************************************************************************
490 'struct packet_city_rename' handler.
491 ****************************************************************************/
492 void handle_city_rename(struct player *pplayer, int city_id,
493 const char *name)
495 struct city *pcity = player_city_by_number(pplayer, city_id);
496 char message[1024];
498 if (!pcity) {
499 return;
502 if (!is_allowed_city_name(pplayer, name, message, sizeof(message))) {
503 notify_player(pplayer, pcity->tile, E_BAD_COMMAND,
504 ftc_server, "%s", message);
505 return;
508 sz_strlcpy(pcity->name, name);
509 city_refresh(pcity);
510 send_city_info(NULL, pcity);
513 /****************************************************************************
514 Handles a packet from the client that requests the city options for the
515 given city be changed.
516 ****************************************************************************/
517 void handle_city_options_req(struct player *pplayer, int city_id,
518 bv_city_options options)
520 struct city *pcity = player_city_by_number(pplayer, city_id);
522 if (!pcity) {
523 return;
526 pcity->city_options = options;
528 send_city_info(pplayer, pcity);