246
258
* available candidates. */
247
259
int candidate_to_upgrade = myrand(unit_list_size(candidates));
248
260
struct unit *punit = unit_list_get(candidates, candidate_to_upgrade);
249
struct unit_type *upgrade_type
250
= can_upgrade_unittype(pplayer, unit_type(punit));
252
notify_player(pplayer, punit->tile, E_UNIT_UPGRADED,
253
_("%s was upgraded for free to %s."),
254
unit_name_translation(punit),
255
utype_name_translation(upgrade_type));
257
/* For historical reasons some veteran status may be lost while
258
* upgrading. Note that the upgraded unit may have the NoVeteran
260
if (utype_has_flag(upgrade_type, F_NO_VETERAN)) {
263
punit->veteran = MAX(punit->veteran
264
- game.info.autoupgrade_veteran_loss, 0);
266
assert(test_unit_upgrade(punit, TRUE) == UR_OK);
267
upgrade_unit(punit, upgrade_type, TRUE);
261
struct unit_type *type_from = unit_type(punit);
262
struct unit_type *type_to = can_upgrade_unittype(pplayer, type_from);
264
upgrade_unit(punit, type_to, TRUE);
265
notify_player(pplayer, unit_tile(punit), E_UNIT_UPGRADED, ftc_server,
266
_("%s was upgraded for free to %s."),
267
utype_name_translation(type_from),
268
269
unit_list_unlink(candidates, punit);
272
unit_list_unlink_all(candidates);
273
273
unit_list_free(candidates);
276
276
/***************************************************************************
277
Pay the cost of supported units of one city
278
***************************************************************************/
279
void pay_for_units(struct player *pplayer, struct city *pcity)
281
int potential_gold = 0;
283
built_impr_iterate(pcity, pimpr) {
284
if (can_city_sell_building(pcity, pimpr)) {
285
potential_gold += impr_sell_gold(pimpr);
287
} built_impr_iterate_end;
289
unit_list_iterate_safe(pcity->units_supported, punit) {
291
if (pplayer->economic.gold + potential_gold < punit->upkeep[O_GOLD]) {
292
/* We cannot upkeep this unit any longer and selling off city
293
* improvements will not help so we will have to disband */
294
assert(pplayer->economic.gold + potential_gold >= 0);
296
notify_player(pplayer, NULL, E_UNIT_LOST,
297
_("Not enough gold to pay upkeep "
298
"for %s. Unit disbanded."),
299
unit_name_translation(punit));
302
/* Gold can get negative here as city improvements will be sold
303
* afterwards to balance our budget. FIXME: Should units with gold
304
* upkeep give gold when they are disbanded? */
305
pplayer->economic.gold -= punit->upkeep[O_GOLD];
307
} unit_list_iterate_safe_end;
310
/***************************************************************************
311
277
1. Do Leonardo's Workshop upgrade if applicable.
313
279
2. Restore/decrease unit hitpoints.
315
281
3. Kill dead units.
317
4. Randomly kill units on unsafe terrain or unsafe-ocean.
319
5. Rescue airplanes by returning them to base automatically.
321
6. Decrease fuel of planes in the air.
323
7. Refuel planes that are in bases.
325
8. Kill planes that are out of fuel.
283
4. Rescue airplanes by returning them to base automatically.
285
5. Decrease fuel of planes in the air.
287
6. Refuel planes that are in bases.
289
7. Kill planes that are out of fuel.
326
290
****************************************************************************/
327
291
void player_restore_units(struct player *pplayer)
337
301
/* 3) Check that unit has hitpoints */
338
302
if (punit->hp<=0) {
339
303
/* This should usually only happen for heli units,
340
but if any other units get 0 hp somehow, catch
342
notify_player(pplayer, punit->tile, E_UNIT_LOST,
343
_("Your %s has run out of hit points."),
344
unit_name_translation(punit));
304
* but if any other units get 0 hp somehow, catch
306
notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC, ftc_server,
307
_("Your %s has run out of hit points."),
308
unit_tile_link(punit));
345
309
wipe_unit(punit);
346
310
continue; /* Continue iterating... */
349
/* 4) Check for units on unsafe terrains. */
350
if (unit_has_type_flag(punit, F_TRIREME)) {
351
/* Triremes away from coast have a chance of death. */
352
/* Note if a trireme died on a TER_UNSAFE terrain, this would
353
* erronously give the high seas message. This is impossible under
354
* the current rulesets. */
355
int loss_chance = unit_loss_pct(pplayer, punit->tile, punit);
357
if (myrand(100) < loss_chance) {
358
notify_player(pplayer, punit->tile, E_UNIT_LOST,
359
_("Your %s has been lost on the high seas."),
360
unit_name_translation(punit));
362
continue; /* Continue iterating... */
363
} else if (loss_chance > 0) {
364
if (maybe_make_veteran(punit)) {
365
notify_player(pplayer, punit->tile, E_UNIT_BECAME_VET,
366
_("Your %s survived on the high seas "
367
"and became more experienced!"),
368
unit_name_translation(punit));
371
} else if (!(is_air_unit(punit) || is_heli_unit(punit))
372
&& (myrand(100) < unit_loss_pct(pplayer,
373
punit->tile, punit))) {
374
/* All units may have a chance of dying if they are on TER_UNSAFE
376
notify_player(pplayer, punit->tile, E_UNIT_LOST,
377
_("Your %s has been lost on unsafe terrain."),
378
unit_name_translation(punit));
380
continue; /* Continue iterating... */
383
/* 5) Rescue planes if needed */
384
if (is_air_unit(punit)) {
313
/* 4) Rescue planes if needed */
314
if (utype_fuel(unit_type(punit))) {
385
315
/* Shall we emergency return home on the last vapors? */
387
317
/* I think this is strongly against the spirit of client goto.
390
320
if (punit->fuel <= 1
391
321
&& !is_unit_being_refueled(punit)) {
392
bool carrier_found = FALSE;
394
unit_list_iterate(punit->tile->units, carrier) {
395
if ((unit_has_type_flag(carrier, F_CARRIER)
396
|| (unit_has_type_flag(punit, F_MISSILE)
397
&& unit_has_type_flag(carrier, F_MISSILE_CARRIER)))
398
&& get_transporter_capacity(carrier) >
399
get_transporter_occupancy(carrier)) {
400
put_unit_onto_transporter(punit, carrier);
401
carrier_found = TRUE;
404
} unit_list_iterate_end;
406
if (!carrier_found) {
407
iterate_outward(punit->tile, punit->moves_left / SINGLE_MOVE, itr_tile) {
408
if (is_airunit_refuel_point(itr_tile, unit_owner(punit),
409
unit_type(punit), FALSE)
410
&&(air_can_move_between(punit->moves_left / SINGLE_MOVE, punit->tile,
411
itr_tile, unit_owner(punit)) >= 0)) {
322
struct unit *carrier;
324
carrier = find_transport_from_tile(punit, punit->tile);
326
put_unit_onto_transporter(punit, carrier);
331
struct pf_parameter parameter;
333
pft_fill_unit_parameter(¶meter, punit);
334
pfm = pf_map_new(¶meter);
336
pf_map_iterate_move_costs(pfm, ptile, move_cost, TRUE) {
337
if (move_cost > punit->moves_left) {
342
if (is_airunit_refuel_point(ptile, pplayer,
343
unit_type(punit), FALSE)) {
345
struct pf_path *path;
348
/* Client orders may be running for this unit - if so
349
* we free them before engaging goto. */
412
350
free_unit_orders(punit);
413
punit->goto_tile = itr_tile;
414
set_unit_activity(punit, ACTIVITY_GOTO);
415
(void) do_unit_goto(punit, GOTO_MOVE_ANY, FALSE);
417
if (!is_unit_being_refueled(punit)) {
418
unit_list_iterate(punit->tile->units, carrier) {
419
if ((unit_has_type_flag(carrier, F_CARRIER)
420
|| (unit_has_type_flag(punit, F_MISSILE)
421
&& unit_has_type_flag(carrier, F_MISSILE_CARRIER)))
422
&& get_transporter_capacity(carrier) >
423
get_transporter_occupancy(carrier)) {
352
path = pf_map_get_path(pfm, ptile);
354
alive = ai_follow_path(punit, path, ptile);
357
freelog(LOG_ERROR, "rescue plane: unit %d died enroute!", id);
358
} else if (!same_pos(punit->tile, ptile)) {
359
/* Enemy units probably blocked our route
360
* FIXME: We should try find alternative route around
361
* the enemy unit instead of just giving up and crashing. */
363
"rescue plane: unit %d could not move to refuel point!",
368
/* Clear activity. Unit info will be sent in the end of
370
unit_activity_handling(punit, ACTIVITY_IDLE);
371
punit->goto_tile = NULL;
373
if (!is_unit_being_refueled(punit)) {
374
carrier = find_transport_from_tile(punit, punit->tile);
424
376
put_unit_onto_transporter(punit, carrier);
427
} unit_list_iterate_end;
430
notify_player(pplayer, punit->tile, E_UNIT_ORDERS,
431
_("Your %s has returned to refuel."),
432
unit_name_translation(punit));
380
notify_player(pplayer, unit_tile(punit),
381
E_UNIT_ORDERS, ftc_server,
382
_("Your %s has returned to refuel."),
385
pf_path_destroy(path);
435
} iterate_outward_end;
388
} pf_map_iterate_move_costs_end;
392
/* Unit died trying to move to refuel point. */
442
/* 7) Automatically refuel air units in cities, airbases, and
401
/* 6) Automatically refuel air units in cities, airbases, and
443
402
* transporters (carriers). */
444
403
if (is_unit_being_refueled(punit)) {
445
punit->fuel=unit_type(punit)->fuel;
404
punit->fuel = utype_fuel(unit_type(punit));
448
407
} unit_list_iterate_safe_end;
450
/* 8) Check if there are air units without fuel */
409
/* 7) Check if there are air units without fuel */
451
410
unit_list_iterate_safe(pplayer->units, punit) {
452
if (is_air_unit(punit) && punit->fuel <= 0
453
&& unit_type(punit)->fuel > 0) {
454
notify_player(pplayer, punit->tile, E_UNIT_LOST,
455
_("Your %s has run out of fuel."),
456
unit_name_translation(punit));
411
if (punit->fuel <= 0 && utype_fuel(unit_type(punit))) {
412
notify_player(pplayer, unit_tile(punit), E_UNIT_LOST_MISC, ftc_server,
413
_("Your %s has run out of fuel."),
414
unit_tile_link(punit));
457
415
wipe_unit(punit);
459
417
} unit_list_iterate_safe_end;
617
notify_player(unit_owner(punit), punit->tile, E_UNIT_BECAME_VET,
602
notify_player(unit_owner(punit), unit_tile(punit),
603
E_UNIT_BECAME_VET, ftc_server,
618
604
/* TRANS: Your <unit> became ... */
619
605
_("Your %s became more experienced!"),
620
unit_name_translation(punit));
609
/**************************************************************************
610
Pillages base from tile
611
**************************************************************************/
612
static void unit_pillage_base(struct tile *ptile, struct base_type *pbase)
614
if (territory_claiming_base(pbase)) {
615
/* Clearing borders will take care of the vision providing
617
map_clear_border(ptile);
619
struct player *owner = tile_owner(ptile);
621
if (pbase->vision_main_sq >= 0 && owner) {
622
/* Base provides vision, but no borders. */
623
map_refog_circle(owner, ptile, pbase->vision_main_sq, -1,
624
game.info.vision_reveal_tiles, V_MAIN);
626
if (pbase->vision_invis_sq >= 0 && owner) {
627
/* Base provides vision, but no borders. */
628
map_refog_circle(owner, ptile, pbase->vision_invis_sq, -1,
629
game.info.vision_reveal_tiles, V_INVIS);
632
tile_remove_base(ptile, pbase);
623
635
/**************************************************************************
635
647
struct tile *ptile = punit->tile;
636
648
bool check_adjacent_units = FALSE;
638
if (activity != ACTIVITY_IDLE && activity != ACTIVITY_FORTIFIED
639
&& activity != ACTIVITY_GOTO && activity != ACTIVITY_EXPLORE) {
652
case ACTIVITY_EXPLORE:
653
case ACTIVITY_FORTIFIED:
655
case ACTIVITY_PATROL_UNUSED:
656
case ACTIVITY_UNKNOWN:
640
658
/* We don't need the activity_count for the above */
661
case ACTIVITY_FORTIFYING:
662
case ACTIVITY_SENTRY:
663
punit->activity_count += get_activity_rate_this_turn(punit);
666
case ACTIVITY_POLLUTION:
669
case ACTIVITY_IRRIGATE:
670
case ACTIVITY_FORTRESS:
671
case ACTIVITY_RAILROAD:
672
case ACTIVITY_PILLAGE:
673
case ACTIVITY_TRANSFORM:
674
case ACTIVITY_AIRBASE:
675
case ACTIVITY_FALLOUT:
641
677
punit->activity_count += get_activity_rate_this_turn(punit);
643
679
/* settler may become veteran when doing something useful */
644
if (activity != ACTIVITY_FORTIFYING && activity != ACTIVITY_SENTRY
645
&& maybe_settler_become_veteran(punit)) {
680
if (maybe_settler_become_veteran(punit)) {
646
681
notify_unit_experience(punit);
650
686
unit_restore_movepoints(pplayer, punit);
652
if (activity == ACTIVITY_EXPLORE) {
690
case ACTIVITY_FORTIFIED:
691
case ACTIVITY_FORTRESS:
692
case ACTIVITY_SENTRY:
694
case ACTIVITY_UNKNOWN:
695
case ACTIVITY_AIRBASE:
696
case ACTIVITY_FORTIFYING:
697
case ACTIVITY_PATROL_UNUSED:
699
/* no default, ensure all handled */
702
case ACTIVITY_EXPLORE:
653
703
do_explore(punit);
657
if (activity==ACTIVITY_PILLAGE) {
658
if (punit->activity_target == S_LAST) { /* case for old save files */
706
case ACTIVITY_PILLAGE:
707
if (punit->activity_target == S_LAST
708
&& punit->activity_base == -1) { /* case for old save files */
659
709
if (punit->activity_count >= 1) {
660
enum tile_special_type what
661
= get_preferred_pillage(get_tile_infrastructure_set(ptile, NULL));
710
enum tile_special_type what;
714
base_type_iterate(pbase) {
715
if (tile_has_base(ptile, pbase)) {
716
if (pbase->pillageable) {
717
BV_SET(bases, base_index(pbase));
720
} base_type_iterate_end;
722
what = get_preferred_pillage(get_tile_infrastructure_set(ptile, NULL),
663
725
if (what != S_LAST) {
664
tile_clear_special(ptile, what);
727
unit_pillage_base(ptile, base_by_number(what - S_LAST - 1));
729
tile_clear_special(ptile, what);
665
731
update_tile_knowledge(ptile);
666
732
set_unit_activity(punit, ACTIVITY_IDLE);
667
733
check_adjacent_units = TRUE;
685
755
} unit_list_iterate_end;
686
756
update_tile_knowledge(ptile);
688
ai_incident_pillage(unit_owner(punit), tile_owner(ptile));
758
call_incident(INCIDENT_PILLAGE, unit_owner(punit), tile_owner(ptile));
690
760
/* Change vision if effects have changed. */
691
761
unit_list_refresh_vision(ptile->units);
695
if (activity == ACTIVITY_POLLUTION) {
696
if (total_activity(ptile, ACTIVITY_POLLUTION)
697
>= tile_activity_time(ACTIVITY_POLLUTION, ptile)) {
765
case ACTIVITY_POLLUTION:
766
if (total_activity_done(ptile, ACTIVITY_POLLUTION)) {
698
767
tile_clear_special(ptile, S_POLLUTION);
699
768
unit_activity_done = TRUE;
703
if (activity == ACTIVITY_FALLOUT) {
704
if (total_activity(ptile, ACTIVITY_FALLOUT)
705
>= tile_activity_time(ACTIVITY_FALLOUT, ptile)) {
772
case ACTIVITY_FALLOUT:
773
if (total_activity_done(ptile, ACTIVITY_FALLOUT)) {
706
774
tile_clear_special(ptile, S_FALLOUT);
707
775
unit_activity_done = TRUE;
711
if (activity == ACTIVITY_FORTRESS) {
712
if (total_activity (ptile, ACTIVITY_FORTRESS)
713
>= tile_activity_time(ACTIVITY_FORTRESS, ptile)) {
714
tile_set_special(ptile, S_FORTRESS);
715
map_claim_ownership(ptile, unit_owner(punit), ptile);
716
unit_activity_done = TRUE;
718
/* watchtower becomes effective
719
* FIXME: Reqs on other specials will not be updated immediately. */
720
unit_list_refresh_vision(ptile->units);
724
if (activity == ACTIVITY_AIRBASE) {
725
if (total_activity (ptile, ACTIVITY_AIRBASE)
726
>= tile_activity_time(ACTIVITY_AIRBASE, ptile)) {
727
tile_set_special(ptile, S_AIRBASE);
728
unit_activity_done = TRUE;
732
if (activity == ACTIVITY_IRRIGATE) {
733
if (total_activity (ptile, ACTIVITY_IRRIGATE)
734
>= tile_activity_time(ACTIVITY_IRRIGATE, ptile)) {
735
struct terrain *old = tile_get_terrain(ptile);
780
if (total_activity_base(ptile, punit->activity_base)
781
>= tile_activity_base_time(ptile, punit->activity_base)) {
782
struct base_type *new_base = base_by_number(punit->activity_base);
784
create_base(ptile, new_base, unit_owner(punit));
786
unit_activity_done = TRUE;
790
case ACTIVITY_IRRIGATE:
791
if (total_activity_done(ptile, ACTIVITY_IRRIGATE)) {
792
struct terrain *old = tile_terrain(ptile);
737
794
tile_apply_activity(ptile, ACTIVITY_IRRIGATE);
738
795
check_terrain_change(ptile, old);
739
796
unit_activity_done = TRUE;
743
if (activity == ACTIVITY_ROAD) {
801
case ACTIVITY_TRANSFORM:
802
if (total_activity_done(ptile, activity)) {
803
struct terrain *old = tile_terrain(ptile);
805
tile_apply_activity(ptile, activity);
806
check_terrain_change(ptile, old);
807
unit_activity_done = TRUE;
808
check_adjacent_units = TRUE;
744
813
if (total_activity (ptile, ACTIVITY_ROAD)
745
814
+ total_activity (ptile, ACTIVITY_RAILROAD)
746
815
>= tile_activity_time(ACTIVITY_ROAD, ptile)) {
747
816
tile_set_special(ptile, S_ROAD);
748
817
unit_activity_done = TRUE;
752
if (activity == ACTIVITY_RAILROAD) {
753
if (total_activity (ptile, ACTIVITY_RAILROAD)
754
>= tile_activity_time(ACTIVITY_RAILROAD, ptile)) {
821
case ACTIVITY_RAILROAD:
822
if (total_activity_done(ptile, ACTIVITY_RAILROAD)) {
755
823
tile_set_special(ptile, S_RAILROAD);
756
824
unit_activity_done = TRUE;
760
if (activity == ACTIVITY_MINE) {
761
if (total_activity (ptile, ACTIVITY_MINE)
762
>= tile_activity_time(ACTIVITY_MINE, ptile)) {
763
struct terrain *old = tile_get_terrain(ptile);
765
tile_apply_activity(ptile, ACTIVITY_MINE);
766
check_terrain_change(ptile, old);
767
unit_activity_done = TRUE;
768
check_adjacent_units = TRUE;
772
if (activity == ACTIVITY_TRANSFORM) {
773
if (total_activity (ptile, ACTIVITY_TRANSFORM)
774
>= tile_activity_time(ACTIVITY_TRANSFORM, ptile)) {
775
struct terrain *old = tile_get_terrain(ptile);
777
tile_apply_activity(ptile, ACTIVITY_TRANSFORM);
778
check_terrain_change(ptile, old);
779
unit_activity_done = TRUE;
780
check_adjacent_units = TRUE;
784
829
if (unit_activity_done) {
785
830
update_tile_knowledge(ptile);
1427
1502
/* This unit may have blocked tiles of adjacent cities. Update them. */
1428
map_city_radius_iterate(unit_tile, ptile1) {
1429
struct city *pcity = tile_get_city(ptile1);
1431
update_city_tile_status_map(pcity, unit_tile);
1433
} map_city_radius_iterate_end;
1503
city_map_update_tile_now(ptile);
1436
1506
if (phomecity) {
1437
1507
city_refresh(phomecity);
1438
1508
send_city_info(city_owner(phomecity), phomecity);
1440
1511
if (pcity && pcity != phomecity) {
1441
1512
city_refresh(pcity);
1442
1513
send_city_info(city_owner(pcity), pcity);
1444
if (pcity && unit_list_size(unit_tile->units) == 0) {
1516
if (pcity && unit_list_size(ptile->units) == 0) {
1445
1517
/* The last unit in the city was killed: update the occupied flag. */
1446
1518
send_city_info(NULL, pcity);
1450
1522
/**************************************************************************
1523
Handle units destroyed when their transport is destroyed
1524
**************************************************************************/
1525
static void unit_lost_with_transport(const struct player *pplayer,
1526
struct unit *pcargo,
1527
struct unit_type *ptransport)
1529
notify_player(pplayer, unit_tile(pcargo), E_UNIT_LOST_MISC, ftc_server,
1530
_("%s lost when %s was lost."),
1531
unit_tile_link(pcargo),
1532
utype_name_translation(ptransport));
1533
server_remove_unit(pcargo);
1536
/**************************************************************************
1451
1537
Remove the unit, and passengers if it is a carrying any. Remove the
1452
1538
_minimum_ number, eg there could be another boat on the square.
1453
1539
**************************************************************************/
1454
1540
void wipe_unit(struct unit *punit)
1456
bool wipe_cargo = TRUE; /* This used to be a function parameter. */
1457
1542
struct tile *ptile = punit->tile;
1458
1543
struct player *pplayer = unit_owner(punit);
1459
struct unit_type *putype_save = unit_type(punit);
1544
struct unit_type *putype_save = unit_type(punit); /* for notify messages */
1546
int saved_id = punit->id;
1547
int homecity_id = punit->homecity;
1461
1549
/* First pull all units off of the transporter. */
1462
1550
if (get_transporter_capacity(punit) > 0) {
1465
1553
/* Could use unload_unit_from_transporter here, but that would
1466
1554
* call send_unit_info for the transporter unnecessarily. */
1467
1555
pull_unit_from_transporter(pcargo, punit);
1556
if (!can_unit_exist_at_tile(pcargo, ptile)) {
1468
1559
if (pcargo->activity == ACTIVITY_SENTRY) {
1469
1560
/* Activate sentried units - like planes on a disbanded carrier.
1470
1561
* Note this will activate ground units even if they just change
1471
1562
* transporter. */
1472
1563
set_unit_activity(pcargo, ACTIVITY_IDLE);
1474
send_unit_info(NULL, pcargo);
1565
if (!can_unit_exist_at_tile(pcargo, ptile)) {
1567
/* No need for send_unit_info() here. Unit info will be sent
1568
* when it is assigned to a new transport or it will be removed. */
1570
send_unit_info(NULL, pcargo);
1476
1573
} unit_list_iterate_end;
1479
/* No need to wipe the cargo unless it's a ground transporter. */
1480
wipe_cargo &= is_ground_units_transport(punit);
1482
/* FIXME: is this the correct time to remove the unit?
1483
* putype_save used to bypass this for two later notify messages
1485
/* Now remove the unit. */
1486
server_remove_unit(punit);
1488
/* Finally reassign, bounce, or destroy all ground units at this location.
1489
* There's no need to worry about air units; they can fly away. */
1491
&& is_ocean(tile_get_terrain(ptile))
1492
&& !tile_get_city(ptile)) {
1576
script_signal_emit("unit_lost", 2,
1577
API_TYPE_UNIT, punit,
1578
API_TYPE_PLAYER, pplayer);
1580
if (unit_alive(saved_id)) {
1581
/* Now remove the unit. */
1582
server_remove_unit(punit);
1585
/* update unit upkeep */
1586
city_units_upkeep(game_find_city_by_number(homecity_id));
1588
/* Finally reassign, bounce, or destroy all units that cannot exist at this
1589
* location without transport. */
1493
1591
struct city *pcity = NULL;
1494
int capacity = ground_unit_transporter_capacity(ptile, pplayer);
1496
/* Get rid of excess standard units. */
1498
unit_list_iterate_safe(ptile->units, pcargo) {
1499
if (is_ground_unit(pcargo)
1500
&& pcargo->transported_by == -1
1501
&& !unit_has_type_flag(pcargo, F_UNDISBANDABLE)
1502
&& !unit_has_type_flag(pcargo, F_GAMELOSS)) {
1503
server_remove_unit(pcargo);
1504
if (++capacity >= 0) {
1508
} unit_list_iterate_safe_end;
1511
/* Get rid of excess undisbandable/gameloss units. */
1513
unit_list_iterate_safe(ptile->units, pcargo) {
1514
if (is_ground_unit(pcargo) && pcargo->transported_by == -1) {
1593
/* First save undisbandable and gameloss units */
1594
unit_list_iterate_safe(ptile->units, pcargo) {
1595
if (pcargo->transported_by == -1
1596
&& !can_unit_exist_at_tile(pcargo, ptile)
1597
&& (unit_has_type_flag(pcargo, F_UNDISBANDABLE)
1598
|| unit_has_type_flag(pcargo, F_GAMELOSS))) {
1599
struct unit *ptransport = find_transport_from_tile(pcargo, ptile);
1600
if (ptransport != NULL) {
1601
put_unit_onto_transporter(pcargo, ptransport);
1602
send_unit_info(NULL, pcargo);
1515
1604
if (unit_has_type_flag(pcargo, F_UNDISBANDABLE)) {
1516
1605
pcity = find_closest_owned_city(unit_owner(pcargo),
1517
1606
pcargo->tile, TRUE, NULL);
1518
1607
if (pcity && teleport_unit_to_city(pcargo, pcity, 0, FALSE)) {
1519
notify_player(pplayer, ptile, E_UNIT_RELOCATED,
1608
notify_player(pplayer, ptile, E_UNIT_RELOCATED, ftc_server,
1520
1609
_("%s escaped the destruction of %s, and "
1521
1610
"fled to %s."),
1522
unit_name_translation(pcargo),
1523
1612
utype_name_translation(putype_save),
1527
if (!unit_has_type_flag(pcargo, F_UNDISBANDABLE) || !pcity) {
1528
notify_player(pplayer, ptile, E_UNIT_LOST,
1529
_("%s lost when %s was lost."),
1530
unit_name_translation(pcargo),
1531
utype_name_translation(putype_save));
1532
server_remove_unit(pcargo);
1534
if (++capacity >= 0) {
1538
} unit_list_iterate_safe_end;
1541
/* Reassign existing units. This is an O(n^2) operation as written. */
1542
unit_list_iterate(ptile->units, ptrans) {
1543
if (is_ground_units_transport(ptrans)) {
1544
int occupancy = get_transporter_occupancy(ptrans);
1546
unit_list_iterate(ptile->units, pcargo) {
1547
if (occupancy >= get_transporter_capacity(ptrans)) {
1550
if (is_ground_unit(pcargo) && pcargo->transported_by == -1) {
1551
put_unit_onto_transporter(pcargo, ptrans);
1554
} unit_list_iterate_end;
1556
} unit_list_iterate_end;
1616
if (!unit_has_type_flag(pcargo, F_UNDISBANDABLE) || !pcity) {
1617
unit_lost_with_transport(pplayer, pcargo, putype_save);
1626
} unit_list_iterate_safe_end;
1629
/* Then other units */
1631
unit_list_iterate_safe(ptile->units, pcargo) {
1632
if (pcargo->transported_by == -1
1633
&& !can_unit_exist_at_tile(pcargo, ptile)) {
1634
struct unit *ptransport = find_transport_from_tile(pcargo, ptile);
1636
if (ptransport != NULL) {
1637
put_unit_onto_transporter(pcargo, ptransport);
1638
send_unit_info(NULL, pcargo);
1640
unit_lost_with_transport(pplayer, pcargo, putype_save);
1648
} unit_list_iterate_safe_end;
1564
1656
**************************************************************************/
1565
1657
void kill_unit(struct unit *pkiller, struct unit *punit, bool vet)
1659
char pkiller_link[MAX_LEN_LINK], punit_link[MAX_LEN_LINK];
1567
1660
struct player *pvictim = unit_owner(punit);
1568
1661
struct player *pvictor = unit_owner(pkiller);
1569
1662
int ransom, unitcount = 0;
1664
sz_strlcpy(pkiller_link, unit_link(pkiller));
1665
sz_strlcpy(punit_link, unit_tile_link(punit));
1571
1667
/* barbarian leader ransom hack */
1572
1668
if( is_barbarian(pvictim) && unit_has_type_role(punit, L_BARBARIAN_LEADER)
1573
1669
&& (unit_list_size(punit->tile->units) == 1)
1574
&& (is_ground_unit(pkiller) || is_heli_unit(pkiller)) ) {
1670
&& uclass_has_flag(unit_class(pkiller), UCF_COLLECT_RANSOM)) {
1671
/* Occupying units can collect ransom if leader is alone in the tile */
1575
1672
ransom = (pvictim->economic.gold >= game.info.ransom_gold)
1576
1673
? game.info.ransom_gold : pvictim->economic.gold;
1577
notify_player(pvictor, pkiller->tile, E_UNIT_WIN_ATT,
1578
_("Barbarian leader captured, %d gold ransom paid."),
1674
notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
1675
_("Barbarian leader captured, %d gold ransom paid."),
1580
1677
pvictor->economic.gold += ransom;
1581
1678
pvictim->economic.gold -= ransom;
1582
1679
send_player_info(pvictor, NULL); /* let me see my new gold :-) */
1593
1690
if (!is_stack_vulnerable(punit->tile) || unitcount == 1) {
1594
notify_player(pvictor, pkiller->tile, E_UNIT_WIN_ATT,
1595
/* TRANS: "... Cannon ... the Polish Destroyer." */
1596
_("Your attacking %s succeeded against the %s %s!"),
1597
unit_name_translation(pkiller),
1598
nation_adjective_for_player(pvictim),
1599
unit_name_translation(punit));
1691
notify_player(pvictor, unit_tile(pkiller), E_UNIT_WIN_ATT, ftc_server,
1692
/* TRANS: "... Cannon ... the Polish Destroyer." */
1693
_("Your attacking %s succeeded against the %s %s!"),
1695
nation_adjective_for_player(pvictim),
1601
1698
notify_unit_experience(pkiller);
1603
notify_player(pvictim, punit->tile, E_UNIT_LOST,
1604
/* TRANS: "Cannon ... the Polish Destroyer." */
1605
_("%s lost to an attack by the %s %s."),
1606
unit_name_translation(punit),
1607
nation_adjective_for_player(pvictor),
1608
unit_name_translation(pkiller));
1700
notify_player(pvictim, unit_tile(punit), E_UNIT_LOST_DEF, ftc_server,
1701
/* TRANS: "Cannon ... the Polish Destroyer." */
1702
_("%s lost to an attack by the %s %s."),
1704
nation_adjective_for_player(pvictor),
1610
1707
wipe_unit(punit);
1611
1708
} else { /* unitcount > 1 */
1655
1752
* Also if a large number of units die you don't find out what type
1656
1753
* they all are. */
1657
for (i = 0; i<MAX_NUM_PLAYERS+MAX_NUM_BARBARIANS; i++) {
1754
for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
1658
1755
if (num_killed[i] == 1) {
1659
if (i == player_index(pvictim)) {
1660
assert(other_killed[i] == NULL);
1661
notify_player(player_by_number(i), punit->tile, E_UNIT_LOST,
1662
/* TRANS: "Cannon ... the Polish Destroyer." */
1663
_("%s lost to an attack by the %s %s."),
1664
unit_name_translation(punit),
1665
nation_adjective_for_player(pvictor),
1666
unit_name_translation(pkiller));
1668
assert(other_killed[i] != punit);
1669
notify_player(player_by_number(i), punit->tile, E_UNIT_LOST,
1670
/* TRANS: "Cannon lost when the Polish Destroyer
1671
* attacked the German Musketeers." */
1672
_("%s lost when the %s %s attacked the %s %s."),
1673
unit_name_translation(other_killed[i]),
1674
nation_adjective_for_player(pvictor),
1675
unit_name_translation(pkiller),
1676
nation_adjective_for_player(pvictim),
1677
unit_name_translation(punit));
1756
if (i == player_index(pvictim)) {
1757
assert(other_killed[i] == NULL);
1758
notify_player(player_by_number(i), unit_tile(punit),
1759
E_UNIT_LOST_DEF, ftc_server,
1760
/* TRANS: "Cannon ... the Polish Destroyer." */
1761
_("%s lost to an attack by the %s %s."),
1763
nation_adjective_for_player(pvictor),
1766
assert(other_killed[i] != punit);
1767
notify_player(player_by_number(i), unit_tile(punit),
1768
E_UNIT_LOST_DEF, ftc_server,
1769
/* TRANS: "Cannon lost when the Polish Destroyer
1770
* attacked the German Musketeers." */
1771
_("%s lost when the %s %s attacked the %s %s."),
1772
unit_link(other_killed[i]),
1773
nation_adjective_for_player(pvictor),
1775
nation_adjective_for_player(pvictim),
1679
1778
} else if (num_killed[i] > 1) {
1680
if (i == player_index(pvictim)) {
1681
int others = num_killed[i] - 1;
1779
if (i == player_index(pvictim)) {
1780
int others = num_killed[i] - 1;
1684
notify_player(player_by_number(i), punit->tile, E_UNIT_LOST,
1685
/* TRANS: "Musketeers (and Cannon) lost to an
1686
* attack from the Polish Destroyer." */
1687
_("%s (and %s) lost to an attack from the %s %s."),
1688
unit_name_translation(punit),
1689
unit_name_translation(other_killed[i]),
1690
nation_adjective_for_player(pvictor),
1691
unit_name_translation(pkiller));
1693
notify_player(player_by_number(i), punit->tile, E_UNIT_LOST,
1694
/* TRANS: "Musketeers and 3 other units lost to
1695
* an attack from the Polish Destroyer."
1696
* (only happens with at least 2 other units) */
1697
PL_("%s and %d other unit lost to an attack "
1699
"%s and %d other units lost to an attack "
1700
"from the %s %s.", others),
1701
unit_name_translation(punit),
1703
nation_adjective_for_player(pvictor),
1704
unit_name_translation(pkiller));
1707
notify_player(player_by_number(i), punit->tile, E_UNIT_LOST,
1708
/* TRANS: "2 units lost when the Polish Destroyer
1709
* attacked the German Musketeers."
1710
* (only happens with at least 2 other units) */
1711
PL_("%d unit lost when the %s %s attacked the %s %s.",
1712
"%d units lost when the %s %s attacked the %s %s.",
1715
nation_adjective_for_player(pvictor),
1716
unit_name_translation(pkiller),
1717
nation_adjective_for_player(pvictim),
1718
unit_name_translation(punit));
1783
notify_player(player_by_number(i), unit_tile(punit),
1784
E_UNIT_LOST_DEF, ftc_server,
1785
/* TRANS: "Musketeers (and Cannon) lost to an
1786
* attack from the Polish Destroyer." */
1787
_("%s (and %s) lost to an attack from the %s %s."),
1789
unit_link(other_killed[i]),
1790
nation_adjective_for_player(pvictor),
1793
notify_player(player_by_number(i), unit_tile(punit),
1794
E_UNIT_LOST_DEF, ftc_server,
1795
/* TRANS: "Musketeers and 3 other units lost to
1796
* an attack from the Polish Destroyer."
1797
* (only happens with at least 2 other units) */
1798
PL_("%s and %d other unit lost to an attack "
1800
"%s and %d other units lost to an attack "
1801
"from the %s %s.", others),
1804
nation_adjective_for_player(pvictor),
1808
notify_player(player_by_number(i), unit_tile(punit),
1809
E_UNIT_LOST_DEF, ftc_server,
1810
/* TRANS: "2 units lost when the Polish Destroyer
1811
* attacked the German Musketeers."
1812
* (only happens with at least 2 other units) */
1813
PL_("%d unit lost when the %s %s attacked the %s %s.",
1814
"%d units lost when the %s %s attacked the %s %s.",
1817
nation_adjective_for_player(pvictor),
1819
nation_adjective_for_player(pvictim),
1972
2076
**************************************************************************/
1973
2077
static void do_nuke_tile(struct player *pplayer, struct tile *ptile)
1975
struct city *pcity = tile_get_city(ptile);
2079
struct city *pcity = NULL;
1977
2081
unit_list_iterate_safe(ptile->units, punit) {
1978
notify_player(unit_owner(punit), ptile, E_UNIT_LOST,
1979
_("Your %s was nuked by %s."),
1980
unit_name_translation(punit),
1981
pplayer == unit_owner(punit)
1983
: nation_plural_for_player(pplayer));
2082
notify_player(unit_owner(punit), ptile, E_UNIT_LOST_MISC, ftc_server,
2083
_("Your %s was nuked by %s."),
2084
unit_tile_link(punit),
2085
pplayer == unit_owner(punit)
2087
: nation_plural_for_player(pplayer));
1984
2088
if (unit_owner(punit) != pplayer) {
1985
notify_player(pplayer, ptile, E_UNIT_WIN,
1986
_("The %s %s was nuked."),
1987
nation_adjective_for_player(unit_owner(punit)),
1988
unit_name_translation(punit));
2089
notify_player(pplayer, ptile, E_UNIT_WIN, ftc_server,
2090
_("The %s %s was nuked."),
2091
nation_adjective_for_player(unit_owner(punit)),
2092
unit_tile_link(punit));
1990
2094
wipe_unit(punit);
1991
2095
} unit_list_iterate_safe_end;
2097
pcity = tile_city(ptile);
1994
notify_player(city_owner(pcity), ptile, E_CITY_NUKED,
1995
_("%s was nuked by %s."),
1997
pplayer == city_owner(pcity)
1999
: nation_plural_for_player(pplayer));
2100
notify_player(city_owner(pcity), ptile, E_CITY_NUKED, ftc_server,
2101
_("%s was nuked by %s."),
2103
pplayer == city_owner(pcity)
2105
: nation_plural_for_player(pplayer));
2001
2107
if (city_owner(pcity) != pplayer) {
2002
notify_player(pplayer, ptile, E_CITY_NUKED,
2108
notify_player(pplayer, ptile, E_CITY_NUKED, ftc_server,
2007
city_reduce_size(pcity, pcity->size / 2);
2113
city_reduce_size(pcity, pcity->size / 2, pplayer);
2010
if (!is_ocean(tile_get_terrain(ptile)) && myrand(2) == 1) {
2116
if (!is_ocean_tile(ptile) && myrand(2) == 1) {
2011
2117
if (game.info.nuke_contamination == CONTAMINATION_POLLUTION) {
2012
2118
if (!tile_has_special(ptile, S_POLLUTION)) {
2013
2119
tile_set_special(ptile, S_POLLUTION);
2128
2238
if (get_transporter_occupancy(punit) > 0) {
2129
notify_player(pplayer, punit->tile, E_BAD_COMMAND,
2130
_("You cannot paradrop a unit that is "
2131
"transporting other units."));
2239
notify_player(pplayer, unit_tile(punit), E_BAD_COMMAND, ftc_server,
2240
_("You cannot paradrop a unit that is "
2241
"transporting other units."));
2134
2244
if (!map_is_known(ptile, pplayer)) {
2135
notify_player(pplayer, ptile, E_BAD_COMMAND,
2136
_("The destination location is not known."));
2245
notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2246
_("The destination location is not known."));
2140
2250
/* Safe terrain according to player map? */
2141
if (!is_native_terrain(punit, map_get_player_tile(ptile, pplayer)->terrain)) {
2142
notify_player(pplayer, ptile, E_BAD_COMMAND,
2143
_("This unit cannot paradrop into %s."),
2144
terrain_name_translation(
2145
map_get_player_tile(ptile, pplayer)->terrain));
2251
if (!is_native_terrain(unit_type(punit),
2252
map_get_player_tile(ptile, pplayer)->terrain,
2253
map_get_player_tile(ptile, pplayer)->special,
2254
map_get_player_tile(ptile, pplayer)->bases)) {
2255
notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2256
_("This unit cannot paradrop into %s."),
2257
terrain_name_translation(
2258
map_get_player_tile(ptile, pplayer)->terrain));
2149
2262
if (map_is_known_and_seen(ptile, pplayer, V_MAIN)
2150
&& ((tile_get_city(ptile)
2151
&& pplayers_non_attack(pplayer, city_owner(tile_get_city(ptile))))
2263
&& ((tile_city(ptile)
2264
&& pplayers_non_attack(pplayer, city_owner(tile_city(ptile))))
2152
2265
|| is_non_attack_unit_tile(ptile, pplayer))) {
2153
notify_player(pplayer, ptile, E_BAD_COMMAND,
2154
_("Cannot attack unless you declare war first."));
2266
notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2267
_("Cannot attack unless you declare war first."));
2159
2272
int range = unit_type(punit)->paratroopers_range;
2160
2273
int distance = real_map_distance(punit->tile, ptile);
2161
2274
if (distance > range) {
2162
notify_player(pplayer, ptile, E_BAD_COMMAND,
2163
_("The distance to the target (%i) "
2164
"is greater than the unit's range (%i)."),
2275
notify_player(pplayer, ptile, E_BAD_COMMAND, ftc_server,
2276
_("The distance to the target (%i) "
2277
"is greater than the unit's range (%i)."),
2170
2283
/* Safe terrain, really? Not transformed since player last saw it. */
2171
2284
if (!can_unit_exist_at_tile(punit, ptile)) {
2172
2285
map_show_circle(pplayer, ptile, unit_type(punit)->vision_radius_sq);
2173
notify_player(pplayer, ptile, E_UNIT_LOST,
2174
_("Your %s paradropped into the %s "
2176
unit_name_translation(punit),
2177
terrain_name_translation(ptile->terrain));
2286
notify_player(pplayer, ptile, E_UNIT_LOST_MISC, ftc_server,
2287
_("Your %s paradropped into the %s and was lost."),
2288
unit_tile_link(punit),
2289
terrain_name_translation(tile_terrain(ptile)));
2178
2290
server_remove_unit(punit);
2182
if ((tile_get_city(ptile) && pplayers_non_attack(pplayer, city_owner(tile_get_city(ptile))))
2294
if ((tile_city(ptile)
2295
&& pplayers_non_attack(pplayer, city_owner(tile_city(ptile))))
2183
2296
|| is_non_allied_unit_tile(ptile, pplayer)) {
2184
2297
map_show_circle(pplayer, ptile, unit_type(punit)->vision_radius_sq);
2185
2298
maybe_make_contact(ptile, pplayer);
2186
notify_player(pplayer, ptile, E_UNIT_LOST,
2187
_("Your %s was killed by enemy units at the "
2188
"paradrop destination."),
2189
unit_name_translation(punit));
2299
notify_player(pplayer, ptile, E_UNIT_LOST_MISC, ftc_server,
2300
_("Your %s was killed by enemy units at the "
2301
"paradrop destination."),
2302
unit_tile_link(punit));
2190
2303
server_remove_unit(punit);
2196
2309
int move_cost = unit_type(punit)->paratroopers_mr_sub;
2197
2310
punit->paradropped = TRUE;
2198
return move_unit(punit, ptile, move_cost);
2202
/**************************************************************************
2203
Get gold from entering a hut.
2204
**************************************************************************/
2205
static void hut_get_gold(struct unit *punit, int cred)
2207
struct player *pplayer = unit_owner(punit);
2208
notify_player(pplayer, punit->tile, E_HUT_GOLD,
2209
_("You found %d gold."), cred);
2210
pplayer->economic.gold += cred;
2213
/**************************************************************************
2214
Get a tech from entering a hut.
2215
**************************************************************************/
2216
static void hut_get_tech(struct unit *punit)
2218
struct player *pplayer = unit_owner(punit);
2219
Tech_type_id new_tech;
2220
const char* tech_name;
2222
new_tech = give_random_free_tech(pplayer);
2224
tech_name = advance_name_for_player(pplayer, new_tech);
2225
notify_player(pplayer, punit->tile, E_HUT_TECH,
2226
_("You found %s in ancient scrolls of wisdom."),
2228
script_signal_emit("tech_researched", 3,
2229
API_TYPE_TECH_TYPE, &advances[new_tech],
2230
API_TYPE_PLAYER, pplayer,
2231
API_TYPE_STRING, "hut");
2232
notify_embassies(pplayer, NULL, NULL, E_TECH_GAIN,
2233
_("The %s have acquired %s"
2234
" from ancient scrolls of wisdom."),
2235
nation_plural_for_player(pplayer),
2239
/**************************************************************************
2240
Get a mercenary unit from entering a hut.
2241
**************************************************************************/
2242
static void hut_get_mercenaries(struct unit *punit)
2244
struct player *pplayer = unit_owner(punit);
2246
notify_player(pplayer, punit->tile, E_HUT_MERC,
2247
_("A band of friendly mercenaries joins your cause."));
2248
(void) create_unit(pplayer, punit->tile,
2249
find_a_unit_type(L_HUT, L_HUT_TECH), FALSE,
2250
punit->homecity, -1);
2253
/**************************************************************************
2254
Get barbarians from hut, unless close to a city.
2255
Unit may die: returns 1 if unit is alive after, or 0 if it was killed.
2256
**************************************************************************/
2257
static bool hut_get_barbarians(struct unit *punit)
2259
struct player *pplayer = unit_owner(punit);
2262
if (city_exists_within_city_radius(punit->tile, TRUE)
2263
|| unit_has_type_flag(punit, F_GAMELOSS)) {
2264
notify_player(pplayer, punit->tile, E_HUT_BARB_CITY_NEAR,
2265
_("An abandoned village is here."));
2267
/* save coords and type in case unit dies */
2268
struct tile *unit_tile = punit->tile;
2269
struct unit_type *type = unit_type(punit);
2271
ok = unleash_barbarians(unit_tile);
2274
notify_player(pplayer, unit_tile, E_HUT_BARB,
2275
_("You have unleashed a horde of barbarians!"));
2277
notify_player(pplayer, unit_tile, E_HUT_BARB_KILLED,
2278
_("Your %s has been killed by barbarians!"),
2279
utype_name_translation(type));
2285
/**************************************************************************
2286
Get new city from hut, or settlers (nomads) if terrain is poor.
2287
**************************************************************************/
2288
static void hut_get_city(struct unit *punit)
2290
struct player *pplayer = unit_owner(punit);
2292
if (city_can_be_built_here(punit->tile, punit)) {
2293
notify_player(pplayer, punit->tile, E_HUT_CITY,
2294
_("You found a friendly city."));
2295
create_city(pplayer, punit->tile,
2296
city_name_suggestion(pplayer, punit->tile));
2298
if (unit_has_type_flag(punit, F_CITIES) || unit_has_type_flag(punit, F_SETTLERS)) {
2299
/* In case city was found during autosettler activities */
2300
initialize_infrastructure_cache(pplayer);
2303
/* Init ai.choice. Handling ferryboats might use it. */
2304
init_choice(&punit->tile->city->ai.choice);
2307
notify_player(pplayer, punit->tile, E_HUT_SETTLER,
2308
_("Friendly nomads are impressed by you,"
2310
(void) create_unit(pplayer, punit->tile, get_role_unit(F_CITIES,0),
2311
0, punit->homecity, -1);
2315
/**************************************************************************
2316
Return 1 if unit is alive, and 0 if it was killed
2317
**************************************************************************/
2318
static bool unit_enter_hut(struct unit *punit)
2320
struct player *pplayer = unit_owner(punit);
2311
move_unit(punit, ptile, move_cost);
2316
/**************************************************************************
2317
Give 25 Gold or kill the unit. For H_LIMITEDHUTS
2318
Return TRUE if unit is alive, and FALSE if it was killed
2319
**************************************************************************/
2320
static bool hut_get_limited(struct unit *punit)
2321
2322
bool ok = TRUE;
2322
2323
int hut_chance = myrand(12);
2324
if (game.info.hut_overflight == OVERFLIGHT_NOTHING && is_air_unit(punit)) {
2324
struct player *pplayer = unit_owner(punit);
2325
/* 1 in 12 to get barbarians */
2326
if (hut_chance != 0) {
2328
notify_player(pplayer, unit_tile(punit), E_HUT_GOLD, ftc_server,
2329
_("You found %d gold."), cred);
2330
pplayer->economic.gold += cred;
2331
} else if (city_exists_within_city_radius(punit->tile, TRUE)
2332
|| unit_has_type_flag(punit, F_GAMELOSS)) {
2333
notify_player(pplayer, unit_tile(punit),
2334
E_HUT_BARB_CITY_NEAR, ftc_server,
2335
_("An abandoned village is here."));
2337
notify_player(pplayer, unit_tile(punit), E_HUT_BARB_KILLED, ftc_server,
2338
_("Your %s has been killed by barbarians!"),
2339
unit_tile_link(punit));
2346
/**************************************************************************
2347
Due to the effects in the scripted hut behavior can not be predicted,
2348
unit_enter_hut returns nothing.
2349
**************************************************************************/
2350
static void unit_enter_hut(struct unit *punit)
2352
struct player *pplayer = unit_owner(punit);
2353
enum hut_behavior behavior = unit_class(punit)->hut_behavior;
2355
/* FIXME: Should we still run "hut_enter" script when
2356
* hut_behavior is HUT_NOTHING or HUT_FRIGHTEN? */
2357
if (behavior == HUT_NOTHING) {
2328
2361
tile_clear_special(punit->tile, S_HUT);
2329
2362
update_tile_knowledge(punit->tile);
2331
if (game.info.hut_overflight == OVERFLIGHT_FRIGHTEN && is_air_unit(punit)) {
2332
notify_player(pplayer, punit->tile, E_HUT_BARB,
2333
_("Your overflight frightens the tribe;"
2334
" they scatter in terror."));
2364
if (behavior == HUT_FRIGHTEN) {
2365
notify_player(pplayer, unit_tile(punit), E_HUT_BARB, ftc_server,
2366
_("Your overflight frightens the tribe;"
2367
" they scatter in terror."));
2338
2371
/* AI with H_LIMITEDHUTS only gets 25 gold (or barbs if unlucky) */
2339
if (pplayer->ai.control && ai_handicap(pplayer, H_LIMITEDHUTS)
2340
&& hut_chance != 10) {
2372
if (pplayer->ai_data.control && ai_handicap(pplayer, H_LIMITEDHUTS)) {
2373
(void) hut_get_limited(punit);
2344
2377
script_signal_emit("hut_enter", 1, API_TYPE_UNIT, punit);
2346
switch (hut_chance) {
2348
hut_get_gold(punit, 25);
2350
case 1: case 2: case 3:
2351
hut_get_gold(punit, 50);
2354
hut_get_gold(punit, 100);
2356
case 5: case 6: case 7:
2357
hut_get_tech(punit);
2360
if (num_role_units(L_HUT) != 0) {
2361
hut_get_mercenaries(punit);
2363
hut_get_gold(punit, 25);
2367
ok = hut_get_barbarians(punit);
2370
hut_get_city(punit);
2374
2379
send_player_info(pplayer, pplayer); /* eg, gold */
2378
2383
/****************************************************************************
2558
2564
*****************************************************************/
2559
2565
static void wakeup_neighbor_sentries(struct unit *punit)
2561
/* There may be sentried units with a sightrange>3, but we don't
2569
if (NULL != tile_city(unit_tile(punit))) {
2572
unit_list_iterate(unit_tile(punit)->units, aunit) {
2573
/* Consider only unit not transported. */
2574
if (-1 == punit->transported_by) {
2577
} unit_list_iterate_end;
2579
alone_in_city = (1 == count);
2581
alone_in_city = FALSE;
2584
/* There may be sentried units with a sightrange > 3, but we don't
2562
2585
wake them up if the punit is farther away than 3. */
2563
square_iterate(punit->tile, 3, ptile) {
2586
square_iterate(unit_tile(punit), 3, ptile) {
2564
2587
unit_list_iterate(ptile->units, penemy) {
2588
int distance_sq = sq_map_distance(punit->tile, ptile);
2565
2589
int radius_sq = get_unit_vision_at(penemy, penemy->tile, V_MAIN);
2566
enum unit_move_type move_type = unit_type(penemy)->move_type;
2567
struct terrain *pterrain = tile_get_terrain(ptile);
2569
2591
if (!pplayers_allied(unit_owner(punit), unit_owner(penemy))
2570
&& penemy->activity == ACTIVITY_SENTRY
2571
&& radius_sq >= sq_map_distance(punit->tile, ptile)
2572
&& can_player_see_unit(unit_owner(penemy), punit)
2573
/* on board transport; don't awaken */
2574
&& !(move_type == LAND_MOVING && is_ocean(pterrain))) {
2575
set_unit_activity(penemy, ACTIVITY_IDLE);
2576
send_unit_info(NULL, penemy);
2592
&& penemy->activity == ACTIVITY_SENTRY
2593
&& radius_sq >= distance_sq
2594
/* If the unit moved on a city, and the unit is alone, consider
2597
|| can_player_see_unit(unit_owner(penemy), punit))
2598
/* on board transport; don't awaken */
2599
&& can_unit_exist_at_tile(penemy, unit_tile(penemy))) {
2600
set_unit_activity(penemy, ACTIVITY_IDLE);
2601
send_unit_info(NULL, penemy);
2578
2603
} unit_list_iterate_end;
2579
2604
} square_iterate_end;
2587
2612
&& ppatrol->orders.vigilant) {
2588
2613
if (maybe_cancel_patrol_due_to_enemy(ppatrol)) {
2589
2614
cancel_orders(ppatrol, " stopping because of nearby enemy");
2590
notify_player(unit_owner(ppatrol), ppatrol->tile, E_UNIT_ORDERS,
2591
_("Orders for %s aborted after enemy movement was "
2593
unit_name_translation(ppatrol));
2615
notify_player(unit_owner(ppatrol), unit_tile(ppatrol),
2616
E_UNIT_ORDERS, ftc_server,
2617
_("Orders for %s aborted after enemy movement was "
2619
unit_link(ppatrol));
2596
2622
} unit_list_iterate_end;
2597
2623
} square_iterate_end;
2600
2626
/**************************************************************************
2601
Does: 1) updates the units homecity and the city it enters/leaves (the
2602
cities happiness varies). This also takes into account if the
2627
Does: 1) updates the unit's homecity and the city it enters/leaves (the
2628
city's happiness varies). This also takes into account when the
2603
2629
unit enters/leaves a fortress.
2604
2) handles any huts at the units destination.
2630
2) process any huts at the unit's destination.
2605
2631
3) updates adjacent cities' unavailable tiles.
2607
FIXME: Sometimes it is not neccesary to send cities because the goverment
2608
doesn't care if a unit is away or not.
2633
FIXME: Sometimes it is not necessary to send cities because the goverment
2634
doesn't care whether a unit is away or not.
2609
2635
**************************************************************************/
2610
static void handle_unit_move_consequences(struct unit *punit,
2611
struct tile *src_tile,
2612
struct tile *dst_tile,
2636
static void unit_move_consequences(struct unit *punit,
2637
struct tile *src_tile,
2638
struct tile *dst_tile,
2615
struct city *fromcity = tile_get_city(src_tile);
2616
struct city *tocity = tile_get_city(dst_tile);
2617
struct city *homecity = NULL;
2618
struct player *pplayer = unit_owner(punit);
2619
/* struct government *g = government_of_player(pplayer);*/
2620
bool refresh_homecity = FALSE;
2622
if (punit->homecity != 0) {
2623
homecity = game_find_city_by_number(punit->homecity);
2641
struct city *fromcity = tile_city(src_tile);
2642
struct city *tocity = tile_city(dst_tile);
2643
struct city *homecity_start_pos = NULL;
2644
struct city *homecity_end_pos = NULL;
2645
int homecity_id_start_pos = punit->homecity;
2646
int homecity_id_end_pos = punit->homecity;
2647
struct player *pplayer_start_pos = unit_owner(punit);
2648
struct player *pplayer_end_pos = pplayer_start_pos;
2649
struct unit_type *type_start_pos = unit_type(punit);
2650
struct unit_type *type_end_pos = type_start_pos;
2651
bool refresh_homecity_start_pos = FALSE;
2652
bool refresh_homecity_end_pos = FALSE;
2653
int saved_id = punit->id;
2654
bool unit_died = FALSE;
2627
handle_unit_enter_city(punit, tocity, passenger);
2630
/* We only do this for non-AI players to now make sure the AI turns
2657
unit_enter_city(punit, tocity, passenger);
2659
if(!unit_alive(saved_id)) {
2660
/* Unit died inside unit_enter_city().
2661
* This means that some cleanup has already taken place when it was
2662
* removed from game. */
2665
/* In case script has changed something about unit */
2666
pplayer_end_pos = unit_owner(punit);
2667
type_end_pos = unit_type(punit);
2668
homecity_id_end_pos = punit->homecity;
2672
if (homecity_id_start_pos != 0) {
2673
homecity_start_pos = game_find_city_by_number(homecity_id_start_pos);
2675
if (homecity_id_start_pos != homecity_id_end_pos) {
2676
homecity_end_pos = game_find_city_by_number(homecity_id_end_pos);
2678
homecity_end_pos = homecity_start_pos;
2681
/* We only do refreshes for non-AI players to now make sure the AI turns
2631
2682
doesn't take too long. Perhaps we should make a special refresh_city
2632
functions that only refreshed happiness. */
2633
if (!pplayer->ai.control) {
2634
/* might have changed owners or may be destroyed */
2635
tocity = tile_get_city(dst_tile);
2637
if (tocity) { /* entering a city */
2638
if (city_owner(tocity) == unit_owner(punit)) {
2639
if (tocity != homecity) {
2640
city_refresh(tocity);
2641
send_city_info(pplayer, tocity);
2645
refresh_homecity = TRUE;
2649
if (fromcity) { /* leaving a city */
2651
refresh_homecity = TRUE;
2653
if (fromcity != homecity && city_owner(fromcity) == unit_owner(punit)) {
2654
city_refresh(fromcity);
2655
send_city_info(pplayer, fromcity);
2659
/* entering/leaving a fortress or friendly territory */
2661
if ((game.info.happyborders > 0 && tile_owner(src_tile) != tile_owner(dst_tile))
2663
(tile_has_special(dst_tile, S_FORTRESS)
2664
&& is_friendly_city_near(unit_owner(punit), dst_tile))
2666
(tile_has_special(src_tile, S_FORTRESS)
2667
&& is_friendly_city_near(unit_owner(punit), src_tile))) {
2668
refresh_homecity = TRUE;
2672
if (refresh_homecity) {
2673
city_refresh(homecity);
2674
send_city_info(pplayer, homecity);
2678
/* The unit block different tiles of adjacent enemy cities before and
2679
after. Update the relevant cities. */
2681
/* First check cities near the source. */
2682
map_city_radius_iterate(src_tile, tile1) {
2683
struct city *pcity = tile_get_city(tile1);
2686
update_city_tile_status_map(pcity, src_tile);
2687
send_city_info(NULL, pcity);
2689
} map_city_radius_iterate_end;
2690
/* Then check cities near the destination. */
2691
map_city_radius_iterate(dst_tile, tile1) {
2692
struct city *pcity = tile_get_city(tile1);
2695
update_city_tile_status_map(pcity, dst_tile);
2696
send_city_info(NULL, pcity);
2698
} map_city_radius_iterate_end;
2683
functions that only refreshed happines. */
2685
/* might have changed owners or may be destroyed */
2686
tocity = tile_city(dst_tile);
2688
if (tocity) { /* entering a city */
2689
if (tocity->owner == pplayer_end_pos) {
2690
if (tocity != homecity_end_pos && !pplayer_end_pos->ai_data.control) {
2691
city_refresh(tocity);
2692
send_city_info(pplayer_end_pos, tocity);
2695
if (homecity_start_pos) {
2696
refresh_homecity_start_pos = TRUE;
2700
if (fromcity) { /* leaving a city */
2701
if (homecity_start_pos) {
2702
refresh_homecity_start_pos = TRUE;
2704
if (fromcity != homecity_start_pos
2705
&& fromcity->owner == pplayer_start_pos
2706
&& !pplayer_start_pos->ai_data.control) {
2707
city_refresh(fromcity);
2708
send_city_info(pplayer_start_pos, fromcity);
2712
/* entering/leaving a fortress or friendly territory */
2713
if (homecity_start_pos || homecity_end_pos) {
2714
if ((game.info.happyborders > 0 && tile_owner(src_tile) != tile_owner(dst_tile))
2715
|| (tile_has_base_flag_for_unit(dst_tile,
2718
&& is_friendly_city_near(pplayer_end_pos, dst_tile))
2719
|| (tile_has_base_flag_for_unit(src_tile,
2722
&& is_friendly_city_near(pplayer_start_pos, src_tile))) {
2723
refresh_homecity_start_pos = TRUE;
2724
refresh_homecity_end_pos = TRUE;
2728
if (refresh_homecity_start_pos && !pplayer_start_pos->ai_data.control) {
2729
city_refresh(homecity_start_pos);
2730
send_city_info(pplayer_start_pos, homecity_start_pos);
2732
if (refresh_homecity_end_pos
2733
&& (!refresh_homecity_start_pos
2734
|| homecity_start_pos != homecity_end_pos)
2735
&& !pplayer_end_pos->ai_data.control) {
2736
city_refresh(homecity_end_pos);
2737
send_city_info(pplayer_end_pos, homecity_end_pos);
2740
city_map_update_tile_now(dst_tile);
2789
2859
/* Enhance vision if unit steps into a fortress */
2790
new_vision = vision_new(unit_owner(punit), pdesttile, TRUE);
2791
punit->server.vision = new_vision;
2792
vision_layer_iterate(v) {
2793
vision_change_sight(new_vision, v,
2794
get_unit_vision_at(punit, pdesttile, v));
2795
} vision_layer_iterate_end;
2797
ASSERT_VISION(new_vision);
2799
/* Claim ownership of fortress? */
2800
if (tile_has_special(pdesttile, S_FORTRESS)
2801
&& (!tile_owner(pdesttile) || pplayers_at_war(tile_owner(pdesttile), pplayer))) {
2802
map_claim_ownership(pdesttile, pplayer, pdesttile);
2805
unit_list_unlink(psrctile->units, punit);
2806
punit->tile = pdesttile;
2807
punit->moved = TRUE;
2808
if (punit->transported_by != -1) {
2809
ptransporter = game_find_unit_by_number(punit->transported_by);
2810
pull_unit_from_transporter(punit, ptransporter);
2812
punit->moves_left = MAX(0, punit->moves_left - move_cost);
2813
if (punit->moves_left == 0) {
2814
punit->done_moving = TRUE;
2816
unit_list_prepend(pdesttile->units, punit);
2817
check_unit_activity(punit);
2861
new_vision = vision_new(unit_owner(punit), pdesttile);
2862
punit->server.vision = new_vision;
2863
vision_layer_iterate(v) {
2864
vision_change_sight(new_vision, v,
2865
get_unit_vision_at(punit, pdesttile, v));
2866
} vision_layer_iterate_end;
2868
ASSERT_VISION(new_vision);
2870
/* Claim ownership of fortress? */
2871
if (game.info.borders > 0
2872
&& tile_has_claimable_base(pdesttile, unit_type(punit))
2873
&& (!tile_owner(pdesttile)
2874
|| pplayers_at_war(tile_owner(pdesttile), pplayer))) {
2875
map_claim_ownership(pdesttile, pplayer, pdesttile);
2876
map_claim_border(pdesttile, pplayer);
2877
city_thaw_workers_queue();
2878
city_refresh_queue_processing();
2881
unit_list_unlink(psrctile->units, punit);
2882
punit->tile = pdesttile;
2883
punit->moved = TRUE;
2884
if (punit->transported_by != -1) {
2885
ptransporter = game_find_unit_by_number(punit->transported_by);
2886
pull_unit_from_transporter(punit, ptransporter);
2888
punit->moves_left = MAX(0, punit->moves_left - move_cost);
2889
if (punit->moves_left == 0) {
2890
punit->done_moving = TRUE;
2892
unit_list_prepend(pdesttile->units, punit);
2893
check_unit_activity(punit);
2820
2897
* Transporter info should be send first becouse this allow us get right
2828
2905
if (ptransporter) {
2829
2906
send_unit_info(NULL, ptransporter);
2832
2909
/* Send updated information to anyone watching. If the unit moves
2833
2910
* in or out of a city we update the 'occupied' field. Note there may
2834
2911
* be cities at both src and dest under some rulesets.
2835
2912
* If unit is about to take over enemy city, unit is seen by
2836
2913
* those players seeing inside cities of old city owner. After city
2837
* has been transferred, updated info is sent inside
2838
* handle_unit_enter_city() */
2839
send_unit_info_to_onlookers(NULL, punit, psrctile, FALSE);
2841
/* Special checks for ground units in the ocean. */
2842
if (!can_unit_survive_at_tile(punit, pdesttile)) {
2843
ptransporter = find_transporter_for_unit(punit, pdesttile);
2845
put_unit_onto_transporter(punit, ptransporter);
2848
/* Set activity to sentry if boarding a ship. */
2849
if (ptransporter && !pplayer->ai.control && !unit_has_orders(punit)
2850
&& !can_unit_exist_at_tile(punit, pdesttile)) {
2851
set_unit_activity(punit, ACTIVITY_SENTRY);
2855
* Transporter info should be send first becouse this allow us get right
2856
* update_menu effect in client side.
2860
* Send updated information to anyone watching that transporter has cargo.
2863
send_unit_info(NULL, ptransporter);
2867
* Send updated information to anyone watching that unit is on transport.
2868
* All players without shared vison with owner player get
2869
* REMOVE_UNIT package.
2871
send_unit_info_to_onlookers(NULL, punit, punit->tile, TRUE);
2914
* has been transferred, updated info is sent by unit_enter_city() */
2916
send_unit_info_to_onlookers(NULL, punit, psrctile, FALSE);
2918
/* Special checks for ground units in the ocean. */
2919
if (!can_unit_survive_at_tile(punit, pdesttile)) {
2920
ptransporter = find_transporter_for_unit(punit);
2922
put_unit_onto_transporter(punit, ptransporter);
2925
/* Set activity to sentry if boarding a ship. */
2926
if (ptransporter && !pplayer->ai_data.control && !unit_has_orders(punit)
2927
&& !can_unit_exist_at_tile(punit, pdesttile)) {
2928
set_unit_activity(punit, ACTIVITY_SENTRY);
2932
* Transporter info should be send first because this allow us get right
2933
* update_menu effect in client side.
2937
* Send updated information to anyone watching that transporter has cargo.
2940
send_unit_info(NULL, ptransporter);
2944
* Send updated information to anyone watching that unit is on transport.
2945
* All players without shared vison with owner player get
2946
* REMOVE_UNIT package.
2948
send_unit_info_to_onlookers(NULL, punit, punit->tile, TRUE);
2874
if ((pcity = tile_get_city(psrctile))) {
2952
if ((pcity = tile_city(psrctile))) {
2875
2953
refresh_dumb_city(pcity);
2877
if ((pcity = tile_get_city(pdesttile))) {
2955
if ((pcity = tile_city(pdesttile))) {
2878
2956
refresh_dumb_city(pcity);
3100
3201
case ORDER_ACTIVITY:
3101
3202
activity = order.activity;
3102
if (!can_unit_do_activity(punit, activity)) {
3103
cancel_orders(punit, " orders canceled because of failed activity");
3104
notify_player(pplayer, punit->tile, E_UNIT_ORDERS,
3105
_("Orders for %s aborted since they "
3106
"give an invalid activity."),
3107
unit_name_translation(punit));
3204
if ((activity == ACTIVITY_BASE && !can_unit_do_activity_base(punit, base))
3205
|| (activity != ACTIVITY_BASE
3206
&& !can_unit_do_activity(punit, activity))) {
3207
cancel_orders(punit, " orders canceled because of failed activity");
3208
notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
3209
_("Orders for %s aborted since they "
3210
"give an invalid activity."),
3110
3214
punit->done_moving = TRUE;
3111
set_unit_activity(punit, activity);
3216
if (activity != ACTIVITY_BASE) {
3217
set_unit_activity(punit, activity);
3219
set_unit_activity_base(punit, base);
3112
3221
send_unit_info(NULL, punit);
3114
3223
case ORDER_MOVE:
3115
3224
/* Move unit */
3116
3225
if (!(dst_tile = mapstep(punit->tile, order.dir))) {
3117
cancel_orders(punit, " move order sent us to invalid location");
3118
notify_player(pplayer, punit->tile, E_UNIT_ORDERS,
3119
_("Orders for %s aborted since they "
3120
"give an invalid location."),
3121
unit_name_translation(punit));
3226
cancel_orders(punit, " move order sent us to invalid location");
3227
notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
3228
_("Orders for %s aborted since they "
3229
"give an invalid location."),
3125
3234
if (!last_order
3126
&& maybe_cancel_goto_due_to_enemy(punit, dst_tile)) {
3127
cancel_orders(punit, " orders canceled because of enemy");
3128
notify_player(pplayer, punit->tile, E_UNIT_ORDERS,
3129
_("Orders for %s aborted as there "
3130
"are units in the way."),
3131
unit_name_translation(punit));
3235
&& maybe_cancel_goto_due_to_enemy(punit, dst_tile)) {
3236
cancel_orders(punit, " orders canceled because of enemy");
3237
notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
3238
_("Orders for %s aborted as there "
3239
"are units in the way."),
3135
3244
freelog(LOG_DEBUG, " moving to %d,%d",
3136
3245
dst_tile->x, dst_tile->y);
3137
res = handle_unit_move_request(punit, dst_tile, FALSE, !last_order);
3246
res = unit_move_handling(punit, dst_tile, FALSE, !last_order);
3138
3247
if (!player_find_unit_by_id(pplayer, unitid)) {
3139
3248
freelog(LOG_DEBUG, " unit died while moving.");
3140
3249
/* A player notification should already have been sent. */
3189
3297
case ORDER_HOMECITY:
3190
3298
freelog(LOG_DEBUG, " orders: changing homecity");
3191
if (punit->tile->city) {
3192
handle_unit_change_homecity(pplayer, unitid, punit->tile->city->id);
3299
if (tile_city(punit->tile)) {
3300
handle_unit_change_homecity(pplayer, unitid, tile_city(punit->tile)->id);
3194
cancel_orders(punit, " no homecity");
3195
notify_player(pplayer, punit->tile, E_UNIT_ORDERS,
3196
_("Attempt to change homecity for %s failed."),
3197
unit_name_translation(punit));
3302
cancel_orders(punit, " no homecity");
3303
notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
3304
_("Attempt to change homecity for %s failed."),
3201
case ORDER_TRADEROUTE:
3309
case ORDER_TRADE_ROUTE:
3202
3310
freelog(LOG_DEBUG, " orders: establishing trade route.");
3203
3311
handle_unit_establish_trade(pplayer, unitid);
3204
3312
if (player_find_unit_by_id(pplayer, unitid)) {
3205
cancel_orders(punit, " no trade route city");
3206
notify_player(pplayer, punit->tile, E_UNIT_ORDERS,
3207
_("Attempt to establish trade route for %s failed."),
3208
unit_name_translation(punit));
3313
cancel_orders(punit, " no trade route city");
3314
notify_player(pplayer, unit_tile(punit), E_UNIT_ORDERS, ftc_server,
3315
_("Attempt to establish trade route for %s failed."),