Added translator comment about government overthrown message.
[freeciv.git] / server / spacerace.c
blob46930d437edcaa0440c4ce5a739d15ebaef246fb
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 <string.h>
20 /* utility */
21 #include "fcintl.h"
22 #include "log.h"
23 #include "shared.h"
25 /* common */
26 #include "calendar.h"
27 #include "events.h"
28 #include "game.h"
29 #include "packets.h"
30 #include "spaceship.h"
32 /* server */
33 #include "plrhand.h"
34 #include "notify.h"
35 #include "srv_main.h"
37 #include "spacerace.h"
40 /**********************************************************************
41 Calculate and fill in the derived quantities about the spaceship.
42 Data reverse engineered from Civ1. --dwp
43 This could be in common, but its better for the client to take
44 the values the server calculates, in case things change.
45 ***********************************************************************/
46 void spaceship_calc_derived(struct player_spaceship *ship)
48 int i;
49 /* these are how many are connected: */
50 int fuel=0;
51 int propulsion=0;
52 int habitation=0;
53 int life_support=0;
54 int solar_panels=0;
56 fc_assert_ret(ship->structurals <= NUM_SS_STRUCTURALS);
57 fc_assert_ret(ship->components <= NUM_SS_COMPONENTS);
58 fc_assert_ret(ship->modules <= NUM_SS_MODULES);
60 ship->mass = 0;
61 ship->support_rate = ship->energy_rate =
62 ship->success_rate = ship->travel_time = 0.0;
64 for (i = 0; i < NUM_SS_STRUCTURALS; i++) {
65 if (BV_ISSET(ship->structure, i)) {
66 ship->mass += (i < 6) ? 200 : 100;
67 /* s0 to s3 are heavier; actually in Civ1 its a bit stranger
68 than this, but not worth figuring out --dwp */
71 for (i = 0; i < ship->fuel; i++) {
72 if (BV_ISSET(ship->structure, components_info[i * 2].required)) {
73 fuel++;
76 for (i = 0; i < ship->propulsion; i++) {
77 if (BV_ISSET(ship->structure, components_info[i * 2 + 1].required)) {
78 propulsion++;
81 for (i = 0; i < ship->habitation; i++) {
82 if (BV_ISSET(ship->structure, modules_info[i * 3].required)) {
83 habitation++;
86 for (i = 0; i < ship->life_support; i++) {
87 if (BV_ISSET(ship->structure, modules_info[i * 3 + 1].required)) {
88 life_support++;
91 for (i = 0; i < ship->solar_panels; i++) {
92 if (BV_ISSET(ship->structure, modules_info[i * 3 + 2].required)) {
93 solar_panels++;
97 ship->mass += 1600 * (habitation + life_support)
98 + 400 * (solar_panels + propulsion + fuel);
100 ship->population = habitation * 10000;
102 if (habitation > 0) {
103 ship->support_rate = life_support / (double) habitation;
105 if (life_support + habitation > 0) {
106 ship->energy_rate = 2.0 * solar_panels / (double)(life_support+habitation);
108 if (fuel>0 && propulsion>0) {
109 ship->success_rate =
110 MIN(ship->support_rate, 1.0) * MIN(ship->energy_rate, 1.0);
113 /* The Success% can be less by up to a few % in some cases
114 (I think if P != F or if P and/or F too small (eg <= 2?) ?)
115 but probably not worth worrying about.
116 Actually, the Civ1 manual suggests travel time is relevant. --dwp
119 ship->travel_time = ship->mass
120 / (200.0 * MIN(propulsion,fuel) + 20.0);
124 /**************************************************************************
125 Send details of src's spaceship (or spaceships of all players
126 if src is NULL) to specified destinations. If dest is NULL then
127 game.est_connections is used.
128 **************************************************************************/
129 void send_spaceship_info(struct player *src, struct conn_list *dest)
131 if (!dest) {
132 dest = game.est_connections;
135 players_iterate(pplayer) {
136 if (!src || pplayer == src) {
137 struct packet_spaceship_info info;
138 struct player_spaceship *ship = &pplayer->spaceship;
140 info.player_num = player_number(pplayer);
141 info.sship_state = ship->state;
142 info.structurals = ship->structurals;
143 info.components = ship->components;
144 info.modules = ship->modules;
145 info.fuel = ship->fuel;
146 info.propulsion = ship->propulsion;
147 info.habitation = ship->habitation;
148 info.life_support = ship->life_support;
149 info.solar_panels = ship->solar_panels;
150 info.launch_year = ship->launch_year;
151 info.population = ship->population;
152 info.mass = ship->mass;
153 info.support_rate = ship->support_rate;
154 info.energy_rate = ship->energy_rate;
155 info.success_rate = ship->success_rate;
156 info.travel_time = ship->travel_time;
157 info.structure = ship->structure;
159 lsend_packet_spaceship_info(dest, &info);
161 } players_iterate_end;
164 /**************************************************************************
165 Handle spaceship launch request.
166 **************************************************************************/
167 void handle_spaceship_launch(struct player *pplayer)
169 struct player_spaceship *ship = &pplayer->spaceship;
170 int arrival;
172 if (!player_capital(pplayer)) {
173 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
174 _("You need to have a capital in order to launch "
175 "your spaceship."));
176 return;
178 if (ship->state >= SSHIP_LAUNCHED) {
179 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
180 _("Your spaceship is already launched!"));
181 return;
183 if (ship->state != SSHIP_STARTED
184 || ship->success_rate == 0.0) {
185 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
186 _("Your spaceship can't be launched yet!"));
187 return;
190 ship->state = SSHIP_LAUNCHED;
191 ship->launch_year = game.info.year;
192 arrival = ship->launch_year + (int) ship->travel_time;
194 notify_player(NULL, NULL, E_SPACESHIP, ftc_server,
195 _("The %s have launched a spaceship! "
196 "It is estimated to arrive at Alpha Centauri in %s."),
197 nation_plural_for_player(pplayer),
198 textyear(arrival));
200 send_spaceship_info(pplayer, NULL);
203 /**************************************************************************
204 Handle spaceship part placement request
205 **************************************************************************/
206 void handle_spaceship_place(struct player *pplayer,
207 enum spaceship_place_type type, int num)
209 (void) do_spaceship_place(pplayer, TRUE, type, num);
212 /**************************************************************************
213 Place a spaceship part
214 **************************************************************************/
215 bool do_spaceship_place(struct player *pplayer, bool user_initiated,
216 enum spaceship_place_type type, int num)
218 struct player_spaceship *ship = &pplayer->spaceship;
220 if (ship->state == SSHIP_NONE) {
221 if (user_initiated) {
222 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
223 _("Spaceship action received,"
224 " but you don't have a spaceship!"));
227 return FALSE;
230 if (ship->state >= SSHIP_LAUNCHED) {
231 if (user_initiated) {
232 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
233 _("You can't modify your spaceship after launch!"));
236 return FALSE;
239 if (type == SSHIP_PLACE_STRUCTURAL) {
240 if (num < 0 || num >= NUM_SS_STRUCTURALS
241 || BV_ISSET(ship->structure, num)) {
242 return FALSE;
244 if (num_spaceship_structurals_placed(ship) >= ship->structurals) {
245 if (user_initiated) {
246 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
247 _("You don't have any unplaced Space Structurals!"));
250 return FALSE;
252 if (num != 0
253 && !BV_ISSET(ship->structure, structurals_info[num].required)) {
254 if (user_initiated) {
255 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
256 _("That Space Structural would not be connected!"));
259 return FALSE;
262 BV_SET(ship->structure, num);
263 spaceship_calc_derived(ship);
264 send_spaceship_info(pplayer, NULL);
265 return TRUE;
268 if (type == SSHIP_PLACE_FUEL) {
269 if (ship->fuel != num - 1) {
270 return FALSE;
272 if (ship->fuel + ship->propulsion >= ship->components) {
273 if (user_initiated) {
274 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
275 _("You don't have any unplaced Space Components!"));
278 return FALSE;
280 if (num > NUM_SS_COMPONENTS/2) {
281 if (user_initiated) {
282 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
283 _("Your spaceship already has"
284 " the maximum number of Fuel Components!"));
287 return FALSE;
290 ship->fuel++;
291 spaceship_calc_derived(ship);
292 send_spaceship_info(pplayer, NULL);
293 return TRUE;
296 if (type == SSHIP_PLACE_PROPULSION) {
297 if (ship->propulsion != num - 1) {
298 return FALSE;
300 if (ship->fuel + ship->propulsion >= ship->components) {
301 if (user_initiated) {
302 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
303 _("You don't have any unplaced"
304 " Space Components!"));
307 return FALSE;
309 if (num > NUM_SS_COMPONENTS/2) {
310 if (user_initiated) {
311 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
312 _("Your spaceship already has the"
313 " maximum number of Propulsion Components!"));
316 return FALSE;
319 ship->propulsion++;
320 spaceship_calc_derived(ship);
321 send_spaceship_info(pplayer, NULL);
322 return TRUE;
325 if (type == SSHIP_PLACE_HABITATION) {
326 if (ship->habitation != num - 1) {
327 return FALSE;
329 if (ship->habitation + ship->life_support + ship->solar_panels
330 >= ship->modules) {
331 if (user_initiated) {
332 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
333 _("You don't have any unplaced Space Modules!"));
336 return FALSE;
338 if (num > NUM_SS_MODULES / 3) {
339 if (user_initiated) {
340 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
341 _("Your spaceship already has the"
342 " maximum number of Habitation Modules!"));
345 return FALSE;
348 ship->habitation++;
349 spaceship_calc_derived(ship);
350 send_spaceship_info(pplayer, NULL);
351 return TRUE;
354 if (type == SSHIP_PLACE_LIFE_SUPPORT) {
355 if (ship->life_support != num - 1) {
356 return FALSE;
358 if (ship->habitation + ship->life_support + ship->solar_panels
359 >= ship->modules) {
360 if (user_initiated) {
361 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
362 _("You don't have any unplaced Space Modules!"));
365 return FALSE;
367 if (num > NUM_SS_MODULES / 3) {
368 if (user_initiated) {
369 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
370 _("Your spaceship already has the"
371 " maximum number of Life Support Modules!"));
374 return FALSE;
377 ship->life_support++;
378 spaceship_calc_derived(ship);
379 send_spaceship_info(pplayer, NULL);
380 return TRUE;
383 if (type == SSHIP_PLACE_SOLAR_PANELS) {
384 if (ship->solar_panels != num - 1) {
385 return FALSE;
387 if (ship->habitation + ship->life_support + ship->solar_panels
388 >= ship->modules) {
389 if (user_initiated) {
390 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
391 _("You don't have any unplaced Space Modules!"));
394 return FALSE;
396 if (num > NUM_SS_MODULES / 3) {
397 if (user_initiated) {
398 notify_player(pplayer, NULL, E_SPACESHIP, ftc_server,
399 _("Your spaceship already has the"
400 " maximum number of Solar Panel Modules!"));
403 return FALSE;
406 ship->solar_panels++;
407 spaceship_calc_derived(ship);
408 send_spaceship_info(pplayer, NULL);
409 return TRUE;
412 log_error("Received unknown spaceship place type %d from %s",
413 type, player_name(pplayer));
414 return FALSE;
417 /**************************************************************************
418 Handle spaceship loss.
419 **************************************************************************/
420 void spaceship_lost(struct player *pplayer)
422 notify_player(NULL, NULL, E_SPACESHIP, ftc_server,
423 _("Without guidance from the capital, the %s "
424 "spaceship is lost!"),
425 nation_adjective_for_player(pplayer));
426 spaceship_init(&pplayer->spaceship);
427 send_spaceship_info(pplayer, NULL);
430 /**************************************************************************
431 Use shuffled order to randomly resolve ties.
432 **************************************************************************/
433 struct player *check_spaceship_arrival(void)
435 double arrival, best_arrival = 0.0;
436 struct player *best_pplayer = NULL;
438 shuffled_players_iterate(pplayer) {
439 struct player_spaceship *ship = &pplayer->spaceship;
441 if (ship->state == SSHIP_LAUNCHED) {
442 arrival = ship->launch_year + ship->travel_time;
443 if (game.info.year >= (int)arrival
444 && (!best_pplayer || arrival < best_arrival)) {
445 best_arrival = arrival;
446 best_pplayer = pplayer;
449 } shuffled_players_iterate_end;
451 if (best_pplayer) {
452 best_pplayer->spaceship.state = SSHIP_ARRIVED;
455 return best_pplayer;