[Freeciv-Dev] Re: (PR#2521) general effects framework
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=2521 >
files attached...
<<< multipart/mixed; boundary="----------=_1079369036-12895-2": Unrecognized >>>
diff -Nur -Xcvs/diff_ignore snap/client/packhand.c snap-eff/client/packhand.c
--- snap/client/packhand.c 2004-02-27 23:37:18.000000000 -0600
+++ snap-eff/client/packhand.c 2004-03-05 20:40:54.000000000 -0600
@@ -1322,6 +1322,8 @@
game.heating=pinfo->heating;
game.nuclearwinter=pinfo->nuclearwinter;
game.cooling=pinfo->cooling;
+ game.can_nuke = pinfo->can_nuke;
+ game.can_space = pinfo->can_space;
if (!can_client_change_view()) {
improvement_status_init(game.improvements,
ARRAY_SIZE(game.improvements));
@@ -1505,6 +1507,9 @@
pplayer->gives_shared_vision = pinfo->gives_shared_vision;
pplayer->city_style=pinfo->city_style;
+ pplayer->can_nuke = pinfo->can_nuke;
+ pplayer->can_space = pinfo->can_space;
+
for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
pplayer->diplstates[i].type =
pinfo->diplstates[i].type;
diff -Nur -Xcvs/diff_ignore snap/common/game.c snap-eff/common/game.c
--- snap/common/game.c 2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/game.c 2004-03-05 20:40:54.000000000 -0600
@@ -256,6 +256,10 @@
game.heating = 0;
game.cooling = 0;
+
+ game.can_nuke = FALSE;
+ game.can_space = FALSE;
+
sz_strlcpy(game.save_name, GAME_DEFAULT_SAVE_NAME);
game.save_nturns=10;
#ifdef HAVE_LIBZ
diff -Nur -Xcvs/diff_ignore snap/common/game.h snap-eff/common/game.h
--- snap/common/game.h 2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/game.h 2004-03-05 20:40:54.000000000 -0600
@@ -119,6 +119,9 @@
int coolinglevel; /* If nuclearwinter is higher than this number there is
a chance of a cooling event. */
+ bool can_nuke; /* bits to record the two effects which survive */
+ bool can_space; /* their origin's destruction. */
+
char save_name[MAX_LEN_NAME];
int save_nturns;
int save_compress_level;
diff -Nur -Xcvs/diff_ignore snap/common/packets.def snap-eff/common/packets.def
--- snap/common/packets.def 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/packets.def 2004-03-05 20:40:54.000000000 -0600
@@ -340,7 +340,7 @@
UINT8 civstyle;
UINT8 diplomacy;
- BOOL spacerace;
+ BOOL spacerace, can_nuke, can_space;
UINT8 global_advances[A_LAST]; diff
UINT16 global_wonders[B_LAST]; diff
@@ -550,6 +550,7 @@
UINT8 barbarian_type;
uint32(unsigned int) gives_shared_vision;
BIT_STRING inventions[A_LAST+1];
+ BOOL can_nuke, can_space;
end
PACKET_PLAYER_TURN_DONE=40;cs
diff -Nur -Xcvs/diff_ignore snap/common/player.c snap-eff/common/player.c
--- snap/common/player.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/player.c 2004-03-05 20:40:54.000000000 -0600
@@ -146,6 +146,9 @@
}
}
+ plr->can_nuke = FALSE;
+ plr->can_space = FALSE;
+
plr->attribute_block.data = NULL;
plr->attribute_block.length = 0;
plr->debug = FALSE;
diff -Nur -Xcvs/diff_ignore snap/common/player.h snap-eff/common/player.h
--- snap/common/player.h 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/player.h 2004-03-05 20:40:54.000000000 -0600
@@ -210,6 +210,9 @@
Impr_Status *island_improv; /* improvements with equiv_range==Island,
dimensioned to
[map.num_continents][game.num_impr_types] */
+ bool can_nuke; /* bits to record the two effects which survive */
+ bool can_space; /* their origin's destruction. */
+
struct {
int length;
void *data;
diff -Nur -Xcvs/diff_ignore snap/server/savegame.c snap-eff/server/savegame.c
--- snap/server/savegame.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/savegame.c 2004-03-05 20:40:54.000000000 -0600
@@ -767,6 +767,11 @@
plr->revolution=secfile_lookup_int_default(file, 0, "player%d.revolution",
plrno);
+ plr->can_nuke = secfile_lookup_bool_default(file, FALSE,
+ "player%d.can_nuke", plrno);
+ plr->can_space = secfile_lookup_bool_default(file, FALSE,
+ "player%d.can_space", plrno);
+
tech_type_iterate(i) {
if (p[i] == '1') {
set_invention(plr, i, TECH_KNOWN);
@@ -1452,6 +1457,8 @@
secfile_insert_bool(file, plr->capital, "player%d.capital", plrno);
secfile_insert_int(file, plr->revolution, "player%d.revolution", plrno);
+ secfile_insert_bool(file, plr->can_nuke, "player%d.can_nuke", plrno);
+ secfile_insert_bool(file, plr->can_space, "player%d.can_space", plrno);
tech_type_iterate(tech_id) {
invs[tech_id] = (get_invention(plr, tech_id) == TECH_KNOWN) ? '1' : '0';
@@ -1968,6 +1975,9 @@
game.warminglevel = secfile_lookup_int(file, "game.warminglevel");
game.nuclearwinter = secfile_lookup_int_default(file, 0,
"game.nuclearwinter");
game.coolinglevel = secfile_lookup_int_default(file, 8,
"game.coolinglevel");
+ game.can_nuke = secfile_lookup_bool_default(file, FALSE, "game.can_nuke");
+ game.can_space = secfile_lookup_bool_default(file, FALSE,
"game.can_space");
+
game.notradesize = secfile_lookup_int_default(file, 0,
"game.notradesize");
game.fulltradesize = secfile_lookup_int_default(file, 1,
"game.fulltradesize");
game.unhappysize = secfile_lookup_int(file, "game.unhappysize");
@@ -2386,6 +2396,8 @@
secfile_insert_int(file, game.warminglevel, "game.warminglevel");
secfile_insert_int(file, game.nuclearwinter, "game.nuclearwinter");
secfile_insert_int(file, game.coolinglevel, "game.coolinglevel");
+ secfile_insert_bool(file, game.can_nuke, "game.can_nuke");
+ secfile_insert_bool(file, game.can_space, "game.can_space");
secfile_insert_int(file, game.notradesize, "game.notradesize");
secfile_insert_int(file, game.fulltradesize, "game.fulltradesize");
secfile_insert_int(file, game.unhappysize, "game.unhappysize");
diff -Nur -Xcvs/diff_ignore snap-pre/ai/aihand.c snap-eff/ai/aihand.c
--- snap-pre/ai/aihand.c 2003-09-21 20:18:36.000000000 -0500
+++ snap-eff/ai/aihand.c 2004-03-05 20:44:46.000000000 -0600
@@ -20,6 +20,7 @@
#include <string.h>
#include "city.h"
+#include "effects.h"
#include "game.h"
#include "government.h"
#include "log.h"
@@ -198,6 +199,7 @@
/* Ideally we should change tax rates here, but since
* this is a rather big CPU operation, we'd rather not. */
check_player_government_rates(pplayer);
+ /* effects_update_all(); FIXME: UNCOMMENT WHEN THIS IS READY -mck */
city_list_iterate(pplayer->cities, acity) {
generic_city_refresh(acity, TRUE, NULL);
auto_arrange_workers(acity);
diff -Nur -Xcvs/diff_ignore snap-pre/client/climisc.c snap-eff/client/climisc.c
--- snap-pre/client/climisc.c 2004-02-27 23:37:18.000000000 -0600
+++ snap-eff/client/climisc.c 2004-03-05 20:44:46.000000000 -0600
@@ -32,6 +32,7 @@
#include "city.h"
#include "diptreaty.h"
+#include "effects.h"
#include "fcintl.h"
#include "game.h"
#include "log.h"
@@ -56,6 +57,24 @@
#include "climisc.h"
+
+/**************************************************************************
+ the server needs to do more on update. see gamehand.c
+**************************************************************************/
+void effects_update_all(void)
+{
+ effects_update_all_common();
+}
+
+/**************************************************************************
+ the server needs to more on delete. see gamehand.c
+**************************************************************************/
+void delete_effects(enum effect_class class, struct player *pplayer,
+ struct city *pcity, struct unit *punit, int id)
+{
+ delete_effects_common(class, pplayer, pcity, punit, id);
+}
+
/**************************************************************************
...
**************************************************************************/
@@ -135,13 +154,15 @@
and to handle the preservation of "destroyed" effects. */
effect_update=FALSE;
+ effects_defer_update();
built_impr_iterate(pcity, i) {
effect_update = TRUE;
city_remove_improvement(pcity, i);
} built_impr_iterate_end;
+ effects_undefer_update();
if (effect_update) {
- /* nothing yet */
+ effects_update_all();
}
popdown_city_dialog(pcity);
diff -Nur -Xcvs/diff_ignore snap-pre/client/packhand.c
snap-eff/client/packhand.c
--- snap-pre/client/packhand.c 2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/client/packhand.c 2004-03-05 20:44:46.000000000 -0600
@@ -25,6 +25,7 @@
#include "capability.h"
#include "capstr.h"
+#include "effects.h"
#include "events.h"
#include "fcintl.h"
#include "game.h"
@@ -77,6 +78,80 @@
static int *reports_thaw_requests = NULL;
static int reports_thaw_requests_size = 0;
+
+#ifdef DEBUG
+/**************************************************************************
+ print out effect definition debugging info
+**************************************************************************/
+static void print_effect_definitions(struct effect_defn_vector *vec,
+ char *header)
+{
+ freelog(LOG_DEBUG, "%s", header);
+
+ effect_defn_vector_iterate(*vec, defn) {
+ char buf[1024], *ptr;
+ ptr = buf;
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " %d/%s",
+ defn->type, effect_type_name(defn->type));
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " range=%d/%s",
+ defn->range, effect_range_name(defn->range));
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " outside=%d", defn->outside);
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " amount=%d", defn->amount);
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " value1=%d", defn->value1);
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " value2=%d", defn->value2);
+ ptr = strchr(ptr, '\0');
+ freelog(LOG_DEBUG, " %s", buf);
+ ptr = buf;
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_bldg=%d/%s",
+ defn->cond_bldg, (defn->cond_bldg == B_LAST) ?
+ "Uncond." : improvement_types[defn->cond_bldg].name);
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_nat=%d/%s",
+ defn->cond_nat, (defn->cond_nat == -1) ?
+ "Uncond." : get_nation_name(defn->cond_gov));
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_gov=%d/%s",
+ defn->cond_gov, (defn->cond_gov == game.government_count) ?
+ "Uncond." : get_government_name(defn->cond_gov));
+ ptr = strchr(ptr, '\0');
+ freelog(LOG_DEBUG, " %s", buf);
+ ptr = buf;
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_adv=%d/%s",
+ defn->cond_adv, (defn->cond_adv == A_NONE) ?
+ "Uncond." : (defn->cond_adv == A_LAST) ? "Never" :
+ advances[defn->cond_adv].name);
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_eff=%d/%s",
+ defn->cond_eff, (defn->cond_eff == EFT_LAST) ?
+ "Uncond." : effect_type_name(defn->cond_eff));
+ ptr = strchr(ptr, '\0');
+ freelog(LOG_DEBUG, " %s", buf);
+ ptr = buf;
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_unit=%d/%s",
+ defn->aff_unit, (defn->aff_unit == UCL_LAST) ?
+ "All" : unit_class_name(defn->aff_unit));
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_terr=%d/%s",
+ defn->aff_terr, (defn->aff_terr == T_LAST) ?
+ "None" : (defn->aff_terr == T_UNKNOWN) ?
+ "All" : get_terrain_name(defn->aff_terr));
+ ptr = strchr(ptr, '\0');
+ my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_spec=%04X/%s",
+ defn->aff_spec, (defn->aff_spec == 0) ?
+ "None" : (defn->aff_spec == S_ALL) ?
+ "All" : get_special_name(defn->aff_spec));
+ ptr = strchr(ptr, '\0');
+ freelog(LOG_DEBUG, " %s", buf);
+ freelog(LOG_DEBUG, " ");
+ } effect_defn_vector_iterate_end;
+}
+#endif
+
/**************************************************************************
Unpackage the unit information into a newly allocated unit structure.
**************************************************************************/
@@ -291,15 +366,21 @@
/**************************************************************************
Updates a city's list of improvements from packet data. "impr" identifies
the improvement, and "have_impr" specifies whether the improvement should
- be added (TRUE) or removed (FALSE). "impr_changed" is set TRUE only if
+ be added (TRUE) or removed (FALSE). "impr_changed" is set TRUE only if
the existing improvement status was changed by this call.
-**************************************************************************/
+
+ Don't add immediate effects here, since we're only reporting to the client
+ what others have built. TODO: this may not be the best way to do this.
+ The client may want info on what effects had occurred in the past, but
+ will not get it this way. For example, getting a building with Get_Imm_Adv
+ will tell the client that another may be ahead in the tech race...
+*************************************************************************/
static void update_improvement_from_packet(struct city *pcity,
Impr_Type_id impr, bool have_impr,
bool *impr_changed)
{
if (have_impr && pcity->improvements[impr] == I_NONE) {
- city_add_improvement(pcity, impr);
+ city_add_improvement(pcity, impr, FALSE);
if (impr_changed) {
*impr_changed = TRUE;
@@ -319,7 +400,8 @@
static void try_update_effects(bool need_update)
{
if (need_update) {
- /* nothing yet... */
+ freelog(LOG_VERBOSE, "%%%%%%%%: try_update_effects"); /* DEBUGGING/REMOVE
*/
+ effects_update_all();
}
}
@@ -469,6 +551,10 @@
/* Initialise list of improvements with city/building wide equiv_range. */
improvement_status_init(pcity->improvements,
ARRAY_SIZE(pcity->improvements));
+
+ /* Initialise city's vector of improvement effects. */
+ effect_vector_init(&pcity->effects);
+ effect_vector_init(&pcity->impr_effects);
}
copy_worklist(&pcity->worklist, &packet->worklist);
pcity->did_buy=packet->did_buy;
@@ -500,15 +586,17 @@
}
}
+ effects_defer_update();
impr_type_iterate(i) {
- if (pcity->improvements[i] == I_NONE && packet->improvements[i] == '1'
- && !city_is_new) {
+ if (pcity->improvements[i] == I_NONE && packet->improvements[i] == '1'
+ && !city_is_new) {
audio_play_sound(get_improvement_type(i)->soundtag,
get_improvement_type(i)->soundtag_alt);
}
- update_improvement_from_packet(pcity, i, packet->improvements[i] == '1',
+ update_improvement_from_packet(pcity, i, packet->improvements[i] == '1',
&need_effect_update);
} impr_type_iterate_end;
+ effects_undefer_update();
/* Since we can see inside the city, just determine the client status
* from what we know. */
@@ -673,6 +761,10 @@
/* Initialise list of improvements with city/building wide equiv_range. */
improvement_status_init(pcity->improvements,
ARRAY_SIZE(pcity->improvements));
+
+ /* Initialise city's improvement effects. */
+ effect_vector_init(&pcity->effects);
+ effect_vector_init(&pcity->impr_effects);
}
update_improvement_from_packet(pcity, B_PALACE, packet->capital,
@@ -1392,13 +1484,20 @@
pplayer->research.inventions[i].state = newstate;
if (newstate != oldstate
&& (newstate == TECH_KNOWN || oldstate == TECH_KNOWN)) {
- need_effect_update = TRUE;
+ /* if could be that we could lose tech at some point */
+ if (newstate == TECH_KNOWN) {
+ add_tech_effects(game.player_ptr, i, TRUE);
+ need_effect_update = TRUE;
+ } else if (oldstate == TECH_KNOWN) {
+ delete_effects(EFC_TECH, pplayer, NULL, NULL, i);
+ need_effect_update = TRUE;
+ }
}
} tech_type_iterate_end;
if (need_effect_update) {
improvements_update_obsolete();
- /* need to update effects here too eventually */
+ effects_update_all();
}
update_research(pplayer);
@@ -1490,11 +1589,24 @@
int i;
bool poptechup, new_tech = FALSE;
char msg[MAX_LEN_MSG];
+ int old_gov_id;
+ int old_nat_id;
+
struct player *pplayer = &game.players[pinfo->playerno];
+ old_nat_id = pplayer->nation;
+ old_gov_id = pplayer->government;
+
sz_strlcpy(pplayer->name, pinfo->name);
pplayer->nation=pinfo->nation;
+
+ /* change nation effects if necessary */
+ if (old_nat_id != pplayer->nation) {
+ delete_effects(EFC_NATION, pplayer, NULL, NULL, old_nat_id);
+ add_nation_effects(pplayer, TRUE);
+ }
+
pplayer->is_male=pinfo->is_male;
pplayer->team = pinfo->team;
@@ -1503,6 +1615,13 @@
pplayer->economic.science=pinfo->science;
pplayer->economic.luxury=pinfo->luxury;
pplayer->government=pinfo->government;
+
+ /* change government effects */
+ if (old_gov_id != pplayer->government) {
+ delete_effects(EFC_GOVERNMENT, pplayer, NULL, NULL, old_gov_id);
+ add_government_effects(pplayer, TRUE);
+ }
+
pplayer->embassy=pinfo->embassy;
pplayer->gives_shared_vision = pinfo->gives_shared_vision;
pplayer->city_style=pinfo->city_style;
@@ -1704,6 +1823,36 @@
update_players_dialog();
}
+/*************************************************************************
+ handle any global effects that we ought to know about.
+**************************************************************************/
+void handle_global_effect(bool add_effect, int player,
+ struct effect_defn *effect_def)
+{
+ struct effect_defn *defn = fc_malloc(sizeof(struct effect_defn));
+ struct player *pplayer = get_player(player);
+
+ printf("in handle_global_effect(%s)\n",
+ add_effect ? "adding" : "deleting");
+ fflush(stdout); /* DEBUGGING */
+
+ *defn = *effect_def;
+
+ if (add_effect) {
+ struct effect *eff = append_effect(pplayer, NULL, NULL, EFR_WORLD);
+ eff->defn = defn;
+ eff->plr = pplayer;
+ eff->home = NULL;
+ eff->id = -1;
+ } else {
+ delete_effect(pplayer, NULL, NULL, -1, defn);
+ /* FIXME: we need to free the defn in the game.effects vector */
+ free(defn);
+ }
+
+ effects_update_all();
+}
+
/**************************************************************************
Ideally the client should let the player choose which type of
modules and components to build, and (possibly) where to extend
@@ -1970,6 +2119,7 @@
if (ptile->continent > map.num_continents) {
map.num_continents = ptile->continent;
allot_island_improvs();
+ allot_island_effects();
}
/* refresh tiles */
@@ -2160,6 +2310,14 @@
u->helptext = mystrdup(p->helptext);
+ effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+ &u->effect_defs);
+
+#ifdef DEBUG
+ freelog(LOG_DEBUG, "%s", u->name);
+ print_effect_definitions(&u->effect_defs, " effect...");
+#endif
+
tilespec_setup_unit_type(p->id);
}
@@ -2187,7 +2345,15 @@
a->preset_cost = p->preset_cost;
a->num_reqs = p->num_reqs;
a->helptext = mystrdup(p->helptext);
-
+
+ effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+ &a->effect_defs);
+
+#ifdef DEBUG
+ freelog(LOG_DEBUG, "%s", a->name);
+ print_effect_definitions(&a->effect_defs, " effect...");
+#endif
+
tilespec_setup_tech_type(p->id);
}
@@ -2236,11 +2402,8 @@
T(equiv_repl, equiv_repl_count, B_LAST);
#undef T
- b->effect = fc_malloc(sizeof(*b->effect) * (p->effect_count + 1));
- for (i = 0; i < p->effect_count; i++) {
- b->effect[i] = p->effect[i];
- }
- b->effect[p->effect_count].type = EFT_LAST;
+ effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+ &b->effect_defs);
#ifdef DEBUG
if(p->id == game.num_impr_types-1) {
@@ -2270,7 +2433,7 @@
b->spec_gate[inx], get_special_name(b->spec_gate[inx]));
}
freelog(LOG_DEBUG, " equiv_range %2d/%s",
- b->equiv_range, effect_range_name(b->equiv_range));
+ b->equiv_range, impr_range_name(b->equiv_range));
freelog(LOG_DEBUG, " equiv_dupl...");
for (inx = 0; b->equiv_dupl[inx] != B_LAST; inx++) {
freelog(LOG_DEBUG, " %2d/%s",
@@ -2291,78 +2454,9 @@
freelog(LOG_DEBUG, " build_cost %3d", b->build_cost);
freelog(LOG_DEBUG, " upkeep %2d", b->upkeep);
freelog(LOG_DEBUG, " sabotage %3d", b->sabotage);
- freelog(LOG_DEBUG, " effect...");
- for (inx = 0; b->effect[inx].type != EFT_LAST; inx++) {
- char buf[1024], *ptr;
- ptr = buf;
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " %d/%s",
- b->effect[inx].type,
- effect_type_name(b->effect[inx].type));
- ptr = strchr(ptr, '\0');
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " range=%d/%s",
- b->effect[inx].range,
- effect_range_name(b->effect[inx].range));
- ptr = strchr(ptr, '\0');
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " amount=%d",
- b->effect[inx].amount);
- ptr = strchr(ptr, '\0');
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " survives=%d",
- b->effect[inx].survives);
- ptr = strchr(ptr, '\0');
- freelog(LOG_DEBUG, " %2d. %s", inx, buf);
- ptr = buf;
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_bldg=%d/%s",
- b->effect[inx].cond_bldg,
- (b->effect[inx].cond_bldg == B_LAST) ?
- "Uncond." :
- improvement_types[b->effect[inx].cond_bldg].name);
- ptr = strchr(ptr, '\0');
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_gov=%d/%s",
- b->effect[inx].cond_gov,
- (b->effect[inx].cond_gov == game.government_count) ?
- "Uncond." :
- get_government_name(b->effect[inx].cond_gov));
- ptr = strchr(ptr, '\0');
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_adv=%d/%s",
- b->effect[inx].cond_adv,
- (b->effect[inx].cond_adv == A_NONE) ?
- "Uncond." :
- (b->effect[inx].cond_adv == A_LAST) ?
- "Never" :
- advances[b->effect[inx].cond_adv].name);
- ptr = strchr(ptr, '\0');
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_eff=%d/%s",
- b->effect[inx].cond_eff,
- (b->effect[inx].cond_eff == EFT_LAST) ?
- "Uncond." :
- effect_type_name(b->effect[inx].cond_eff));
- ptr = strchr(ptr, '\0');
- freelog(LOG_DEBUG, " %s", buf);
- ptr = buf;
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_unit=%d/%s",
- b->effect[inx].aff_unit,
- (b->effect[inx].aff_unit == UCL_LAST) ?
- "All" :
- unit_class_name(b->effect[inx].aff_unit));
- ptr = strchr(ptr, '\0');
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_terr=%d/%s",
- b->effect[inx].aff_terr,
- (b->effect[inx].aff_terr == T_LAST) ?
- "None" :
- (b->effect[inx].aff_terr == T_UNKNOWN) ?
- "All" :
- get_terrain_name(b->effect[inx].aff_terr));
- ptr = strchr(ptr, '\0');
- my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_spec=%04X/%s",
- b->effect[inx].aff_spec,
- (b->effect[inx].aff_spec == 0) ?
- "None" :
- (b->effect[inx].aff_spec == S_ALL) ?
- "All" :
- get_special_name(b->effect[inx].aff_spec));
- ptr = strchr(ptr, '\0');
- freelog(LOG_DEBUG, " %s", buf);
- }
+
+ print_effect_definitions(&b->effect_defs, " effect...");
+
freelog(LOG_DEBUG, " variant %2d", b->variant); /* FIXME:
remove when gen-impr obsoletes */
freelog(LOG_DEBUG, " helptext %s", b->helptext);
} impr_type_iterate_end;
@@ -2451,6 +2545,14 @@
gov->helptext = mystrdup(p->helptext);
+ effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+ &gov->effect_defs);
+
+#ifdef DEBUG
+ freelog(LOG_DEBUG, "%s", gov->name);
+ print_effect_definitions(&gov->effect_defs, " effect...");
+#endif
+
tilespec_setup_government(p->id);
}
@@ -2586,6 +2688,14 @@
}
pl->city_style = p->city_style;
+ effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+ &pl->effect_defs);
+
+#ifdef DEBUG
+ freelog(LOG_DEBUG, "%s", pl->name);
+ print_effect_definitions(&pl->effect_defs, " effect...");
+#endif
+
if (p->class[0] != '\0') {
pl->class = mystrdup(p->class);
} else {
diff -Nur -Xcvs/diff_ignore snap-pre/client/packhand_gen.c
snap-eff/client/packhand_gen.c
--- snap-pre/client/packhand_gen.c 2004-02-22 11:12:02.000000000 -0600
+++ snap-eff/client/packhand_gen.c 2004-03-05 20:55:17.000000000 -0600
@@ -298,6 +298,13 @@
handle_ruleset_control(packet);
return TRUE;
+ case PACKET_GLOBAL_EFFECT:
+ handle_global_effect(
+ ((struct packet_global_effect *)packet)->add_effect,
+ ((struct packet_global_effect *)packet)->player,
+ ((struct packet_global_effect *)packet)->effect_def);
+ return TRUE;
+
default:
return FALSE;
}
diff -Nur -Xcvs/diff_ignore snap-pre/client/packhand_gen.h
snap-eff/client/packhand_gen.h
--- snap-pre/client/packhand_gen.h 2004-02-22 11:12:02.000000000 -0600
+++ snap-eff/client/packhand_gen.h 2004-03-05 20:55:17.000000000 -0600
@@ -92,5 +92,6 @@
void handle_ruleset_terrain(struct packet_ruleset_terrain *packet);
struct packet_ruleset_control;
void handle_ruleset_control(struct packet_ruleset_control *packet);
+void handle_global_effect(bool add_effect, int player, struct effect_defn
*effect_def);
#endif /* FC__PACKHAND_GEN_H */
diff -Nur -Xcvs/diff_ignore snap-pre/common/capstr.c snap-eff/common/capstr.c
--- snap-pre/common/capstr.c 2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/capstr.c 2004-03-05 20:45:56.000000000 -0600
@@ -76,7 +76,7 @@
#define CAPABILITY "+1.14.delta +last_turns_shield_surplus veteran +orders " \
"+starter +union +iso_maps +orders2client " \
- "+change_production +tilespec1 +no_earth"
+ "+change_production +tilespec1 +no_earth +effects"
/* "+1.14.delta" is the new delta protocol for 1.14.0-dev.
*
@@ -102,6 +102,8 @@
*
* "no_earth" means that the map.is_earth value is gone; replaced by
* ptile->spec_sprite
+ *
+ * "effects" sends appropriate effect info to clients.
*/
void init_our_capability(void)
diff -Nur -Xcvs/diff_ignore snap-pre/common/city.c snap-eff/common/city.c
--- snap-pre/common/city.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/city.c 2004-03-05 20:46:34.000000000 -0600
@@ -18,6 +18,7 @@
#include <assert.h>
#include <string.h>
+#include "effects.h"
#include "fcintl.h"
#include "game.h"
#include "government.h"
@@ -466,10 +467,11 @@
**************************************************************************/
bool city_got_building(struct city *pcity, Impr_Type_id id)
{
- if (!improvement_exists(id))
+ if (!improvement_exists(id)) {
return FALSE;
- else
+ } else {
return (pcity->improvements[id] != I_NONE);
+ }
}
/**************************************************************************
@@ -2426,7 +2428,8 @@
arrays if the improvement has effects and/or an equiv_range that
extend outside of the city.
**************************************************************************/
-void city_add_improvement(struct city *pcity, Impr_Type_id impr)
+void city_add_improvement(struct city *pcity, Impr_Type_id impr,
+ bool add_immed_effects)
{
struct player *pplayer = city_owner(pcity);
@@ -2439,6 +2442,7 @@
improvements_update_redundant(pplayer, pcity,
map_get_continent(pcity->x, pcity->y),
improvement_types[impr].equiv_range);
+ add_improvement_effects(pcity, impr, add_immed_effects);
}
/**************************************************************************
@@ -2452,12 +2456,19 @@
freelog(LOG_DEBUG,"Improvement %s removed from city %s",
improvement_types[impr].name, pcity->name);
-
+
mark_improvement(pcity, impr, I_NONE);
+ /* some improvements may stop being redundant. */
improvements_update_redundant(pplayer, pcity,
map_get_continent(pcity->x, pcity->y),
improvement_types[impr].equiv_range);
+
+ /* delete all of these improvement's effects */
+ delete_effects(EFC_IMPROVEMENT, NULL, pcity, NULL, impr);
+
+ freelog(LOG_VERBOSE, "%%%%%%%%: removing improvement"); /* DEBUGGING/REMOVE
*/
+ effects_update_all();
}
/**************************************************************************
@@ -2565,6 +2576,10 @@
pcity->did_sell = FALSE;
pcity->airlift = FALSE;
+ /* Initialise city's vector of improvement effects. */
+ effect_vector_init(&pcity->effects);
+ effect_vector_init(&pcity->impr_effects);
+
pcity->turn_last_built = game.year;
pcity->changed_from_id = 0;
pcity->changed_from_is_unit = FALSE;
@@ -2605,6 +2620,10 @@
**************************************************************************/
void remove_city_virtual(struct city *pcity)
{
+ /* free the effect structures */
+ effect_vector_free(&pcity->effects);
+ effect_vector_free(&pcity->impr_effects);
+
unit_list_unlink_all(&pcity->units_supported);
free(pcity);
}
diff -Nur -Xcvs/diff_ignore snap-pre/common/city.h snap-eff/common/city.h
--- snap-pre/common/city.h 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/city.h 2004-03-05 20:44:46.000000000 -0600
@@ -16,6 +16,7 @@
#include "improvement.h"
#include "unit.h" /* struct unit_list */
#include "worklist.h"
+#include "effects.h"
struct player;
struct government;
@@ -250,6 +251,8 @@
int currently_building;
Impr_Status improvements[B_LAST];
+ struct effect_vector effects;
+ struct effect_vector impr_effects; /* houses all local impr effects */
struct worklist worklist;
@@ -456,7 +459,8 @@
/* granary size as a function of city size */
int city_granary_size(int city_size);
-void city_add_improvement(struct city *pcity,Impr_Type_id impr);
+void city_add_improvement(struct city *pcity,Impr_Type_id impr,
+ bool add_immed_effects);
void city_remove_improvement(struct city *pcity,Impr_Type_id impr);
/* city update functions */
@@ -490,7 +494,7 @@
*/
#define built_impr_iterate(m_pcity, m_i) \
impr_type_iterate(m_i) { \
- if((m_pcity)->improvements[m_i] == I_NONE) { \
+ if ((m_pcity)->improvements[m_i] == I_NONE) { \
continue; \
}
diff -Nur -Xcvs/diff_ignore snap-pre/common/dataio.c snap-eff/common/dataio.c
--- snap-pre/common/dataio.c 2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/dataio.c 2004-03-05 20:48:30.000000000 -0600
@@ -781,32 +781,39 @@
dio_put_uint8(dout, pds->has_reason_to_cancel);
}
-void dio_get_effect(struct data_in *din, struct impr_effect *peffect)
+void dio_get_effect_defn(struct data_in *din, struct effect_defn *defn)
{
- dio_get_uint8(din, (int *) &(peffect->type));
- dio_get_uint8(din, (int *) &(peffect->range));
- dio_get_sint16(din, &peffect->amount);
- dio_get_uint8(din, &peffect->survives);
- dio_get_uint8(din, (int *) &peffect->cond_bldg);
- dio_get_uint8(din, &peffect->cond_gov);
- dio_get_uint8(din, &peffect->cond_adv);
- dio_get_uint8(din, (int *) &(peffect->cond_eff));
- dio_get_uint8(din, (int *) &(peffect->aff_unit));
- dio_get_uint8(din, (int *) &(peffect->aff_terr));
- dio_get_uint16(din, (int *) &(peffect->aff_spec));
+ dio_get_uint8(din, (int *) &defn->type);
+ dio_get_uint8(din, (int *) &defn->range);
+ dio_get_uint8(din, (int *) &defn->outside);
+ dio_get_sint16(din, (int *) &defn->amount);
+ dio_get_sint16(din, (int *) &defn->value1);
+ dio_get_sint16(din, (int *) &defn->value2);
+ dio_get_uint8(din, &defn->cond_bldg);
+ dio_get_uint32(din, &defn->cond_nat);
+ dio_get_uint8(din, &defn->cond_gov);
+ dio_get_uint8(din, &defn->cond_adv);
+ dio_get_uint8(din, (int *) &defn->cond_eff);
+ dio_get_uint8(din, (int *) &defn->aff_unit);
+ dio_get_uint8(din, (int *) &defn->aff_terr);
+ dio_get_uint16(din, (int *) &defn->aff_spec);
}
-void dio_put_effect(struct data_out *dout, const struct impr_effect *peffect)
+void dio_put_effect_defn(struct data_out *dout,
+ const struct effect_defn *defn)
{
- dio_put_uint8(dout, peffect->type);
- dio_put_uint8(dout, peffect->range);
- dio_put_sint16(dout, peffect->amount);
- dio_put_uint8(dout, peffect->survives);
- dio_put_uint8(dout, peffect->cond_bldg);
- dio_put_uint8(dout, peffect->cond_gov);
- dio_put_uint8(dout, peffect->cond_adv);
- dio_put_uint8(dout, peffect->cond_eff);
- dio_put_uint8(dout, peffect->aff_unit);
- dio_put_uint8(dout, peffect->aff_terr);
- dio_put_uint16(dout, peffect->aff_spec);
+ dio_put_uint8(dout, defn->type);
+ dio_put_uint8(dout, defn->range);
+ dio_put_uint8(dout, defn->outside);
+ dio_put_sint16(dout, defn->amount);
+ dio_put_sint16(dout, defn->value1);
+ dio_put_sint16(dout, defn->value2);
+ dio_put_uint8(dout, defn->cond_bldg);
+ dio_put_uint32(dout, defn->cond_nat);
+ dio_put_uint8(dout, defn->cond_gov);
+ dio_put_uint8(dout, defn->cond_adv);
+ dio_put_uint8(dout, defn->cond_eff);
+ dio_put_uint8(dout, defn->aff_unit);
+ dio_put_uint8(dout, defn->aff_terr);
+ dio_put_uint16(dout, defn->aff_spec);
}
diff -Nur -Xcvs/diff_ignore snap-pre/common/dataio.h snap-eff/common/dataio.h
--- snap-pre/common/dataio.h 2003-12-14 18:20:46.000000000 -0600
+++ snap-eff/common/dataio.h 2004-03-05 20:44:46.000000000 -0600
@@ -17,7 +17,7 @@
struct worklist;
struct player_diplstate;
-struct impr_effect;
+struct effect_defn;
struct data_in {
const void *src;
@@ -71,7 +71,7 @@
void dio_get_tech_list(struct data_in *din, int *dest);
void dio_get_worklist(struct data_in *din, struct worklist *pwl);
void dio_get_diplstate(struct data_in *din, struct player_diplstate *pds);
-void dio_get_effect(struct data_in *din, struct impr_effect *peffect);
+void dio_get_effect_defn(struct data_in *din, struct effect_defn *defn);
void dio_get_uint8_vec8(struct data_in *din, int **values, int stop_value);
void dio_get_uint16_vec8(struct data_in *din, int **values, int stop_value);
@@ -100,8 +100,8 @@
void dio_put_worklist(struct data_out *dout, const struct worklist *pwl);
void dio_put_diplstate(struct data_out *dout,
const struct player_diplstate *pds);
-void dio_put_effect(struct data_out *dout,
- const struct impr_effect *peffect);
+void dio_put_effect_defn(struct data_out *dout,
+ const struct effect_defn * defn);
void dio_put_uint8_vec8(struct data_out *dout, int *values, int stop_value);
void dio_put_uint16_vec8(struct data_out *dout, int *values, int stop_value);
diff -Nur -Xcvs/diff_ignore snap-pre/common/effects.c snap-eff/common/effects.c
--- snap-pre/common/effects.c 2003-12-14 18:20:46.000000000 -0600
+++ snap-eff/common/effects.c 2004-03-07 12:03:32.000000000 -0600
@@ -21,6 +21,7 @@
#include "game.h"
#include "government.h"
#include "improvement.h"
+#include "log.h"
#include "map.h"
#include "mem.h"
#include "support.h"
@@ -125,9 +126,82 @@
"Upgrade_One_Leap",
"Upgrade_All_Step",
"Upgrade_All_Leap",
- "Upkeep_Free"
+ "Upkeep_Free",
+ "Unit_Add_To_City",
+ "Unit_AEGIS",
+ "Unit_Airbase",
+ "Unit_Carrier",
+ "Unit_Cities",
+ "Unit_Diplomat",
+ "Unit_Fanatic",
+ "Unit_Field_Unit",
+ "Unit_Fighter",
+ "Unit_Game_Loss",
+ "Unit_Help_Wonder",
+ "Unit_Horse",
+ "Unit_Ignore_Terrain",
+ "Unit_Ignore_Tired",
+ "Unit_Ignore_Walls",
+ "Unit_Ignore_ZOC",
+ "Unit_Marines",
+ "Unit_Missile",
+ "Unit_Missile_Carrier",
+ "Unit_No_Home",
+ "Unit_No_Land_Attack",
+ "Unit_Nonmilitary",
+ "Unit_Nuclear",
+ "Unit_One_Attack",
+ "Unit_Paratroopers",
+ "Unit_Partial_Invisible",
+ "Unit_Pikemen",
+ "Unit_Settlers",
+ "Unit_Spy",
+ "Unit_Trade_Route",
+ "Unit_Transform",
+ "Unit_Trireme",
+ "Unit_Unbribable",
+ "Unit_Undisbandable",
+ "Unit_Super_Spy",
+ "Unit_Unique"
};
+/* get 'struct effect_defn_vector' functions: */
+#define SPECVEC_TAG effect_defn
+#define SPECVEC_TYPE struct effect_defn
+#include "specvec_c.h"
+
+/* get 'struct effect_vector' functions: */
+#define SPECVEC_TAG effect
+#define SPECVEC_TYPE struct effect
+#include "specvec_c.h"
+
+/* does what it says if set */
+static bool defer_effects_update;
+
+/* effects update helpers */
+static void cache_effect(struct effect *eff);
+static bool effects_update_caches(void);
+static bool check_for_conditional_effect(struct effect *eff);
+
+/**************************************************************************
+ These effects are resolved immediately after being added to the effects
+ list and then removed.
+**************************************************************************/
+bool is_immediate_effect(struct effect_defn *defn)
+{
+ switch (defn->type) {
+ case EFT_GIVE_IMM_ADV:
+ case EFT_IMPROVE_REP:
+ case EFT_REVEAL_CITIES: /* this could be a continuing effect, anyone? */
+ case EFT_REVEAL_MAP:
+ case EFT_ENABLE_NUKE: /* these two effects are only immediate in that */
+ case EFT_ENABLE_SPACE: /* they flip bits which stay around */
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
/**************************************************************************
Convert effect range names to enum; case insensitive;
returns EFR_LAST if can't match.
@@ -197,20 +271,971 @@
/**************************************************************************
Return TRUE iff the two effects are equal.
**************************************************************************/
-bool are_effects_equal(const struct impr_effect *const peff1,
- const struct impr_effect *const peff2)
+bool are_effect_defns_equal(const struct effect_defn *const peff1,
+ const struct effect_defn *const peff2)
{
-#define T(name) if(peff1->name!=peff2->name) return FALSE;
+#define T(name) if(peff1->name != peff2->name) return FALSE;
T(type);
T(range);
+ T(outside);
T(amount);
- T(survives);
- T(cond_bldg);
+ T(value1);
+ T(value2);
+
+ T(cond_nat);
T(cond_gov);
T(cond_adv);
+ T(cond_bldg);
T(cond_eff);
+
T(aff_unit);
T(aff_terr);
T(aff_spec);
return TRUE;
+#undef T
+}
+
+/*******************************************************************
+ if pcity is NULL or the effect is active anyway, return active or pending.
+ If pcity is non-NULL, check for the appropriate cond_bldg.
+********************************************************************/
+bool is_effect_emitting(struct effect *eff, struct city *pcity)
+{
+ if (!pcity || eff->has.active) {
+ return eff->has.active || eff->has.pending;
+ } else if (eff->has.pending) {
+ return city_got_building(pcity, eff->defn->cond_bldg);
+ } else {
+ return FALSE; /* effect not even pending a cond_bldg */
+ }
+}
+
+/******************************************************************
+ if pcity is non-NULL, global, player, and island ranges will return for
+ their effect in that city and city and local ranges will be check in that
+ city only.
+ if id is not B_LAST, then all of the above applies and only id's effects in
+ the city are iterated through. If id is specified, pcity must also be.
+
+*******************************************************************/
+void effect_iterator_init(struct effect_iter *iter, struct player *pplayer,
+ struct city *pcity, struct unit *punit,
+ int id, enum effect_type type)
+{
+ assert(!(pcity && !pplayer)); /* can't have a city without a player */
+ assert((id != B_ALL && pcity) || id == B_ALL); /* need city with impr */
+
+ iter->type = type;
+ iter->player = pplayer;
+ iter->city = pcity;
+ iter->unit = punit;
+ iter->id = id;
+
+ iter->range = (punit) ? EFR_LOCAL : EFR_WORLD;
+
+ iter->end_range = EFR_WORLD;
+
+ if (pplayer) {
+ iter->end_range = EFR_PLAYER;
+ }
+ if (pcity) {
+ iter->end_range = EFR_CITY;
+ }
+ if (punit || id != B_ALL) {
+ iter->end_range = EFR_LOCAL;
+ }
+
+ iter->pos = 0;
+}
+
+/*******************************************************************
+ iterates through a particular range of effects returning the first one
+ that matches type and is active. If type is EFT_LAST, return all active
+ effects.
+
+ this function will pick up where it left off if you input the iter
+ used before. see the city_effects_iterate() macro in effects.h for usage.
+********************************************************************/
+struct effect *effect_iterator_get_next_active(struct effect_iter *iter)
+{
+ unsigned short cont;
+ struct effect *eff = NULL;
+
+#define CHECK_LIST(effect_vector, _pcity, _id) \
+ for ( ; iter->pos < effect_vector_size(&(effect_vector)); iter->pos++) { \
+ eff = effect_vector_get(&(effect_vector), iter->pos); \
+ \
+ if ((eff->defn->type == iter->type || iter->type == EFT_ALL) \
+ && is_effect_emitting(eff, (_pcity)) \
+ && ((_id) == B_ALL || (_id) == eff->id)) { \
+ iter->pos++; \
+ return eff; \
+ } \
+ } \
+ iter->pos = 0;
+
+ while(iter->range >= iter->end_range) {
+ switch (iter->range) {
+ case EFR_WORLD:
+ CHECK_LIST(game.effects, iter->city, B_ALL);
+ break;
+ case EFR_PLAYER:
+ CHECK_LIST(iter->player->effects, iter->city, B_ALL);
+ break;
+ case EFR_ISLAND:
+ cont = map_get_continent(iter->city->x, iter->city->y);
+ CHECK_LIST(iter->player->island_effects[cont], iter->city, B_ALL);
+ break;
+ case EFR_CITY:
+ CHECK_LIST(iter->city->effects, NULL, B_ALL); /* cond_bldg cached */
+ break;
+ case EFR_LOCAL:
+ if (iter->unit) {
+ /* nothing yet */
+ } else {
+ CHECK_LIST(iter->city->impr_effects, NULL, iter->id);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (iter->range == EFR_LOCAL) {
+ break;
+ } else {
+ iter->range--;
+ }
+ }
+
+ return NULL;
+
+#undef CHECK_LIST
+}
+
+/*******************************************************************
+ if set, effects_update_all will do nothing until until
+ effects_undefer_update is called. these are used in savegame.c
+********************************************************************/
+void effects_defer_update(void)
+{
+ defer_effects_update = TRUE;
+}
+
+/*******************************************************************
+ allows effects_update_all to function.
+********************************************************************/
+void effects_undefer_update(void)
+{
+ defer_effects_update = FALSE;
+}
+
+/*******************************************************************
+ iterate through all effects --- perhaps multiple times --- to activate
+ all effects. be all that you can be.
++
+ TODO: possibly there's an optimization to be make inside the cond_eff loop.
+ if there are no effects in game.effects with !eff->has_eff, then we
+ only need to loop within a player anytime there is a change rather
+ than over all players every time.
+********************************************************************/
+void effects_update_all_common(void)
+{
+ int i;
+ bool changed = TRUE;
+ bool needs_condeff;
+
+ if (defer_effects_update) {
+ return;
+ }
+
+ freelog(LOG_DEBUG, "updating all effects");
+
+ needs_condeff = effects_update_caches();
+
+ /* check for cond_eff and activate effects as necessary
+ * you don't want to even contemplate the worst-case scenario here ;) */
+ while(needs_condeff && changed) {
+ freelog(LOG_DEBUG, "effects_update_all: needed to loop for cond_eff");
+ changed = FALSE;
+
+ /* global effects */
+ effect_vector_iterate(game.effects, eff) {
+ changed = check_for_conditional_effect(eff);
+ } effect_vector_iterate_end;
+
+ players_iterate(pplayer) {
+ /* player effects */
+ effect_vector_iterate(pplayer->effects, eff) {
+ changed = check_for_conditional_effect(eff);
+ } effect_vector_iterate_end;
+
+ /* island effects */
+ for(i = 1; i <= map.num_continents; i++) {
+ effect_vector_iterate(pplayer->island_effects[i], eff) {
+ changed = check_for_conditional_effect(eff);
+ } effect_vector_iterate_end;
+ }
+
+ /* city effects */
+ city_list_iterate(pplayer->cities, pcity) {
+ effect_vector_iterate(pcity->effects, eff) {
+ changed = check_for_conditional_effect(eff);
+ } effect_vector_iterate_end;
+
+ /* local effects */
+ effect_vector_iterate(pcity->impr_effects, eff) {
+ changed = check_for_conditional_effect(eff);
+ } effect_vector_iterate_end;
+ } city_list_iterate_end;
+ } players_iterate_end;
+ }
+}
+
+/*******************************************************************
+ caches as many of the requirements of an effect as we possibly can
+ since if we have to loop for cond_eff, we don't want to recalculate
+ these each time.
+********************************************************************/
+static void cache_effect(struct effect *eff)
+{
+ /* store this for later comparison */
+ eff->has.changed = 0;
+ eff->has.was_active = (eff->has.active || eff->has.pending);
+
+ eff->has.nat = (eff->defn->cond_nat == -1
+ || eff->defn->cond_nat == eff->plr->nation);
+
+#undef BIGDEBUG /* FIXME: delete all BIGDEBUGs before commit. */
+#define BIGDEBUG /* FIXME: delete all BIGDEBUGs before commit. */
+
+#ifdef BIGDEBUG
+ if (!eff->has.nat) {
+ freelog(LOG_DEBUG,
+ "cache_effect: (no req. nat) p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+ }
+#endif
+ eff->has.adv = (eff->defn->cond_adv == A_NONE
+ || get_invention(eff->plr,
+ eff->defn->cond_adv) == TECH_KNOWN);
+#ifdef BIGDEBUG
+ if (!eff->has.adv) {
+ freelog(LOG_DEBUG,
+ "cache_effect: (no req. adv) p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+ }
+#endif
+ eff->has.gov = (eff->defn->cond_gov == game.government_count
+ || eff->defn->cond_gov == eff->plr->government);
+
+ if (!eff->has.gov) {
+ freelog(LOG_DEBUG,
+ "cache_effect: (no req. gov) p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+ }
+
+ /* this depends on the city we're looking at, can't fully cache
+ * except if the effect's range is city or less. */
+ /* the || should protect eff->home from being evaluated if NULL ??? */
+ eff->has.bldg = (eff->defn->cond_bldg == B_LAST
+ || (eff->defn->range < EFR_ISLAND
+ && city_got_building(eff->home, eff->defn->cond_bldg)));
+
+#ifdef BIGDEBUG
+ if (!eff->has.bldg) {
+ freelog(LOG_DEBUG,
+ "cache_effect: (no bldg) p: %s c: %s i: %d r: %s n: %s"
+ "\n\t\t\t bldg: %s s:%d e:%d",
+ eff->plr->name, (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type),
+ get_improvement_name(eff->defn->cond_bldg),
+ eff->home->improvements[eff->defn->cond_bldg],
+ improvement_exists(eff->defn->cond_bldg));
+ }
+#endif
+
+ /* redundant buildings have their effects suppressed */
+ if (eff->home) {
+ eff->has.no_equiv = (eff->home->improvements[eff->id] != I_REDUNDANT);
+ } else {
+ eff->has.no_equiv = TRUE;
+ }
+
+#ifdef BIGDEBUG
+ if (!eff->has.no_equiv) {
+ freelog(LOG_DEBUG,
+ "cache_effect: (sup. by equiv) p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+ }
+#endif
+
+ /* requires multiple passes, can't fully cache */
+ eff->has.condeff = (eff->defn->cond_eff == EFT_LAST);
+
+#ifdef BIGDEBUG
+ if (!eff->has.condeff) {
+ freelog(LOG_DEBUG,
+ "cache_effect: (no req. cond_eff) p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+ }
+#endif
+
+ eff->has.pending = eff->has.nat && eff->has.gov && eff->has.adv
+ && eff->has.no_equiv && eff->has.condeff;
+ eff->has.active = eff->has.pending && eff->has.bldg;
+
+#ifdef BIGDEBUG
+ if (eff->has.pending && !eff->has.active) {
+ freelog(LOG_DEBUG,
+ "cache_effect: (pending) p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+ }
+
+ if (eff->has.active) {
+ freelog(LOG_DEBUG,
+ "cache_effect: (active) p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+ }
+#endif
+
+ eff->has.changed = eff->has.was_active ^
+ (eff->has.active || eff->has.pending);
+}
+
+/*******************************************************************
+ cache each effect for everything except for conditional effects and
+ buildings.
+
+ return TRUE if any of the effects have a cond_eff.
+********************************************************************/
+static bool effects_update_caches(void)
+{
+ int i;
+ bool condeff_flag = FALSE;
+
+ /* global effects */
+ effect_vector_iterate(game.effects, eff) {
+ cache_effect(eff);
+ condeff_flag |= !eff->has.condeff;
+ } effect_vector_iterate_end;
+
+ players_iterate(pplayer) {
+ /* player effects */
+ effect_vector_iterate(pplayer->effects, eff) {
+ cache_effect(eff);
+ condeff_flag |= !eff->has.condeff;
+ } effect_vector_iterate_end;
+
+ /* island effects */
+ for(i = 1; i <= map.num_continents; i++) {
+ effect_vector_iterate(pplayer->island_effects[i], eff) {
+ cache_effect(eff);
+ condeff_flag |= !eff->has.condeff;
+ } effect_vector_iterate_end;
+ }
+
+ /* city effects */
+ city_list_iterate(pplayer->cities, pcity) {
+ effect_vector_iterate(pcity->effects, eff) {
+ cache_effect(eff);
+ condeff_flag |= !eff->has.condeff;
+ } effect_vector_iterate_end;
+
+ /* local impr effects */
+ effect_vector_iterate(pcity->impr_effects, eff) {
+ cache_effect(eff);
+ condeff_flag |= !eff->has.condeff;
+ } effect_vector_iterate_end;
+ } city_list_iterate_end;
+ } players_iterate_end;
+
+ return condeff_flag;
+}
+
+/*******************************************************************
+ does a complete check for prerequisite effects for eff
+ if we find an active effect that satisfies cond_eff, then we activate the
+ eff or set its pending status and then return TRUE (so we stop after the
+ first positive result)
+
+ remember that the origin of the effect (the improvement generating it)
+ must be within the range of the cond_eff.
+
+ N.B. Depending on the cond_eff dependencies of future popular mod-packs,
+ these checks might be rearranged to get a faster hit.
+********************************************************************/
+static bool check_for_conditional_effect(struct effect *eff)
+{
+ int cont;
+
+#define CHECK_CONDEFF(eff, eff2) \
+ if ((eff)->defn->cond_eff == (eff2)->defn->type \
+ && is_effect_emitting((eff2), (eff)->home)) { \
+ if (eff->has.bldg) { \
+ (eff)->has.active = TRUE; \
+ } else { \
+ (eff)->has.pending = TRUE; \
+ } \
+ \
+ eff->has.changed = eff->has.was_active ^ \
+ (eff->has.active || eff->has.pending); \
+ \
+ freelog(LOG_DEBUG, "effects: (cond eff found) " \
+ "p: %s c: %s i: %d r: %s n: %s", \
+ eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", \
+ eff->id, effect_range_name(eff->defn->range), \
+ effect_type_name(eff->defn->type)); \
+ \
+ return TRUE; \
+ }
+
+ /* FIXME: this is buggy I think, or at the least needs optimization */
+ /* if there is no cond_eff and all other prereqs are there, continue */
+ if (eff->has.pending || !eff->home
+ || !(eff->has.nat && eff->has.gov && eff->has.adv)) {
+ return FALSE;
+ }
+
+ /* does any global cond_eff affect eff's origin? */
+ effect_vector_iterate(game.effects, eff2) {
+ CHECK_CONDEFF(eff, eff2);
+ } effect_vector_iterate_end;
+
+ /* does any player-wide cond_eff affect eff's origin? */
+ effect_vector_iterate(eff->plr->effects, eff2) {
+ CHECK_CONDEFF(eff, eff2);
+ } effect_vector_iterate_end;
+
+ /* homeless? */
+ if (!eff->home) {
+ return FALSE;
+ }
+
+ /* does any island-wide cond_eff affect eff's origin? */
+ cont = map_get_continent(eff->home->x, eff->home->y);
+
+ effect_vector_iterate(eff->plr->island_effects[cont], eff2) {
+ CHECK_CONDEFF(eff, eff2);
+ } effect_vector_iterate_end;
+
+ /* does any city-wide cond_eff affect eff's origin? */
+ effect_vector_iterate(eff->home->effects, eff2) {
+ CHECK_CONDEFF(eff, eff2);
+ } effect_vector_iterate_end;
+
+ /* does any local cond_eff affect eff's origin? */
+ effect_vector_iterate(eff->home->impr_effects, eff2) {
+ if (eff->id == eff2->id) {
+ CHECK_CONDEFF(eff, eff2);
+ }
+ } effect_vector_iterate_end;
+
+ /* no hits */
+ return FALSE;
+
+#undef CHECK_CONDEFF
+}
+
+/*******************************************************************
+ return a struct effect from the end of the proper vector, extending
+ the vector if necessary
+********************************************************************/
+struct effect *append_effect(struct player *pplayer, struct city *home,
+ struct unit *punit, enum effect_range range)
+{
+ int n, cont;
+
+#define RETURN_NEW_EFFECT(_vec) \
+ n = effect_vector_size(&(_vec)); \
+ effect_vector_reserve(&(_vec), n + 1); \
+ return effect_vector_get(&(_vec), n);
+
+ /* range is always EFR_LOCAL */
+ if (punit) {
+ RETURN_NEW_EFFECT(punit->effects);
+ }
+
+ switch(range) {
+ case EFR_WORLD:
+ RETURN_NEW_EFFECT(game.effects);
+ case EFR_PLAYER:
+ RETURN_NEW_EFFECT(pplayer->effects);
+ case EFR_ISLAND:
+ cont = map_get_continent(home->x, home->y);
+ RETURN_NEW_EFFECT(pplayer->island_effects[cont]);
+ case EFR_CITY:
+ RETURN_NEW_EFFECT(home->effects);
+ case EFR_LOCAL:
+ RETURN_NEW_EFFECT(home->impr_effects);
+ default:
+ assert(0);
+ return NULL;
+ }
+
+#undef RETURN_NEW_EFFECT
+}
+
+/*******************************************************************
+ add effect_vector from a nation
+********************************************************************/
+void add_nation_effects(struct player *pplayer, bool add_immed_effects)
+{
+ bool need_update = FALSE;
+
+ effect_defn_vector_iterate(get_nation_by_plr(pplayer)->effect_defs, defn) {
+ struct effect *eff;
+
+ if (!add_immed_effects && is_immediate_effect(defn)) {
+ continue;
+ }
+
+ eff = append_effect(pplayer, NULL, NULL, defn->range);
+
+ eff->plr = pplayer;
+ eff->home = NULL;
+ eff->unit = NULL;
+ eff->id = pplayer->nation;
+ eff->defn = defn;
+ eff->has.active = eff->has.pending = 0;
+
+ freelog(LOG_DEBUG, "added effect p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+
+ need_update = TRUE;
+ } effect_defn_vector_iterate_end;
+
+ freelog(LOG_VERBOSE, "%%%%%%%%: add nation effects"); /* DEBUGGING/REMOVE */
+ if (need_update) {
+ effects_update_all();
+ }
+}
+
+/*******************************************************************
+ add effect_vector from an tech
+********************************************************************/
+void add_tech_effects(struct player *pplayer, int id, bool add_immed_effects)
+{
+ bool need_update = FALSE;
+
+ /* kludge: A_FUTURE can't yet have effects! :( */
+ if (id == A_FUTURE) {
+ return;
+ }
+
+ effect_defn_vector_iterate(advances[id].effect_defs, defn) {
+ struct effect *eff;
+
+ if (!add_immed_effects && is_immediate_effect(defn)) {
+ continue;
+ }
+
+ eff = append_effect(pplayer, NULL, NULL, defn->range);
+
+ eff->plr = pplayer;
+ eff->home = NULL;
+ eff->unit = NULL;
+ eff->id = id;
+ eff->defn = defn;
+ eff->has.active = eff->has.pending = 0;
+
+ freelog(LOG_DEBUG, "added effect p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+
+ need_update = TRUE;
+ } effect_defn_vector_iterate_end;
+
+
+ freelog(LOG_VERBOSE, "%%%%%%%%: add tech effects"); /* DEBUGGING/REMOVE */
+ if (need_update) {
+ effects_update_all();
+ }
+}
+
+/*******************************************************************
+ add effect_vector from a government
+********************************************************************/
+void add_government_effects(struct player *pplayer, bool add_immed_effects)
+{
+ bool need_update = FALSE;
+
+ effect_defn_vector_iterate(governments[pplayer->government].effect_defs,
+ defn) {
+ struct effect *eff;
+
+ if (!add_immed_effects && is_immediate_effect(defn)) {
+ continue;
+ }
+
+ eff = append_effect(pplayer, NULL, NULL, defn->range);
+
+ eff->plr = pplayer;
+ eff->home = NULL;
+ eff->unit = NULL;
+ eff->id = pplayer->government;
+ eff->defn = defn;
+ eff->has.active = eff->has.pending = 0;
+
+ freelog(LOG_DEBUG, "added effect p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+
+ need_update = TRUE;
+ } effect_defn_vector_iterate_end;
+
+ freelog(LOG_VERBOSE, "%%%%%%%%: add gov effects"); /* DEBUGGING/REMOVE */
+ if (need_update) {
+ effects_update_all();
+ }
+}
+
+/*******************************************************************
+ add effect_vector from an improvement
+********************************************************************/
+void add_improvement_effects(struct city *pcity, int id, bool
add_immed_effects)
+{
+ bool need_update = FALSE;
+
+ effect_defn_vector_iterate(improvement_types[id].effect_defs, defn) {
+ struct effect *eff;
+ struct player *pplayer = city_owner(pcity);
+
+ if (!add_immed_effects && is_immediate_effect(defn)) {
+ continue;
+ }
+
+ eff = append_effect(pplayer, pcity, NULL, defn->range);
+
+ eff->plr = pplayer;
+ eff->home = pcity;
+ eff->unit = NULL;
+ eff->id = id;
+ eff->defn = defn;
+ eff->has.active = eff->has.pending = 0;
+
+ freelog(LOG_DEBUG, "added effect p: %s c: %s i: %d r: %s n: %s",
+ eff->plr->name, eff->home->name,
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+
+ need_update = TRUE;
+
+ } effect_defn_vector_iterate_end;
+
+ freelog(LOG_VERBOSE, "%%%%%%%%: add improvement effects"); /*
DEBUGGING/REMOVE */
+ if (need_update) {
+ effects_update_all();
+ }
+}
+
+/*******************************************************************
+ add effect_vector for a unit
+********************************************************************/
+void add_unit_effects(struct unit *punit, bool add_immed_effects)
+{
+ bool need_update = FALSE;
+ Unit_Type_id type = punit->type;
+
+ effect_defn_vector_iterate(unit_types[type].effect_defs, defn) {
+ struct effect *eff;
+ struct player *pplayer = unit_owner(punit);
+
+ if (!add_immed_effects && is_immediate_effect(defn)) {
+ continue;
+ }
+
+ eff = append_effect(pplayer, NULL, punit, defn->range);
+
+ eff->plr = pplayer;
+ eff->home = NULL;
+ eff->unit = punit;
+ eff->id = type;
+ eff->defn = defn;
+ eff->has.active = eff->has.pending = 0;
+
+ freelog(LOG_DEBUG, "added effect p: %s u: %s i: %d r: %s n: %s",
+ eff->plr->name, unit_name(type),
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+
+ need_update = TRUE;
+
+ } effect_defn_vector_iterate_end;
+
+ freelog(LOG_VERBOSE, "%%%%%%%%: add unit effects"); /* DEBUGGING/REMOVE */
+
+ if (need_update) {
+ effects_update_all();
+ }
+}
+
+/*******************************************************************
+ called when the number of continents changes
+
+ for each player, we place all the Island-ranged effects from each
+ continent into a holding vector, resize pplayer->island_effects
+ and then reinsert the effects from the holding vector back into
+ the appropriate island_effects vector.
+********************************************************************/
+void allot_island_effects(void)
+{
+ int i, s, size = 0;
+ static unsigned short old_num_cont;
+ struct effect_vector holding;
+
+ freelog(LOG_DEBUG, "reallotting island effects old:%d cur:%d",
+ old_num_cont, map.num_continents);
+
+#define ADD_EFFECT(_vec, _eff) \
+ effect_vector_reserve(&(_vec), effect_vector_size(&(_vec)) + 1); \
+ memcpy(effect_vector_get(&(_vec), effect_vector_size(&(_vec)) - 1), \
+ (_eff), sizeof(struct effect));
+
+ players_iterate(pplayer) {
+ /* create a holding place for the effects */
+ effect_vector_init(&holding);
+
+ /* store all the island effects in a holding list */
+ for (i = 1; i <= old_num_cont; i++) {
+ size += effect_vector_size(&pplayer->island_effects[i]);
+ }
+ effect_vector_reserve(&holding, size);
+
+ for (s = 0, i = 1; i <= old_num_cont; i++) {
+ effect_vector_iterate(pplayer->island_effects[i], eff) {
+ memcpy(effect_vector_get(&holding, s++), eff, sizeof(struct effect));
+ } effect_vector_iterate_end;
+
+ effect_vector_free(&pplayer->island_effects[i]);
+ }
+
+ /* reallocate and init island lists */
+ pplayer->island_effects = fc_realloc(pplayer->island_effects,
+ (map.num_continents + 1)
+ * sizeof(struct effect_vector));
+
+ for (i = 1; i <= map.num_continents; i++) {
+ effect_vector_init(&pplayer->island_effects[i]);
+ }
+
+ /* reinsert */
+ effect_vector_iterate(holding, eff) {
+ int cont = map_get_continent(eff->home->x, eff->home->y);
+
+ ADD_EFFECT(pplayer->island_effects[cont], eff);
+ } effect_vector_iterate_end;
+
+
+ effect_vector_free(&holding);
+ } players_iterate_end;
+
+#undef ADD_EFFECT
+
+ /* save for next time around */
+ old_num_cont = map.num_continents;
+
+ effects_update_all();
+}
+
+/*******************************************************************
+ delete all effects specified by the nation's effect_defs
+********************************************************************/
+static void delete_nation_effects(struct player *pplayer, int id)
+{
+ /* player.c sets the default nation to this value. don't cause a core */
+ if (id == NO_NATION_SELECTED) {
+ return;
+ }
+
+ effect_defn_vector_iterate(get_nation_by_idx(id)->effect_defs, defn) {
+ delete_effect(pplayer, NULL, NULL, id, defn);
+ } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects specified by the tech's effect_defs
+********************************************************************/
+static void delete_tech_effects(struct player *pplayer, int id)
+{
+ /* kludge: A_FUTURE can't yet have effects! :( */
+ if (id == A_FUTURE) {
+ return;
+ }
+
+ effect_defn_vector_iterate(advances[id].effect_defs, defn) {
+ delete_effect(pplayer, NULL, NULL, id, defn);
+ } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects specified by the governments's effect_defs
+********************************************************************/
+static void delete_government_effects(struct player *pplayer, int id)
+{
+ /* game.c sets the default government to this value. */
+ if (id == G_MAGIC) {
+ return;
+ }
+
+ effect_defn_vector_iterate(governments[id].effect_defs, defn) {
+ delete_effect(pplayer, NULL, NULL, id, defn);
+ } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects specified by the improvment's effect_defs
+********************************************************************/
+static void delete_improvement_effects(struct city *pcity, int id)
+{
+ effect_defn_vector_iterate(improvement_types[id].effect_defs, defn) {
+ delete_effect(city_owner(pcity), pcity, NULL, id, defn);
+ } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects specified by the unit's effect_defs
+********************************************************************/
+static void delete_unit_effects(struct unit *punit)
+{
+ effect_defn_vector_iterate(unit_type(punit)->effect_defs, defn) {
+ delete_effect(unit_owner(punit), NULL, punit, -1, defn);
+ } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects for a particular effect_defn_vector
+********************************************************************/
+void delete_effects_common(enum effect_class class, struct player *pplayer,
+ struct city *pcity, struct unit *punit, int id)
+{
+ switch (class) {
+ case EFC_UNIT:
+ delete_unit_effects(punit);
+ break;
+ case EFC_IMPROVEMENT:
+ delete_improvement_effects(pcity, id);
+ break;
+ case EFC_TECH:
+ delete_tech_effects(pplayer, id);
+ break;
+ case EFC_GOVERNMENT:
+ delete_government_effects(pplayer, id);
+ break;
+ case EFC_NATION:
+ delete_nation_effects(pplayer, id);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+/*******************************************************************
+ remove an effect (via its definition) from its vector.
+ this will delete all such effects that match the parameters given.
+
+ you need to update all effects manually after this.
+********************************************************************/
+void delete_effect(struct player *pplayer, struct city *pcity,
+ struct unit *punit, int id, struct effect_defn *defn)
+{
+
+#define SEARCH_LIST_AND_DEL(eff_list) \
+{ \
+ int i = 0, size = effect_vector_size(&(eff_list)); \
+ while (i < size) { \
+ struct effect *_eff = effect_vector_get(&(eff_list), i); \
+ if (are_effect_defns_equal(_eff->defn, defn) \
+ && (!pplayer || _eff->plr == pplayer) \
+ && (!pcity || _eff->home == pcity) \
+ && (id == B_LAST || _eff->id == id)) { \
+ freelog(LOG_DEBUG, "deleted effect p: %s, c: %s i: %d n: %s", \
+ pplayer->name, (pcity) ? pcity->name : "(homeless)", \
+ id, effect_type_name(defn->type)); \
+ memcpy(_eff, effect_vector_get(&(eff_list), size - 1), \
+ sizeof(struct effect)); \
+ size--; \
+ (eff_list).vector.n--; \
+ } else { \
+ i++; \
+ } \
+ } \
+}
+
+ switch(defn->range) {
+ case EFR_WORLD:
+ SEARCH_LIST_AND_DEL(game.effects);
+ break;
+ case EFR_PLAYER:
+ assert(pplayer);
+ SEARCH_LIST_AND_DEL(pplayer->effects);
+ break;
+ case EFR_ISLAND:
+ assert(pplayer);
+ SEARCH_LIST_AND_DEL(pplayer->island_effects[id]);
+ break;
+ case EFR_CITY:
+ assert(pcity);
+ SEARCH_LIST_AND_DEL(pcity->effects);
+ break;
+ case EFR_LOCAL:
+ assert(pcity || punit);
+ if (pcity) {
+ SEARCH_LIST_AND_DEL(pcity->impr_effects);
+ } else {
+ SEARCH_LIST_AND_DEL(punit->effects);
+ }
+ break;
+ default:
+ break;
+ }
+
+#undef SEARCH_LIST_AND_DEL
+}
+
+/*******************************************************************
+ copy the vectors of an effect_defn_vector into an array for packetization.
+********************************************************************/
+void effect_defn_vector_to_array(const struct effect_defn_vector *vector,
+ struct effect_defn *array, int *array_count)
+{
+ *array_count = 0;
+ effect_defn_vector_iterate(*vector, item) {
+ array[*array_count] = *item;
+ (*array_count)++;
+ } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ copy an array of vectors of effect_defn into a effect_defn_vector.
+********************************************************************/
+void effect_defn_array_to_vector(const struct effect_defn *array,
+ int array_count,
+ struct effect_defn_vector *vector)
+{
+ int i;
+
+ effect_defn_vector_init(vector);
+ effect_defn_vector_reserve(vector, array_count);
+ for (i = 0; i < array_count; i++) {
+ *effect_defn_vector_get(vector, i) = array[i];
+ }
}
diff -Nur -Xcvs/diff_ignore snap-pre/common/effects.h snap-eff/common/effects.h
--- snap-pre/common/effects.h 2003-12-14 18:20:46.000000000 -0600
+++ snap-eff/common/effects.h 2004-03-05 20:44:46.000000000 -0600
@@ -18,6 +18,19 @@
#include "shared.h" /* bool */
#include "terrain.h"
+struct player;
+struct city;
+
+/* the different classes an effect could belong to.
+ * certain classes can only have certain ranges */
+enum effect_class {
+ EFC_UNIT,
+ EFC_IMPROVEMENT,
+ EFC_TECH,
+ EFC_GOVERNMENT,
+ EFC_NATION
+};
+
/* Range of effects (used in equiv_range and effect.range fields)
* These must correspond to effect_range_names[] in improvement.c. */
enum effect_range {
@@ -116,18 +129,243 @@
EFT_UPGRADE_ALL_STEP,
EFT_UPGRADE_ALL_LEAP,
EFT_UPKEEP_FREE,
- EFT_LAST /* keep this last */
+ EFT_UNIT_ADD_TO_CITY,
+ EFT_UNIT_AEGIS,
+ EFT_UNIT_AIRBASE,
+ EFT_UNIT_CARRIER,
+ EFT_UNIT_CITIES,
+ EFT_UNIT_DIPLOMAT,
+ EFT_UNIT_FANATIC,
+ EFT_UNIT_FIELD_UNIT,
+ EFT_UNIT_FIGHTER,
+ EFT_UNIT_GAME_LOSS,
+ EFT_UNIT_HELP_WONDER,
+ EFT_UNIT_HORSE,
+ EFT_UNIT_IGNORE_TERRAIN,
+ EFT_UNIT_IGNORE_TIRED,
+ EFT_UNIT_IGNORE_WALLS,
+ EFT_UNIT_IGNORE_ZOC,
+ EFT_UNIT_MARINES,
+ EFT_UNIT_MISSILE,
+ EFT_UNIT_MISSILE_CARRIER,
+ EFT_UNIT_NO_HOME,
+ EFT_UNIT_NO_LAND_ATTACK,
+ EFT_UNIT_NONMILITARY,
+ EFT_UNIT_NUCLEAR,
+ EFT_UNIT_ONE_ATTACK,
+ EFT_UNIT_PARATROOPERS,
+ EFT_UNIT_PARTIAL_INVISIBLE,
+ EFT_UNIT_PIKEMEN,
+ EFT_UNIT_SETTLERS,
+ EFT_UNIT_SPY,
+ EFT_UNIT_TRADE_ROUTE,
+ EFT_UNIT_TRANSFORM,
+ EFT_UNIT_TRIREME,
+ EFT_UNIT_UNBRIBABLE,
+ EFT_UNIT_UNDISBANDABLE,
+ EFT_UNIT_SUPER_SPY,
+ EFT_UNIT_UNIQUE,
+
+ EFT_LAST /* keep this last */
};
#define EFT_ALL EFT_LAST
+/* an effect definition. lists of these are in:
+ * nation, government, tech, improvement, and soon-to-be-in unit structs */
+struct effect_defn {
+ enum effect_type type;
+ enum effect_range range;
+ bool outside; /* affects outside of cities or center
tile */
+ short amount;
+ short value1; /* auxillary amount (paratroopers) */
+ short value2; /* ditto */
+
+ int cond_nat; /* actually Nation_Type_id */
+ int cond_gov;
+ int cond_adv; /* actually Tech_Type_id */
+ int cond_bldg; /* actually Impr_Type_id */
+ enum effect_type cond_eff;
+
+ enum tile_terrain_type aff_terr;
+ enum tile_special_type aff_spec;
+ int aff_unit; /* actually Unit_Class_id */
+};
+
+#define SPECVEC_TAG effect_defn
+#define SPECVEC_TYPE struct effect_defn
+#include "specvec.h"
+
+#define effect_defn_vector_iterate(_vec, _defn) \
+{ \
+ int _iter; \
+ struct effect_defn *_defn; \
+ for (_iter = 0; _iter < effect_defn_vector_size(&(_vec)); _iter++) { \
+ _defn = effect_defn_vector_get(&(_vec), _iter);
+
+#define effect_defn_vector_iterate_end \
+ } \
+}
+
+/* active, pending and has.* cache whether the effect is active */
+struct effect {
+ /* save a bunch of memory */
+ struct {
+ unsigned int active:1; /* is effect active? */
+ unsigned int pending:1; /* is effect active except for cond_bldg? */
+ unsigned int changed:1; /* has effect changed since last update? */
+ unsigned int was_active:1; /* temp variable for calculation of 'changed'
*/
+
+ unsigned int nat:1; /* has req. nation (or doesn't need one) */
+ unsigned int adv:1; /* has req. advance (or doesn't need one) */
+ unsigned int gov:1; /* has req. gov (or doesn't need one) */
+ unsigned int bldg:1; /* has req. bldg (only partially cached) */
+ unsigned int condeff:1; /* has cond_eff (only partially cached) */
+ unsigned int no_equiv:1; /* there's no equivalent bldg that suppresses
*/
+ } has;
+
+ struct player *plr;
+ struct city *home; /* NULL if effect has no location (origin) */
+ struct unit *unit; /* NULL if effect is not attached to a unit */
+ int id; /* id of thing generating effect */
+
+ struct effect_defn *defn; /* a pointer to the effect definition */
+};
+
+#define SPECVEC_TAG effect
+#define SPECVEC_TYPE struct effect
+#include "specvec.h"
+
+#define effect_vector_iterate(_vec, _eff) \
+{ \
+ int _iter; \
+ struct effect *_eff; \
+ for (_iter = 0; _iter < effect_vector_size(&(_vec)); _iter++) { \
+ _eff = effect_vector_get(&(_vec), _iter);
+
+#define effect_vector_iterate_end \
+ } \
+}
+
+struct effect_iter {
+ /* these are set by the user */
+ enum effect_type type; /* what type to look for. EFT_ALL returns all */
+ struct player *player; /* if NULL, only EFR_WORLD */
+ struct city *city; /* if !NULL, all effects affecting this city */
+ struct unit *unit; /* if !NULL, all effects affecting this unit */
+ int id; /* if !B_ALL, all effects affecting this impr */
+
+ /* these are internal. They track and end the iteration */
+ enum effect_range range;
+ enum effect_range end_range;
+ int pos;
+};
+
/* lookups */
+bool is_immediate_effect(struct effect_defn *defn);
enum effect_range effect_range_from_str(const char *str);
const char *effect_range_name(enum effect_range id);
enum effect_type effect_type_from_str(const char *str);
const char *effect_type_name(enum effect_type id);
+bool are_effect_defns_equal(const struct effect_defn *const peff1,
+ const struct effect_defn *const peff2);
+
+/* retrieval */
+bool is_effect_emitting(struct effect *eff, struct city *pcity);
+void effect_iterator_init(struct effect_iter *iter, struct player *pplayer,
+ struct city *pcity, struct unit *punit,
+ int id, enum effect_type type);
+struct effect *effect_iterator_get_next_active(struct effect_iter *iter);
+
+/* initialization, update, destroy */
+void effects_defer_update(void);
+void effects_undefer_update(void);
+void effects_update_all(void);
+void effects_update_all_common(void);
+
+struct effect *append_effect(struct player *pplayer, struct city *home,
+ struct unit *punit, enum effect_range range);
+void add_nation_effects(struct player *pplayer, bool add_immed_effects);
+void add_tech_effects(struct player *pplayer, int id, bool add_immed_effects);
+void add_government_effects(struct player *pplayer, bool add_immed_effects);
+void add_improvement_effects(struct city *pcity, int id,
+ bool add_immed_effects);
+void add_unit_effects(struct unit *punit, bool add_immed_effects);
+
+void delete_effect(struct player *pplayer, struct city *pcity,
+ struct unit *punit, int id, struct effect_defn *defn);
+void delete_effects(enum effect_class class, struct player *pplayer,
+ struct city *pcity, struct unit *punit, int id);
+void delete_effects_common(enum effect_class class, struct player *pplayer,
+ struct city *pcity, struct unit *punit, int id);
+
+void allot_island_effects(void);
+
+/* packet conversion */
+void effect_defn_vector_to_array(const struct effect_defn_vector *vector,
+ struct effect_defn *array, int *array_count);
+void effect_defn_array_to_vector(const struct effect_defn *array,
+ int array_count,
+ struct effect_defn_vector *vector);
+
+/* useful iterators */
+
+/* search for effects affecting a particular improvement */
+#define improvement_effects_iterate(_pcity, _id, _type, _eff) \
+{ \
+ struct effect_iter _iter; \
+ struct effect *(_eff); \
+ struct player *_plr; \
+ \
+ assert(_pcity); \
+ _plr = city_owner(_pcity); \
+ effect_iterator_init(&_iter, _plr, (_pcity), NULL, (_id), (_type)); \
+ while( ((_eff) = effect_iterator_get_next_active(&_iter)) ) {
+
+#define improvement_effects_iterate_end \
+ } \
+}
+
+/* search for effects affecting a particular city */
+#define city_effects_iterate(_pcity, _type, _eff) \
+ improvement_effects_iterate((_pcity), B_ALL, (_type), (_eff))
+
+#define city_effects_iterate_end \
+ improvement_effects_iterate_end
+
+/* search for effects affecting a particular player */
+#define player_effects_iterate(_player, _type, _eff) \
+{ \
+ struct effect_iter _iter; \
+ struct effect *(_eff); \
+ effect_iterator_init(&_iter, (_player), NULL, NULL, B_ALL, (_type)); \
+ while( ((_eff) = effect_iterator_get_next_active(&_iter)) ) {
+
+#define player_effects_iterate_end \
+ } \
+}
+
+/* search for effects affecting everyone */
+#define global_effects_iterate(_type, _eff) \
+ player_effects_iterate(NULL, (_type), (_eff))
+
+#define global_effects_iterate_end \
+ player_effects_iterate_end
+
+/* search for effects affecting a particular unit */
+#define unit_effects_iterate(_punit, _type, _eff) \
+{ \
+ struct effect_iter _iter; \
+ struct effect *(_eff); \
+ struct player *_plr; \
+ \
+ assert(_punit); \
+ _plr = unit_owner(_punit); \
+ effect_iterator_init(&_iter, _plr, NULL, (_punit), B_ALL, (_type)); \
+ while( ((_eff) = effect_iterator_get_next_active(&_iter)) ) {
-bool are_effects_equal(const struct impr_effect *const peff1,
- const struct impr_effect *const peff2);
+#define unit_effects_iterate_end \
+ } \
+}
#endif /* FC__EFFECTS_H */
diff -Nur -Xcvs/diff_ignore snap-pre/common/game.c snap-eff/common/game.c
--- snap-pre/common/game.c 2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/game.c 2004-03-05 20:50:10.000000000 -0600
@@ -254,6 +254,8 @@
game.occupychance= GAME_DEFAULT_OCCUPYCHANCE;
game.revolution_length = GAME_DEFAULT_REVOLUTION_LENGTH;
+ effect_vector_init(&game.effects);
+
game.heating = 0;
game.cooling = 0;
@@ -336,8 +338,14 @@
***************************************************************/
void game_free(void)
{
+ effect_vector_free(&game.effects);
game_remove_all_players();
map_free();
+
+ /* reinitialize internal variables */
+ map.num_continents = 0;
+ allot_island_effects();
+
idex_free();
ruleset_data_free();
cm_free();
@@ -440,16 +448,27 @@
***************************************************************/
void game_remove_player(struct player *pplayer)
{
+ int i;
+
if (pplayer->attribute_block.data) {
free(pplayer->attribute_block.data);
pplayer->attribute_block.data = NULL;
}
+ effect_vector_free(&pplayer->effects);
+
if (pplayer->island_improv) {
free(pplayer->island_improv);
pplayer->island_improv = NULL;
}
+ if (pplayer->island_effects) {
+ for (i = 1; i <= map.num_continents; i++) {
+ effect_vector_free(&pplayer->island_effects[i]);
+ }
+ pplayer->island_effects = NULL;
+ }
+
conn_list_unlink_all(&pplayer->connections);
unit_list_iterate(pplayer->units, punit)
diff -Nur -Xcvs/diff_ignore snap-pre/common/game.h snap-eff/common/game.h
--- snap-pre/common/game.h 2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/game.h 2004-03-05 20:44:46.000000000 -0600
@@ -20,6 +20,7 @@
#endif
#include "connection.h" /* struct conn_list */
+#include "effects.h"
#include "improvement.h" /* Impr_Status */
#include "player.h"
#include "shared.h"
@@ -108,6 +109,7 @@
/* global_wonders[] may also be (-1), or the id of a city
which no longer exists, if the wonder has been destroyed */
Impr_Status improvements[B_LAST]; /* impr. with equiv_range==World */
+ struct effect_vector effects; /* effects with
range==global */
int heating; /* Number of polluted squares. */
int globalwarming; /* Total damage done. (counts towards a warming event.) */
diff -Nur -Xcvs/diff_ignore snap-pre/common/government.h
snap-eff/common/government.h
--- snap-pre/common/government.h 2003-07-04 06:20:45.000000000 -0500
+++ snap-eff/common/government.h 2004-03-05 20:44:46.000000000 -0600
@@ -13,6 +13,7 @@
#ifndef FC__GOVERNMENT_H
#define FC__GOVERNMENT_H
+#include "effects.h"
#include "shared.h"
struct city;
@@ -152,6 +153,8 @@
int hints;
struct Sprite *sprite;
+
+ struct effect_defn_vector effect_defs;
char *helptext;
};
diff -Nur -Xcvs/diff_ignore snap-pre/common/improvement.c
snap-eff/common/improvement.c
--- snap-pre/common/improvement.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/improvement.c 2004-03-05 20:44:46.000000000 -0600
@@ -18,6 +18,7 @@
#include <assert.h>
#include <string.h>
+#include "effects.h"
#include "game.h"
#include "log.h"
#include "map.h"
@@ -100,8 +101,7 @@
free(p->equiv_repl);
p->equiv_repl = NULL;
- free(p->effect);
- p->effect = NULL;
+ effect_defn_vector_free(&(p->effect_defs));
free(p->helptext);
p->helptext = NULL;
@@ -346,6 +346,9 @@
/**************************************************************************
Whether player could build this improvement, assuming they had
the tech req, and assuming a city with the right pre-reqs etc.
+
+ FIXME: this will not work correctly with a general effects paradigm.
+ We must pass in a city if there is one.
**************************************************************************/
bool could_player_eventually_build_improvement(struct player *p,
Impr_Type_id id)
@@ -358,28 +361,51 @@
impr = get_improvement_type(id);
- if (impr->effect) {
- struct impr_effect *peffect = impr->effect;
- enum effect_type type;
-
- /* This if for a spaceship component is asked */
- while ((type = peffect->type) != EFT_LAST) {
- if (type == EFT_SPACE_PART) {
- /* TODO: remove this */
- if (game.global_wonders[B_APOLLO] == 0)
- return FALSE;
- if (p->spaceship.state >= SSHIP_LAUNCHED)
- return FALSE;
- if (peffect->amount == 1 && p->spaceship.structurals >=
NUM_SS_STRUCTURALS)
- return FALSE;
- if (peffect->amount == 2 && p->spaceship.components >=
NUM_SS_COMPONENTS)
- return FALSE;
- if (peffect->amount == 3 && p->spaceship.modules >= NUM_SS_MODULES)
- return FALSE;
+ /* we have some special rules for space parts. */
+ effect_defn_vector_iterate(impr->effect_defs, defn) {
+ /* is this improvement considered a space part? */
+ if (defn->type == EFT_SPACE_PART) {
+ bool space_enabled = FALSE;
+
+ /* if spaceship is already launched, can't build it */
+ if (p->spaceship.state >= SSHIP_LAUNCHED) {
+ return FALSE;
+ }
+
+ /* we can't build it though unless we feel the "Enable_Space" effect */
+ player_effects_iterate(p, EFT_ENABLE_SPACE, eff) {
+ space_enabled = TRUE;
+ break;
+ } player_effects_iterate_end;
+
+ if (!space_enabled) {
+ return FALSE;
+ }
+
+ /* ok, we can go to space, but we still can't build
+ * it if we've already built too many... amounts are
+ * special-cased, defined here. */
+ switch (defn->amount) {
+ case 1:
+ if (p->spaceship.structurals >= NUM_SS_STRUCTURALS) {
+ return FALSE;
+ }
+ break;
+ case 2:
+ if (p->spaceship.components >= NUM_SS_COMPONENTS) {
+ return FALSE;
+ }
+ break;
+ case 3:
+ default: /* treat > 3 to be 3. */
+ if (p->spaceship.modules >= NUM_SS_MODULES) {
+ return FALSE;
+ }
+ break;
}
- peffect++;
}
- }
+ } effect_defn_vector_iterate_end;
+
if (is_wonder(id)) {
/* Can't build wonder if already built */
if (game.global_wonders[id] != 0) return FALSE;
@@ -464,13 +490,17 @@
Impr_Status *improvs =
&pplayer->island_improv[cont * game.num_impr_types];
- built_impr_iterate(pcity, id) {
+ impr_type_iterate(id) {
+ if (pcity->improvements[id] == I_NONE) {
+ continue;
+ }
+
if (improvement_types[id].equiv_range != IR_ISLAND) {
continue;
}
improvs[id] = pcity->improvements[id];
- } built_impr_iterate_end;
+ } impr_type_iterate_end;
} city_list_iterate_end;
} players_iterate_end;
diff -Nur -Xcvs/diff_ignore snap-pre/common/improvement.h
snap-eff/common/improvement.h
--- snap-pre/common/improvement.h 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/improvement.h 2004-03-05 20:44:46.000000000 -0600
@@ -32,7 +32,6 @@
#define I_OBSOLETE 2 /* Built, but obsoleted by a tech */
#define I_REDUNDANT 3 /* Built, but replaced by wonder/other building */
-
/* FIXME: Remove this define when there is per-file need for this enum. */
#define OLD_IMPR_TYPE_ENUM
@@ -64,6 +63,7 @@
* it can also be used for fixed allocations to ensure ability
* to hold full number of improvement types. */
#define B_LAST MAX_NUM_ITEMS
+#define B_ALL B_LAST
/* Range of equivalence (used in equiv_range fields)
* These must correspond to impr_range_names[] in improvement.c. */
@@ -76,25 +76,6 @@
IR_LAST /* keep this last */
};
-/* An effect conferred by an improvement. */
-struct impr_effect {
- enum effect_type type;
- enum effect_range range;
- int amount;
- int survives; /* 1 = effect survives wonder
destruction */
- Impr_Type_id cond_bldg; /* B_LAST = unconditional */
- int cond_gov; /* game.government_count =
unconditional */
- Tech_Type_id cond_adv; /* A_NONE = unconditional; A_LAST = never */
- enum effect_type cond_eff; /* EFT_LAST = unconditional */
- Unit_Class_id aff_unit; /* UCL_LAST = all */
- enum tile_terrain_type aff_terr; /* T_UNKNOWN = all; T_LAST = none */
- enum tile_special_type aff_spec; /* S_* bit mask of specials affected */
-};
-
-/* Maximum number of effects per improvement
- * (this should not be more than the number of bits in the Eff_Status type) */
-#define MAX_EFFECTS 16
-
/* Type of improvement. (Read from buildings.ruleset file.) */
struct impr_type {
char name[MAX_LEN_NAME];
@@ -113,8 +94,9 @@
int build_cost; /* Use wrappers to access this. */
int upkeep;
int sabotage;
- struct impr_effect *effect; /* list; .type==EFT_LAST terminated */
- int variant; /* FIXME: remove when gen-impr obsoletes */
+ struct effect_defn_vector effect_defs; /* list of effect definitions
*/
+ int variant; /* FIXME: remove when gen-impr obsoletes */
+
struct Sprite *sprite; /* icon of the improvement */
char *helptext;
char soundtag[MAX_LEN_NAME];
diff -Nur -Xcvs/diff_ignore snap-pre/common/nation.h snap-eff/common/nation.h
--- snap-pre/common/nation.h 2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/nation.h 2004-03-05 20:44:46.000000000 -0600
@@ -13,6 +13,7 @@
#ifndef FC__NATION_H
#define FC__NATION_H
+#include "effects.h"
#include "shared.h" /* MAX_LEN_NAME */
#include "terrain.h" /* T_COUNT */
@@ -99,6 +100,8 @@
int wonder; /* primary Wonder */
int government;
} goals;
+
+ struct effect_defn_vector effect_defs;
};
struct team {
diff -Nur -Xcvs/diff_ignore snap-pre/common/packets.def
snap-eff/common/packets.def
--- snap-pre/common/packets.def 2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/packets.def 2004-03-05 20:51:16.000000000 -0600
@@ -157,7 +157,7 @@
type CITY_MAP = city_map(char)
type WORKLIST = worklist(struct worklist)
type TECH_LIST = tech_list(int)
-type EFFECT = effect(struct impr_effect)
+type EFFECT_DEFN = effect_defn(struct effect_defn)
# typedefs for enums
type CLAUSE = uint8(enum clause_type)
@@ -947,6 +947,8 @@
bitvector(bv_flags) flags;
bitvector(bv_roles) roles;
+ UINT8 effect_defs_count;
+ EFFECT_DEFN effect_defs[255:effect_defs_count];
end
PACKET_RULESET_GAME=97;sc
@@ -963,6 +965,8 @@
UINT8 tech_cost_style;
UINT8 tech_leakage;
TECH_LIST global_init_techs[MAX_NUM_TECH_LIST];
+ UINT8 effect_defs_count;
+ EFFECT_DEFN effect_defs[255:effect_defs_count];
UINT8 trireme_loss_chance[MAX_VET_LEVELS]; add-cap(veteran)
UINT8 work_veteran_chance[MAX_VET_LEVELS]; add-cap(veteran)
@@ -986,6 +990,8 @@
STRING helptext[MAX_LEN_PACKET];
STRING graphic_str[MAX_LEN_NAME];
STRING graphic_alt[MAX_LEN_NAME];
+ UINT8 effect_defs_count;
+ EFFECT_DEFN effect_defs[255:effect_defs_count];
end
PACKET_RULESET_GOVERNMENT=100;sc
@@ -1049,6 +1055,8 @@
STRING graphic_str[MAX_LEN_NAME];
STRING graphic_alt[MAX_LEN_NAME];
STRING helptext[MAX_LEN_PACKET];
+ UINT8 effect_defs_count;
+ EFFECT_DEFN effect_defs[255:effect_defs_count];
end
PACKET_RULESET_TERRAIN_CONTROL=101;sc
@@ -1096,6 +1104,8 @@
UINT8 leader_count;
STRING leader_name[MAX_NUM_LEADERS:leader_count][MAX_LEN_NAME];
BOOL leader_sex[MAX_NUM_LEADERS:leader_count];
+ UINT8 effect_defs_count;
+ EFFECT_DEFN effect_defs[255:effect_defs_count];
end
PACKET_RULESET_CITY=103;sc
@@ -1132,8 +1142,8 @@
IMPROVEMENT equiv_dupl[255:equiv_dupl_count];
UINT8 equiv_repl_count;
IMPROVEMENT equiv_repl[255:equiv_repl_count];
- UINT8 effect_count;
- EFFECT effect[255:effect_count];
+ UINT8 effect_defs_count;
+ EFFECT_DEFN effect_defs[255:effect_defs_count];
end
PACKET_RULESET_TERRAIN=105;sc
@@ -1214,3 +1224,9 @@
STRING team_name[MAX_NUM_TEAMS][MAX_LEN_NAME];
end
+
+PACKET_GLOBAL_EFFECT=107;sc
+ BOOL add_effect; /* if FALSE, remove the effect */
+ PLAYER player;
+ EFFECT_DEFN effect_def[1];
+end
diff -Nur -Xcvs/diff_ignore snap-pre/common/player.c snap-eff/common/player.c
--- snap-pre/common/player.c 2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/player.c 2004-03-05 20:44:46.000000000 -0600
@@ -131,18 +131,26 @@
plr->gives_shared_vision = 0;
plr->really_gives_vision = 0;
- /* Initialise list of improvements with Player-wide equiv_range */
+ /* Initialise list of improvements and effects with Player-wide range */
improvement_status_init(plr->improvements, ARRAY_SIZE(plr->improvements));
+ effect_vector_init(&plr->effects);
- /* Initialise list of improvements with Island-wide equiv_range */
+ /* Initialise list of improvements and effects with Island-wide range */
plr->island_improv = NULL;
+ plr->island_effects = NULL;
if (map.num_continents > 0) {
plr->island_improv = fc_malloc((map.num_continents + 1) *
game.num_impr_types * sizeof(Impr_Status));
+
+ plr->island_effects = fc_malloc((map.num_continents + 1) *
+ sizeof(struct effect_vector));
+
for (i = 1; i <= map.num_continents; i++) {
improvement_status_init(&plr->island_improv[i * game.num_impr_types],
game.num_impr_types);
+
+ effect_vector_init(&plr->island_effects[i]);
}
}
diff -Nur -Xcvs/diff_ignore snap-pre/common/player.h snap-eff/common/player.h
--- snap-pre/common/player.h 2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/player.h 2004-03-05 20:44:46.000000000 -0600
@@ -15,6 +15,7 @@
#include "city.h"
#include "connection.h"
+#include "effects.h"
#include "improvement.h" /* Impr_Status */
#include "nation.h"
#include "shared.h"
@@ -209,6 +210,8 @@
Impr_Status improvements[B_LAST]; /* improvements with equiv_range==Player */
Impr_Status *island_improv; /* improvements with equiv_range==Island,
dimensioned to
[map.num_continents][game.num_impr_types] */
+ struct effect_vector effects; /* effects with range==Player */
+ struct effect_vector *island_effects; /* effects with range==Island */
bool can_nuke; /* bits to record the two effects which survive */
bool can_space; /* their origin's destruction. */
diff -Nur -Xcvs/diff_ignore snap-pre/common/specvec.h snap-eff/common/specvec.h
--- snap-pre/common/specvec.h 2003-08-07 22:42:16.000000000 -0500
+++ snap-eff/common/specvec.h 2004-03-05 20:44:46.000000000 -0600
@@ -66,9 +66,9 @@
void SPECVEC_FOO(_vector_init) (SPECVEC_VECTOR *tthis);
void SPECVEC_FOO(_vector_reserve) (SPECVEC_VECTOR *tthis, int n);
-size_t SPECVEC_FOO(_vector_size) (SPECVEC_VECTOR *tthis);
-SPECVEC_TYPE *SPECVEC_FOO(_vector_get) (SPECVEC_VECTOR *tthis, int index);
-void SPECVEC_FOO(_vector_copy) (SPECVEC_VECTOR *to, SPECVEC_VECTOR *from);
+size_t SPECVEC_FOO(_vector_size) (const SPECVEC_VECTOR *tthis);
+SPECVEC_TYPE *SPECVEC_FOO(_vector_get) (const SPECVEC_VECTOR *tthis, int
index);
+void SPECVEC_FOO(_vector_copy) (SPECVEC_VECTOR *to, const SPECVEC_VECTOR
*from);
void SPECVEC_FOO(_vector_free) (SPECVEC_VECTOR *tthis);
#undef SPECVEC_TAG
diff -Nur -Xcvs/diff_ignore snap-pre/common/specvec_c.h
snap-eff/common/specvec_c.h
--- snap-pre/common/specvec_c.h 2003-08-07 22:45:00.000000000 -0500
+++ snap-eff/common/specvec_c.h 2004-03-05 20:44:46.000000000 -0600
@@ -51,12 +51,12 @@
ath_minnum(&tthis->vector, n);
}
-size_t SPECVEC_FOO(_vector_size) (SPECVEC_VECTOR *tthis)
+size_t SPECVEC_FOO(_vector_size) (const SPECVEC_VECTOR *tthis)
{
return tthis->vector.n;
}
-SPECVEC_TYPE *SPECVEC_FOO(_vector_get) (SPECVEC_VECTOR *tthis, int index)
+SPECVEC_TYPE *SPECVEC_FOO(_vector_get) (const SPECVEC_VECTOR *tthis, int index)
{
assert(index>=0 && index<tthis->vector.n);
@@ -64,7 +64,7 @@
}
/* You must _init "*to" before using this function */
-void SPECVEC_FOO(_vector_copy) (SPECVEC_VECTOR *to, SPECVEC_VECTOR *from)
+void SPECVEC_FOO(_vector_copy) (SPECVEC_VECTOR *to, const SPECVEC_VECTOR *from)
{
int i;
size_t size = SPECVEC_FOO(_vector_size) (from);
diff -Nur -Xcvs/diff_ignore snap-pre/common/tech.c snap-eff/common/tech.c
--- snap-pre/common/tech.c 2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/tech.c 2004-03-05 20:44:46.000000000 -0600
@@ -57,7 +57,7 @@
...
**************************************************************************/
void set_invention(struct player *pplayer, Tech_Type_id tech,
- enum tech_state value)
+ enum tech_state value, bool add_immed_effects)
{
if (pplayer->research.inventions[tech].state == value) {
return;
@@ -68,6 +68,7 @@
if (value == TECH_KNOWN) {
game.global_advances[tech]++;
improvements_update_obsolete();
+ add_tech_effects(pplayer, tech, add_immed_effects);
}
}
@@ -194,16 +195,16 @@
tech_type_iterate(i) {
if (!tech_is_available(pplayer, i)) {
- set_invention(pplayer, i, TECH_UNKNOWN);
+ set_invention(pplayer, i, TECH_UNKNOWN, FALSE);
} else {
if (get_invention(pplayer, i) == TECH_REACHABLE) {
- set_invention(pplayer, i, TECH_UNKNOWN);
+ set_invention(pplayer, i, TECH_UNKNOWN, FALSE);
}
if (get_invention(pplayer, i) == TECH_UNKNOWN
&& get_invention(pplayer, advances[i].req[0]) == TECH_KNOWN
&& get_invention(pplayer, advances[i].req[1]) == TECH_KNOWN) {
- set_invention(pplayer, i, TECH_REACHABLE);
+ set_invention(pplayer, i, TECH_REACHABLE, FALSE);
}
}
build_required_techs(pplayer, i);
diff -Nur -Xcvs/diff_ignore snap-pre/common/tech.h snap-eff/common/tech.h
--- snap-pre/common/tech.h 2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/tech.h 2004-03-05 20:44:46.000000000 -0600
@@ -14,6 +14,7 @@
#define FC__TECH_H
#include "shared.h"
+#include "effects.h"
#include "nation.h" /* Nation_Type_id */
@@ -103,13 +104,15 @@
* itself. Precalculated at server then send to client.
*/
int num_reqs;
+
+ struct effect_defn_vector effect_defs;
};
BV_DEFINE(tech_vector, A_LAST);
enum tech_state get_invention(struct player *pplayer, Tech_Type_id tech);
void set_invention(struct player *pplayer, Tech_Type_id tech,
- enum tech_state value);
+ enum tech_state value, bool add_immed_effects);
void update_research(struct player *pplayer);
Tech_Type_id get_next_tech(struct player *pplayer, Tech_Type_id goal);
diff -Nur -Xcvs/diff_ignore snap-pre/common/unit.c snap-eff/common/unit.c
--- snap-pre/common/unit.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/unit.c 2004-03-05 20:52:50.000000000 -0600
@@ -1512,6 +1512,10 @@
punit->occupy = 0;
punit->has_orders = FALSE;
+ /* Initialise unit's vector of improvement effects. */
+ effect_vector_init(&punit->effects);
+ add_unit_effects(punit, TRUE);
+
return punit;
}
@@ -1522,6 +1526,9 @@
void destroy_unit_virtual(struct unit *punit)
{
free_unit_orders(punit);
+
+ effect_vector_free(&punit->effects);
+
free(punit);
}
diff -Nur -Xcvs/diff_ignore snap-pre/common/unit.h snap-eff/common/unit.h
--- snap-pre/common/unit.h 2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/unit.h 2004-03-05 20:53:16.000000000 -0600
@@ -162,6 +162,8 @@
int transported_by;
int occupy; /* number of units that occupy transporter */
+ struct effect_vector effects;
+
bool has_orders;
struct {
int length, index;
diff -Nur -Xcvs/diff_ignore snap-pre/common/unittype.h
snap-eff/common/unittype.h
--- snap-pre/common/unittype.h 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/unittype.h 2004-03-05 20:44:46.000000000 -0600
@@ -14,6 +14,7 @@
#define FC__UNITTYPE_H
#include "shared.h"
+#include "effects.h"
struct player;
struct city;
@@ -196,6 +197,8 @@
bv_flags flags;
bv_roles roles;
+ struct effect_defn_vector effect_defs; /* list of effect definitions */
+
int happy_cost; /* unhappy people in home city */
int shield_cost; /* normal upkeep cost */
int food_cost; /* settler food cost */
diff -Nur -Xcvs/diff_ignore snap-pre/data/default/units.ruleset
snap-eff/data/default/units.ruleset
--- snap-pre/data/default/units.ruleset 2004-02-22 11:12:04.000000000 -0600
+++ snap-eff/data/default/units.ruleset 2004-03-05 20:44:46.000000000 -0600
@@ -85,6 +85,7 @@
; (NOTE: gold upkeep is still not implemented)
; flags = special flag strings
; roles = special role strings
+; effect = effects that this unit has. see doc/README.effects
; sound_move = optional sound effect when the unit moves
; sound_move_alt= optional alternative sound effect if above not
; supported in client
@@ -206,6 +207,14 @@
uk_gold = 0
flags = "Settlers", "NonMil", "Airbase", "AddToCity", "Cities",
"NoVeteran"
roles = ""
+effect =
+ { "type"
+ "Unit_Settlers"
+ "Unit_Nonmilitary"
+ "Unit_Airbase"
+ "Unit_Add_To_City"
+ "Unit_Cities"
+ }
helptext = _("\
Settlers are one of the key units in the game. They can be used to\
found new cities, irrigate land, build roads, railroads,\
@@ -250,6 +259,15 @@
uk_gold = 0
flags = "Settlers", "NonMil", "Transform", "Airbase", "AddToCity",
"Cities", "NoVeteran"
roles = ""
+effect =
+ { "type"
+ "Unit_Settlers"
+ "Unit_Nonmilitary"
+ "Unit_Transform"
+ "Unit_Airbase"
+ "Unit_Add_To_City"
+ "Unit_Cities"
+ }
helptext = _("\
Engineers are similar to Settlers, but they work twice as fast and\
move twice as fast. Engineers may also perform major terrain\
@@ -407,6 +425,10 @@
uk_gold = 0
flags = "Pikemen"
roles = "DefendGood", "FirstBuild"
+effect =
+ { "type"
+ "Unit_Pikemen"
+ }
[unit_musketeers]
name = _("Musketeers")
@@ -492,6 +514,11 @@
uk_gold = 0
flags = "IgTer", "IgZOC"
roles = "DefendGood", "Partisan", "BarbarianTech"
+effect =
+ { "type"
+ "Unit_Ignore_Terrain"
+ "Unit_Ignore_ZOC"
+ }
helptext = _("\
A number of Partisans are granted free when an enemy conquers your\
city, but only under these conditions:\
@@ -532,6 +559,10 @@
uk_gold = 0
flags = "IgTer"
roles = "DefendGood"
+effect =
+ { "type"
+ "Unit_Ignore_Terrain"
+ }
[unit_riflemen]
name = _("Riflemen")
@@ -588,6 +619,10 @@
uk_gold = 0
flags = "Marines"
roles = "DefendOk", "BarbarianSeaTech"
+effect =
+ { "type"
+ "Unit_Marines"
+ }
[unit_paratroopers]
name = _("Paratroopers")
@@ -620,6 +655,10 @@
paratroopers_range = 10
paratroopers_mr_req = 1
paratroopers_mr_sub = 0
+effect =
+ { "type", "amount", "value1", "value2"
+ "Unit_Paratroopers", 10, 1, 0
+ }
[unit_mech_inf]
name = _("Mech. Inf.")
@@ -681,6 +720,10 @@
uk_gold = 0
flags = "Horse"
roles = "AttackFast", "Hut", "Barbarian"
+effect =
+ { "type"
+ "Unit_Horse"
+ }
[unit_chariot]
name = _("Chariot")
@@ -709,6 +752,10 @@
uk_gold = 0
flags = "Horse"
roles = "AttackFast", "Hut"
+effect =
+ { "type"
+ "Unit_Horse"
+ }
[unit_elephants]
name = _("Elephants")
@@ -737,6 +784,10 @@
uk_gold = 0
flags = "Horse"
roles = "AttackFast"
+effect =
+ { "type"
+ "Unit_Horse"
+ }
[unit_crusaders]
name = _("Crusaders")
@@ -765,6 +816,10 @@
uk_gold = 0
flags = "Horse"
roles = "AttackFast"
+effect =
+ { "type"
+ "Unit_Horse"
+ }
[unit_knights]
name = _("Knights")
@@ -794,6 +849,10 @@
flags = "Horse"
roles = "AttackFast", "HutTech", "BarbarianTech",
"BarbarianBuildTech", "BarbarianSeaTech"
+effect =
+ { "type"
+ "Unit_Horse"
+ }
[unit_dragoons]
name = _("Dragoons")
@@ -822,6 +881,10 @@
uk_gold = 0
flags = "Horse"
roles = "AttackFast", "BarbarianBuildTech", "BarbarianSeaTech"
+effect =
+ { "type"
+ "Unit_Horse"
+ }
[unit_cavalry]
name = _("Cavalry")
@@ -990,6 +1053,10 @@
uk_gold = 0
flags = "IgWall"
roles = "AttackStrong"
+effect =
+ { "type"
+ "Unit_Ignore_Walls"
+ }
[unit_fighter]
name = _("Fighter")
@@ -1018,6 +1085,10 @@
uk_gold = 0
flags = "Fighter"
roles = ""
+effect =
+ { "type"
+ "Unit_Fighter"
+ }
[unit_bomber]
name = _("Bomber")
@@ -1046,6 +1117,11 @@
uk_gold = 0
flags = "FieldUnit", "OneAttack"
roles = ""
+effect =
+ { "type"
+ "Unit_Field_Unit"
+ "Unit_One_Attack"
+ }
[unit_helicopter]
name = _("Helicopter")
@@ -1074,6 +1150,11 @@
uk_gold = 0
flags = "FieldUnit", "OneAttack"
roles = ""
+effect =
+ { "type"
+ "Unit_Field_Unit"
+ "Unit_One_Attack"
+ }
helptext = _("\
The Helicopter is a very powerful unit, as it can both fly and\
conquer cities. Care must be exercised, because Helicopters lose a\
@@ -1108,6 +1189,11 @@
uk_gold = 0
flags = "Partial_Invis", "Fighter"
roles = ""
+effect =
+ { "type"
+ "Unit_Partial_Invisible"
+ "Unit_Fighter"
+ }
helptext = _("\
An improved Fighter, with improved attack and a higher movement\
radius.\
@@ -1140,6 +1226,12 @@
uk_gold = 0
flags = "Partial_Invis", "FieldUnit", "OneAttack"
roles = ""
+effect =
+ { "type"
+ "Unit_Partial_Invisible"
+ "Unit_Field_Unit"
+ "Unit_Fighter"
+ }
helptext = _("\
An improved Bomber, with improved attack and a higher movement\
radius.\
@@ -1172,6 +1264,10 @@
uk_gold = 0
flags = "Trireme"
roles = "Ferryboat"
+effect =
+ { "type"
+ "Unit_Trireme"
+ }
[unit_caravel]
name = _("Caravel")
@@ -1372,6 +1468,10 @@
uk_gold = 0
flags = "AEGIS"
roles = "DefendGood"
+effect =
+ { "type"
+ "Unit_AEGIS"
+ }
[unit_battleship]
name = _("Battleship")
@@ -1429,6 +1529,12 @@
flags = "Partial_Invis",
"Missile_Carrier", "No_Land_Attack"
roles = ""
+effect =
+ { "type"
+ "Unit_Partial_Invisible"
+ "Unit_Missile_Carrier"
+ "Unit_No_Land_Attack"
+ }
helptext = _("\
Submarines have a very high strategic value, but have a weak\
defence.\
@@ -1461,6 +1567,10 @@
uk_gold = 0
flags = "Carrier"
roles = ""
+effect =
+ { "type"
+ "Unit_Carrier"
+ }
helptext = _("\
TIP: Guard Carriers with a handful of fast-moving ships and a\
battleship, as losing a fully-equipped Carrier is VERY\
@@ -1522,6 +1632,12 @@
uk_gold = 0
flags = "FieldUnit", "OneAttack", "Missile"
roles = ""
+effect =
+ { "type"
+ "Unit_Field_Unit"
+ "Unit_One_Attack"
+ "Unit_Missile"
+ }
helptext = _("\
TIP: A handful of these can successfully keep the waters around\
your treasured homeland free of enemy ships.\
@@ -1554,6 +1670,13 @@
uk_gold = 0
flags = "FieldUnit", "OneAttack", "Missile", "Nuclear"
roles = ""
+effect =
+ { "type"
+ "Unit_Field_Unit"
+ "Unit_One_Attack"
+ "Unit_Missile"
+ "Unit_Nuclear"
+ }
helptext = _("\
You can build Nuclear units when you have the required advance, and\
the Manhattan Project wonder has been built by any player.\
@@ -1601,6 +1724,12 @@
uk_gold = 0
flags = "Diplomat", "IgZOC", "NonMil"
roles = ""
+effect =
+ { "type"
+ "Unit_Diplomat"
+ "Unit_Ignore_ZOC"
+ "Unit_Nonmilitary"
+ }
helptext = _("\
- A Diplomat can establish embassies with other civilizations\
by moving into another player's city.\
@@ -1647,6 +1776,13 @@
uk_gold = 0
flags = "Diplomat", "IgZOC", "NonMil", "Spy"
roles = ""
+effect =
+ { "type"
+ "Unit_Diplomat"
+ "Unit_Ignore_ZOC"
+ "Unit_Nonmilitary"
+ "Unit_Spy"
+ }
helptext = _("\
A Spy is a full time professional and as such is much more\
skilled in the arts of espionage than her Diplomat predecessor.\
@@ -1694,6 +1830,13 @@
uk_gold = 0
flags = "TradeRoute", "HelpWonder", "IgZOC", "NonMil"
roles = ""
+effect =
+ { "type"
+ "Unit_Trade_Route"
+ "Unit_Help_Wonder"
+ "Unit_Ignore_ZOC"
+ "Unit_Nonmilitary"
+ }
helptext = _("\
Every Caravan that is used to build a wonder will add 50 shields\
towards the production of the wonder.\
@@ -1730,6 +1873,13 @@
uk_gold = 0
flags = "TradeRoute", "HelpWonder", "IgZOC", "NonMil"
roles = ""
+effect =
+ { "type"
+ "Unit_Trade_Route"
+ "Unit_Help_Wonder"
+ "Unit_Ignore_ZOC"
+ "Unit_Nonmilitary"
+ }
helptext = _("\
The Freight unit replaces the Caravan, and moves at twice the speed.\
")
@@ -1761,6 +1911,12 @@
uk_gold = 0
flags = "IgTer", "IgZOC", "NonMil"
roles = "Explorer"
+effect =
+ { "type"
+ "Unit_Ignore_Terrain"
+ "Unit_Ignore_ZOC"
+ "Unit_Nonmilitary"
+ }
helptext = _("\
Explorers are very useful for mapping unknown territory.\
")
@@ -1793,6 +1949,17 @@
flags = "IgZOC", "NonMil", "Unbribable",
"Undisbandable", "SuperSpy", "NoHome"
roles = "BarbarianLeader"
+effect =
+ { "type"
+ "Unit_Ignore_ZOC"
+ "Unit_Nonmilitary"
+ "Unit_Game_Loss"
+ "Unit_Unique"
+ "Unit_Unbribable"
+ "Unit_Undisbandable"
+ "Unit_Super_Spy"
+ "Unit_No_Home"
+ }
helptext = _("\
When barbarian leader is killed on a tile without any defending units, \
the 100 gold ransom is paid, but only to land units and helicopters.\
diff -Nur -Xcvs/diff_ignore snap-pre/doc/README.effects
snap-eff/doc/README.effects
--- snap-pre/doc/README.effects 2003-09-30 18:20:42.000000000 -0500
+++ snap-eff/doc/README.effects 2004-03-05 20:44:46.000000000 -0600
@@ -274,14 +274,121 @@
"Upkeep_Free" - improvements with AMOUNT or less upkeep cost become
free to upkeep (others are unaffected)
+__________________________________________________________________________
+The effects below are strictly unit effects.
-.range may be one of:
- "None", "Local", "City", "Island", "Player", "World"
+"Unit_Add_To_City" - can disband to add a single point of population to a city
+ (see cities.ruleset for limitation of this ability)
+"Unit_AEGIS" - fivefold increased defence against air attacks and missiles
+
+"Unit_Airbase" - (land only) can produce airbases
+
+"Unit_Carrier" - can transport air and missile units, but not land units
+
+"Unit_Cities" - can disband to produce a city
+
+"Unit_Diplomat" - can do diplomat actions (see diplchance server option)
+
+"Unit_Fanatic" - can only be built by governments that allow them
+ (see data/civ2/governments.ruleset, Fanaticism government)
+
+"Unit_Field_Unit" - cause unhappiness even when not being aggressive
+
+"Unit_Fighter" - can attack air units (no other units can normally do this)
+
+"Unit_Game_Loss" - losing one of these units means you lose the game, but it
+ is produced without homecity and upkeep
+
+"Unit_Help_Wonder" - can help build wonders
+
+"Unit_Horse" - (no effect)
+
+"Unit_Ignore_Terrain" - ignore terrain/road/rail, treat every tile as 1/3
+ move cost
+
+"Unit_Ignore_Tired" - ignore tired penalty when attacking
+
+"Unit_Ignore_Walls" - ignore effect of city walls
+
+"Unit_Ignore_ZOC" - (land only) ignore Zones of Control (ZOC)
+
+"Unit_Marines" - (land only) can attack from transports
+
+"Unit_Missile" - (air only) some buildings and units have higher defence
+ against these
+
+"Unit_Missile_Carrier" - can transport only missiles, but no aircraft or
+ land units
+
+"Unit_No_Home" - this unit has no homecity and will be free of all upkeep,
+ and therefore will not revolt along with its city of
+ origin should it be incited
+
+"Unit_No_Land_Attack" - (sea only) cannot attack targets on land
+
+"Unit_Nonmilitary" - a non-military unit, does not cause unhappiness
+
+"Unit_Nuclear" - nuke!
+
+"Unit_One_Attack" - can only make a single attack, regardless of movement
+ points
+
+"Unit_Paratroopers" - (land only) can paradrop. the maximal range is AMOUNT.
+ VALUE1 is the least move rate required for paradropping.
+ VALUE2 is the move rate which is subtracted after
+ paradropping
+
+"Unit_Partial_Invisible" - visible only to adjancent units; does not hide
+ transported units other than missiles
+
+"Unit_Pikemen" - double defence power against "Horse" flag units
+
+"Unit_Settlers" - can irrigate and build roads
+
+"Unit_Spy" - can do poison and sabotage, _must_ be "Diplomat" also
+
+"Unit_Trade_Route" - can establish trade routes
+
+"Unit_Transform" - can transform terrain
+
+"Unit_Trireme" - (sea only) sinks on high seas, lots of special rules
+
+"Unit_Unbribable" - this unit cannot be bribed
+
+"Unit_Undisbandable" - this unit cannot be disbanded, will not drown, and
+ will not disband due to lack of shields to upkeep it in
+ homecity if not given enough food to upkeep it, homecity
+ will shrink every turn it cannot do so, however
+
+"Unit_Super_Spy" - this unit always wins diplomatic contests, that is,
+ unless it encounters another SuperSpy, in which case
+ defender wins; can also be used on non-diplomat units,
+ in which case it can protect cities from diplomats;
+ also 100% spy survival chance
+
+"Unit_Unique" - a player can only have one of these units in the game at
+ the same time; barbarians cannot use this at present
+
+
+
+.range = one of: "None", "Local", "City", "Island", "Player", "World"
+.outside = 1 if, for effects at greater than City-range, the effect
+ is active in all tiles, not just the city center. For tax
+ and science city bonuses, this means that the TOTAL science
+ output of all cities affected is subject to the bonus,
+ rather than the output of each city individually.
+ Applicable effects: Science_Bonus, Science_Pct,
+ Tax_Bonus, Tax_Pct, Unit_Defend, Unit_Attack,
+ Unit_Attack_Firepower, Unit_Defend_Firepower,
+ Unit_Recover, Unit_Vet_Combat, Upgrade_*
+ (if unspecified, 0 (city center only) is assumed)
.amount = integral AMOUNT parameter for many effects
(must be in the range -32767 to 32767)
-.survives = 1 if effect survives destruction (wonders only)
- (if unspecified, 0 (doesn't survive) is assumed)
+.value1 = integral VALUE1 parameter for certain effects
+ (must be in the range -32767 to 32767)
+.value2 = integral VALUE2 parameter for certain effects
+ (must be in the range -32767 to 32767)
.cond_bldg = must have this building in same city for effect
(if unspecified, effect not conditional on building)
.cond_nat = must be this nation for effect
diff -Nur -Xcvs/diff_ignore snap-pre/server/barbarian.c
snap-eff/server/barbarian.c
--- snap-pre/server/barbarian.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/barbarian.c 2004-03-07 17:04:47.000000000 -0600
@@ -113,6 +113,7 @@
/* make a new player */
+ player_init(barbarians); /* need to do this here to init island effects */
server_player_init(barbarians, TRUE);
barbarians->nation = game.nation_count - 1;
diff -Nur -Xcvs/diff_ignore snap-pre/server/citytools.c
snap-eff/server/citytools.c
--- snap-pre/server/citytools.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/citytools.c 2004-03-05 20:44:46.000000000 -0600
@@ -877,7 +877,7 @@
pnew_capital = city_list_get(&pplayer->cities, myrand(size));
- city_add_improvement(pnew_capital, B_PALACE);
+ city_add_improvement(pnew_capital, B_PALACE, TRUE);
/*
* send_player_cities will recalculate all cities and send them to
@@ -1010,10 +1010,15 @@
if (raze)
raze_city(pcity);
- /* Restore any global improvement effects that this city confers */
+ /* Restore any global improvement effects that this city confers
+ * do not add immediate effects as they occurred when the impr was built */
+ effects_defer_update();
built_impr_iterate(pcity, i) {
- city_add_improvement(pcity, i);
+ city_add_improvement(pcity, i, FALSE);
} built_impr_iterate_end;
+ effects_undefer_update();
+ freelog(LOG_VERBOSE, "%%%%%%%%: transfer city"); /* DEBUGGING/REMOVE */
+ effects_update_all();
/* Set production to something valid for pplayer, if not. */
if ((pcity->is_building_unit
@@ -1084,7 +1089,7 @@
if (!pplayer->capital) {
pplayer->capital = TRUE;
- city_add_improvement(pcity, B_PALACE);
+ city_add_improvement(pcity, B_PALACE, TRUE);
}
/* Before arranging workers to show unknown land */
@@ -1181,10 +1186,17 @@
and to handle the preservation of "destroyed" effects. */
effect_update=FALSE;
+ effects_defer_update();
built_impr_iterate(pcity, i) {
effect_update = TRUE;
city_remove_improvement(pcity, i);
} built_impr_iterate_end;
+ effects_undefer_update();
+
+ if (effect_update) {
+ freelog(LOG_VERBOSE, "%%%%%%%%: remove city"); /* DEBUGGING/REMOVE */
+ effects_update_all();
+ }
/* This is cutpasted with modifications from transfer_city_units. Yes, it is
ugly.
But I couldn't see a nice way to make them use the same code */
@@ -1738,13 +1750,7 @@
*p++=get_worker_city(pcity, x, y)+'0';
*p='\0';
- p=packet->improvements;
-
- impr_type_iterate(i) {
- *p++ = (city_got_building(pcity, i)) ? '1' : '0';
- } impr_type_iterate_end;
-
- *p='\0';
+ sz_strlcpy(packet->improvements, pcity->improvements);
}
/**************************************************************************
diff -Nur -Xcvs/diff_ignore snap-pre/server/cityturn.c
snap-eff/server/cityturn.c
--- snap-pre/server/cityturn.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/cityturn.c 2004-03-05 20:44:46.000000000 -0600
@@ -114,6 +114,8 @@
struct player *pplayer = city_owner(pcity);
bool sold = FALSE;
+ effects_defer_update();
+
built_impr_iterate(pcity, i) {
if (!is_wonder(i) && improvement_obsolete(pplayer, i)) {
do_sell_building(pplayer, pcity, i);
@@ -125,6 +127,13 @@
}
} built_impr_iterate_end;
+ effects_undefer_update();
+
+ if (sold) {
+ freelog(LOG_VERBOSE, "%%%%%%%%: removing obsolete"); /* DEBUGGING/REMOVE */
+ effects_update_all();
+ }
+
if (sold && refresh) {
city_refresh(pcity);
send_city_info(pplayer, pcity);
@@ -945,7 +954,7 @@
pplayer->spaceship.modules++;
} else {
space_part = FALSE;
- city_add_improvement(pcity, pcity->currently_building);
+ city_add_improvement(pcity, pcity->currently_building, TRUE);
}
pcity->before_change_shields -=
impr_build_shield_cost(pcity->currently_building);
diff -Nur -Xcvs/diff_ignore snap-pre/server/gamehand.c
snap-eff/server/gamehand.c
--- snap-pre/server/gamehand.c 2003-12-14 18:20:53.000000000 -0600
+++ snap-eff/server/gamehand.c 2004-03-05 20:44:46.000000000 -0600
@@ -17,6 +17,7 @@
#include <assert.h>
+#include "effects.h"
#include "events.h"
#include "fcintl.h"
#include "improvement.h"
@@ -366,3 +367,132 @@
return game.timeout;
}
+
+#include <stdio.h> /* DEBUGGING */
+
+/**************************************************************************
+ check for changes in global effects and send them to the clients
+ if necessary.
+**************************************************************************/
+static void send_global_effect(struct player *pplayer, struct effect *eff,
+ bool add_effect)
+{
+ struct packet_global_effect packet;
+
+ struct effect_defn *defn = &packet.effect_def[0];
+
+ defn->type = eff->defn->type;
+ defn->range = eff->defn->range;
+ defn->amount = eff->defn->amount;
+ defn->value1 = eff->defn->value1;
+ defn->value2 = eff->defn->value2;
+ defn->cond_nat = -1;
+ defn->cond_gov = game.government_count;
+ defn->cond_adv = A_NONE;
+ defn->cond_bldg = eff->defn->cond_bldg;
+ defn->cond_eff = EFT_LAST;
+ defn->aff_terr = eff->defn->aff_terr;
+ defn->aff_spec = eff->defn->aff_spec;
+ defn->aff_unit = eff->defn->aff_unit;
+
+ packet.add_effect = add_effect;
+ packet.player = eff->plr->player_no;
+
+ lsend_packet_global_effect(&pplayer->connections, &packet);
+
+ printf("sending %s (%s)\n", effect_type_name(eff->defn->type),
+ add_effect ? "adding" : "deleting");
+ fflush(stdout); /* DEBUGGING */
+}
+
+/**************************************************************************
+ on game start and reconnnect, send all effects not owned by dest to dest.
+**************************************************************************/
+void send_global_effects(struct conn_list *dest)
+{
+ conn_list_iterate(*dest, pconn) {
+ effect_vector_iterate(game.effects, eff) {
+ if (eff->plr == pconn->player) {
+ continue; /* don't send effects that the player knows about */
+ }
+
+ /* make sure the client only has one copy of this one */
+ send_global_effect(pconn->player, eff, FALSE);
+ send_global_effect(pconn->player, eff, TRUE);
+ } effect_vector_iterate_end;
+ } conn_list_iterate_end;
+}
+
+/**************************************************************************
+ The server needs to do more on delete.
+
+ We need to make sure that the client is informed of changes to the
+ global effects vector.
+**************************************************************************/
+void delete_effects(enum effect_class class, struct player *pplayer,
+ struct city *pcity, struct unit *punit, int id)
+{
+ struct effect_vector temp;
+ struct conn_list dest;
+
+ conn_list_init(&dest);
+
+ /* put the current vector of global effects in a safe place. */
+ effect_vector_init(&temp);
+ effect_vector_copy(&temp, &game.effects);
+
+ delete_effects_common(class, pplayer, pcity, punit, id);
+
+ /* check if any effects in temp are missing in game.effects */
+ effect_vector_iterate(temp, eff) {
+ effect_vector_iterate(game.effects, eff2) {
+ if (eff->defn == eff2->defn && eff->plr == eff2->plr &&
+ eff->home == eff2->home && eff->id == eff2->id) {
+ goto endloop;
+ }
+ } effect_vector_iterate_end;
+
+ /* we found an eff which isn't in game.effects any longer */
+ players_iterate(pplayer) {
+ if (eff->plr == pplayer) {
+ continue; /* don't send effects that the player knows about */
+ }
+
+ send_global_effect(pplayer, eff, FALSE);
+ } players_iterate_end;
+
+ endloop:;
+ } effect_vector_iterate_end;
+
+ effects_update_all();
+
+ effect_vector_free(&temp);
+ conn_list_unlink_all(&dest);
+}
+
+/**************************************************************************
+ check for changes in global effects and send them to the clients
+ if necessary.
+**************************************************************************/
+void effects_update_all(void)
+{
+ struct conn_list dest;
+
+ conn_list_init(&dest);
+
+ effects_update_all_common();
+
+ effect_vector_iterate(game.effects, eff) {
+ if (eff->has.changed) {
+ players_iterate(pplayer) {
+ if (eff->plr == pplayer) {
+ continue; /* don't send effects that the player knows about */
+ }
+
+ send_global_effect(pplayer, eff, is_effect_emitting(eff, NULL));
+ } players_iterate_end;
+ }
+ } effect_vector_iterate_end;
+
+ conn_list_unlink_all(&dest);
+}
diff -Nur -Xcvs/diff_ignore snap-pre/server/gamehand.h
snap-eff/server/gamehand.h
--- snap-pre/server/gamehand.h 2002-04-25 20:36:31.000000000 -0500
+++ snap-eff/server/gamehand.h 2004-03-05 20:44:46.000000000 -0600
@@ -23,5 +23,6 @@
void send_start_turn_to_clients(void);
int update_timeout(void);
+void send_global_effects(struct conn_list *dest);
#endif /* FC__GAMEHAND_H */
diff -Nur -Xcvs/diff_ignore snap-pre/server/maphand.c snap-eff/server/maphand.c
--- snap-pre/server/maphand.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/maphand.c 2004-03-05 20:44:46.000000000 -0600
@@ -17,9 +17,11 @@
#include <assert.h>
+#include "effects.h"
#include "events.h"
#include "fcintl.h"
#include "game.h"
+#include "improvement.h"
#include "log.h"
#include "map.h"
#include "mem.h"
@@ -1421,6 +1423,7 @@
map_set_continent(x, y, ++map.num_continents);
allot_island_improvs();
+ allot_island_effects();
} else {
/* set the tile to something adjacent to it */
map_set_continent(x, y, con);
@@ -1452,6 +1455,8 @@
assign_continent_numbers();
allot_island_improvs();
+ allot_island_effects();
+ allot_island_effects();
send_all_known_tiles(NULL);
}
diff -Nur -Xcvs/diff_ignore snap-pre/server/plrhand.c snap-eff/server/plrhand.c
--- snap-pre/server/plrhand.c 2004-02-22 11:12:06.000000000 -0600
+++ snap-eff/server/plrhand.c 2004-03-07 20:12:51.441764507 -0600
@@ -320,7 +320,7 @@
bonus_tech_hack = TRUE;
}
- set_invention(plr, tech_found, TECH_KNOWN);
+ set_invention(plr, tech_found, TECH_KNOWN, TRUE);
update_research(plr);
remove_obsolete_buildings(plr);
if (tech_flag(tech_found,TF_RAILROAD)) {
@@ -636,9 +636,9 @@
struct nation_type *nation = get_nation_by_plr(plr);
tech_type_iterate(i) {
- set_invention(plr, i, TECH_UNKNOWN);
+ set_invention(plr, i, TECH_UNKNOWN, FALSE);
} tech_type_iterate_end;
- set_invention(plr, A_NONE, TECH_KNOWN);
+ set_invention(plr, A_NONE, TECH_KNOWN, TRUE);
plr->research.techs_researched = 1;
@@ -649,7 +649,7 @@
if (game.rgame.global_init_techs[i] == A_LAST) {
break;
}
- set_invention(plr, game.rgame.global_init_techs[i], TECH_KNOWN);
+ set_invention(plr, game.rgame.global_init_techs[i], TECH_KNOWN, TRUE);
}
/*
@@ -659,13 +659,13 @@
if (nation->init_techs[i] == A_LAST) {
break;
}
- set_invention(plr, nation->init_techs[i], TECH_KNOWN);
+ set_invention(plr, nation->init_techs[i], TECH_KNOWN, TRUE);
}
for (i = 0; i < tech; i++) {
update_research(plr);
choose_random_tech(plr); /* could be choose_goal_tech -- Syela */
- set_invention(plr, plr->research.researching, TECH_KNOWN);
+ set_invention(plr, plr->research.researching, TECH_KNOWN, TRUE);
}
/* Mark the reachable techs */
@@ -843,7 +843,11 @@
return;
}
+ /* remove current government effects and add the new ones... */
+ delete_effects(EFC_GOVERNMENT, pplayer, NULL, NULL, pplayer->government);
pplayer->government = government;
+ add_government_effects(pplayer, TRUE);
+
notify_player(pplayer, _("Game: %s now governs the %s as a %s."),
pplayer->name,
get_nation_name_plural(pplayer->nation),
@@ -881,7 +885,13 @@
} else {
pplayer->revolution = game.revolution_length;
}
- pplayer->government=game.government_when_anarchy;
+
+ /* remove current government effects and add the new ones... */
+ delete_effects(EFC_GOVERNMENT, pplayer, NULL, NULL, pplayer->government);
+
+ pplayer->government = game.government_when_anarchy;
+ add_government_effects(pplayer, TRUE);
+
notify_player_ex(pplayer, -1, -1, E_REVOLT_START,
_("Game: The %s have incited a revolt!"),
get_nation_name_plural(pplayer->nation));
@@ -1711,6 +1721,7 @@
Nation_Type_id *civilwar_nations = get_nation_civilwar(pplayer->nation);
/* make a new player */
+ player_init(cplayer);
server_player_init(cplayer, TRUE);
ai_data_init(cplayer);
diff -Nur -Xcvs/diff_ignore snap-pre/server/ruleset.c snap-eff/server/ruleset.c
--- snap-pre/server/ruleset.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/ruleset.c 2004-03-05 20:55:02.000000000 -0600
@@ -22,9 +22,11 @@
#include "capability.h"
#include "city.h"
+#include "effects.h"
#include "fcintl.h"
#include "game.h"
#include "government.h"
+#include "improvement.h"
#include "log.h"
#include "map.h"
#include "mem.h"
@@ -102,6 +104,10 @@
static void send_ruleset_cities(struct conn_list *dest);
static void send_ruleset_game(struct conn_list *dest);
+static void fill_effect_defs(struct section_file *file, char *sec, char *name,
+ struct effect_defn_vector *vec, int count,
+ enum effect_class class);
+
/**************************************************************************
datafilename() wrapper: tries to match in two ways.
Returns NULL on failure, the (statically allocated) filename on success.
@@ -495,7 +501,7 @@
char **sec;
struct advance *a;
int num_techs; /* number of techs in the ruleset (means without A_NONE)*/
- int i;
+ int i, count;
const char *filename = secfile_filename(file);
(void) check_ruleset_capabilities(file, "+1.9", filename);
@@ -506,6 +512,7 @@
advances[A_NONE].req[1] = A_NONE;
advances[A_NONE].flags = 0;
advances[A_NONE].root_req = A_LAST;
+ effect_defn_vector_init(&advances[A_NONE].effect_defs);
a = &advances[A_FIRST];
@@ -560,6 +567,15 @@
secfile_lookup_int_default(file, -1, "%s.%s", sec[i], "cost");
a->num_reqs = 0;
+ /* do effect definitions */
+ for (count = 0; secfile_lookup_str_default(file, NULL, "%s.effect%d.type",
+ sec[i], count); count++) {
+ /* nothing */
+ }
+
+ fill_effect_defs(file, sec[i], a->name, &a->effect_defs, count,
+ EFC_TECH);
+
a++;
}
@@ -672,7 +688,7 @@
static void load_ruleset_units(struct section_file *file)
{
struct unit_type *u;
- int i, j, ival, nval, vet_levels, vet_levels_default;
+ int i, j, ival, nval, count, vet_levels, vet_levels_default;
char *sval, **slist, **sec;
const char *filename = secfile_filename(file);
char **vnlist, **def_vnlist;
@@ -891,6 +907,15 @@
}
u->fuel = secfile_lookup_int(file,"%s.fuel", sec[i]);
+ /* do effect definitions */
+ for (count = 0; secfile_lookup_str_default(file, NULL, "%s.effect%d.type",
+ sec[i], count); count++) {
+ /* nothing */
+ }
+
+ fill_effect_defs(file, sec[i], u->name, &u->effect_defs, count,
+ EFC_UNIT);
+
u->happy_cost = secfile_lookup_int(file, "%s.uk_happy", sec[i]);
u->shield_cost = secfile_lookup_int(file, "%s.uk_shield", sec[i]);
u->food_cost = secfile_lookup_int(file, "%s.uk_food", sec[i]);
@@ -960,6 +985,7 @@
lookup_tech_list(file, "u_specials", "partisan_req",
game.rtech.partisan_req, filename);
+
/* Some more consistency checking: */
unit_type_iterate(i) {
if (unit_type_exists(i)) {
@@ -1116,9 +1142,7 @@
{
char **sec, *item, **list;
int i, j, k, nval, count;
- bool problem;
struct impr_type *b;
- struct impr_effect *e;
const char *filename = secfile_filename(file);
(void) check_ruleset_capabilities(file, "+1.10.1", filename);
@@ -1225,164 +1249,14 @@
b->sabotage = secfile_lookup_int(file, "%s.sabotage", sec[i]);
- for (count = 0;
- secfile_lookup_str_default(file, NULL, "%s.effect%d.type", sec[i],
- count); count++) {
+ /* do effect definitions */
+ for (count = 0; secfile_lookup_str_default(file, NULL, "%s.effect%d.type",
+ sec[i], count); count++) {
/* nothing */
}
- if (count>MAX_EFFECTS) {
- freelog(LOG_FATAL, "For %s maximum number of effects (%d) exceeded",
- b->name, MAX_EFFECTS);
- exit(EXIT_FAILURE);
- }
-
- b->effect = fc_malloc((count + 1) * sizeof(b->effect[0]));
- k = 0;
- for (j = 0; j < count; j++) {
- e = &b->effect[k];
- problem = FALSE;
-
- item = secfile_lookup_str(file, "%s.effect%d.type", sec[i], j);
- e->type = effect_type_from_str(item);
- if (e->type == EFT_LAST) {
- freelog(LOG_ERROR,
- "for %s effect[%d].type couldn't match type \"%s\" (%s)",
- b->name, j, item, filename);
- problem = TRUE;
- }
-
- item =
- secfile_lookup_str_default(file, "None", "%s.effect%d.range", sec[i],
j);
- e->range = effect_range_from_str(item);
- if (e->range == EFR_LAST) {
- freelog(LOG_ERROR,
- "for %s effect[%d].range couldn't match range \"%s\" (%s)",
- b->name, j, item, filename);
- problem = TRUE;
- }
-
- e->amount =
- secfile_lookup_int_default(file, 0, "%s.effect%d.amount", sec[i], j);
-
- e->survives =
- secfile_lookup_int_default(file, 0, "%s.effect%d.survives", sec[i], j);
-
- item =
- secfile_lookup_str_default(file, "", "%s.effect%d.cond_bldg", sec[i],
j);
- if (*item != '\0') {
- e->cond_bldg = find_improvement_by_name(item);
- if (e->cond_bldg == B_LAST) {
- freelog(LOG_ERROR,
- "for %s effect[%d].cond_bldg couldn't match improvement
\"%s\" (%s)",
- b->name, j, item, filename);
- problem = TRUE;
- }
- } else {
- e->cond_bldg = B_LAST;
- }
-
- item =
- secfile_lookup_str_default(file, "", "%s.effect%d.cond_gov", sec[i], j);
- if (*item != '\0') {
- struct government *g = find_government_by_name(item);
- if (!g) {
- freelog(LOG_ERROR,
- "for %s effect[%d].cond_gov couldn't match government \"%s\"
(%s)",
- b->name, j, item, filename);
- e->cond_gov = game.government_count;
- problem = TRUE;
- } else {
- e->cond_gov = g->index;
- }
- } else {
- e->cond_gov = game.government_count;
- }
-
- item =
- secfile_lookup_str_default(file, "None", "%s.effect%d.cond_adv",
sec[i], j);
- if (*item != '\0') {
- e->cond_adv = find_tech_by_name(item);
- if (e->cond_adv == A_LAST) {
- freelog(LOG_ERROR,
- "for %s effect[%d].cond_adv couldn't match tech \"%s\" (%s)",
- b->name, j, item, filename);
- problem = TRUE;
- }
- } else {
- e->cond_adv = A_NONE;
- }
-
- item =
- secfile_lookup_str_default(file, "", "%s.effect%d.cond_eff", sec[i], j);
- if (*item != '\0') {
- e->cond_eff = effect_type_from_str(item);
- if (e->cond_eff == EFT_LAST) {
- freelog(LOG_ERROR,
- "for %s effect[%d].cond_eff couldn't match effect \"%s\"
(%s)",
- b->name, j, item, filename);
- problem = TRUE;
- }
- } else {
- e->cond_eff = EFT_LAST;
- }
-
- item =
- secfile_lookup_str_default(file, "", "%s.effect%d.aff_unit", sec[i], j);
- if (*item != '\0') {
- e->aff_unit = unit_class_from_str(item);
- if (e->aff_unit == UCL_LAST) {
- freelog(LOG_ERROR,
- "for %s effect[%d].aff_unit couldn't match class \"%s\" (%s)",
- b->name, j, item, filename);
- problem = TRUE;
- }
- } else {
- e->aff_unit = UCL_LAST;
- }
-
- item =
- secfile_lookup_str_default(file, "", "%s.effect%d.aff_terr", sec[i], j);
- if (*item != '\0') {
- if (0 == strcmp("None", item)) {
- e->aff_terr = T_LAST;
- } else {
- e->aff_terr = get_terrain_by_name(item);
- if (e->aff_terr >= T_UNKNOWN) {
- freelog(LOG_ERROR,
- "for %s effect[%d].aff_terr couldn't match terrain \"%s\"
(%s)",
- b->name, j, item, filename);
- e->aff_terr = T_LAST;
- problem = TRUE;
- }
- }
- } else {
- e->aff_terr = T_UNKNOWN;
- }
-
- item =
- secfile_lookup_str_default(file, "", "%s.effect%d.aff_spec", sec[i], j);
- if (*item != '\0') {
- if (0 == strcmp("None", item)) {
- e->aff_spec = S_NO_SPECIAL;
- } else {
- e->aff_spec = get_special_by_name(item);
- if (e->aff_spec == S_NO_SPECIAL) {
- freelog(LOG_ERROR,
- "for %s effect[%d].aff_spec couldn't match special \"%s\"
(%s)",
- b->name, j, item, filename);
- problem = TRUE;
- }
- }
- } else {
- e->aff_spec = S_ALL;
- }
-
- if (!problem) {
- k++;
- }
- }
- b->effect[k].type = EFT_LAST;
+ fill_effect_defs(file, sec[i], b->name, &b->effect_defs, count,
+ EFC_IMPROVEMENT);
/* FIXME: remove when gen-impr obsoletes */
b->variant = secfile_lookup_int_default(file, 0, "%s.variant", sec[i]);
@@ -1417,15 +1291,15 @@
b->name, advances[b->obsolete_by].name, filename);
b->obsolete_by = A_LAST;
}
- for (j = 0; b->effect[j].type != EFT_LAST; j++) {
- if (!tech_exists(b->effect[j].cond_adv)) {
+ effect_defn_vector_iterate(b->effect_defs, defn) {
+ if (!tech_exists(defn->cond_adv)) {
freelog(LOG_ERROR,
"improvement \"%s\": effect conditional on"
" removed tech \"%s\" (%s)",
- b->name, advances[b->effect[j].cond_adv].name, filename);
- b->effect[j].cond_adv = A_LAST;
+ b->name, advances[defn->cond_adv].name, filename);
+ defn->cond_adv = A_LAST;
}
- }
+ } effect_defn_vector_iterate_end;
}
} impr_type_iterate_end;
@@ -1912,6 +1786,20 @@
ai_gov_tech_hints[j].tech = A_LAST;
}
+ /* effect definitions */
+ government_iterate(g) {
+ int i = g->index;
+ int count;
+
+ for (count = 0; secfile_lookup_str_default(file, NULL, "%s.effect%d.type",
+ sec[i], count); count++) {
+ /* nothing */
+ }
+
+ fill_effect_defs(file, sec[i], g->name, &g->effect_defs, count,
+ EFC_GOVERNMENT);
+ } government_iterate_end;
+
free(sec);
section_file_check_unused(file, filename);
section_file_free(file);
@@ -2182,7 +2070,7 @@
char *bad_leader, *g;
struct nation_type *pl;
struct government *gov;
- int dim, val, i, j, k, nval;
+ int dim, val, i, j, k, nval, count;
char temp_name[MAX_LEN_NAME];
char **techs, **leaders, **sec, **civilwar_nations;
const char *filename = secfile_filename(file);
@@ -2413,6 +2301,15 @@
pl->city_names = load_city_name_list(file, sec[i], ".cities");
+ /* effect definitions */
+ for (count = 0; secfile_lookup_str_default(file, NULL, "%s.effect%d.type",
+ sec[i], count); count++) {
+ /* nothing */
+ }
+
+ fill_effect_defs(file, sec[i], pl->name, &pl->effect_defs, count,
+ EFC_NATION);
+
/* class and legend */
pl->class =
@@ -2707,6 +2604,9 @@
packet.helptext[0] = '\0';
}
+ effect_defn_vector_to_array(&u->effect_defs, packet.effect_defs,
+ &packet.effect_defs_count);
+
lsend_packet_ruleset_unit(dest, &packet);
} unit_type_iterate_end;
}
@@ -2738,6 +2638,9 @@
packet.helptext[0] = '\0';
}
+ effect_defn_vector_to_array(&a->effect_defs, packet.effect_defs,
+ &packet.effect_defs_count);
+
lsend_packet_ruleset_tech(dest, &packet);
} tech_type_iterate_end;
}
@@ -2748,10 +2651,10 @@
**************************************************************************/
static void send_ruleset_buildings(struct conn_list *dest)
{
+
impr_type_iterate(i) {
struct impr_type *b = &improvement_types[i];
struct packet_ruleset_building packet;
- struct impr_effect *eff;
packet.id = i;
sz_strlcpy(packet.name, b->name_orig);
@@ -2786,11 +2689,8 @@
T(equiv_repl, equiv_repl_count, B_LAST);
#undef T
- packet.effect_count = 0;
- for (eff = b->effect; eff->type != EFT_LAST; eff++) {
- packet.effect[packet.effect_count] = *eff;
- packet.effect_count++;
- }
+ effect_defn_vector_to_array(&b->effect_defs, packet.effect_defs,
+ &packet.effect_defs_count);
lsend_packet_ruleset_building(dest, &packet);
} impr_type_iterate_end;
@@ -2941,6 +2841,9 @@
} else {
gov.helptext[0] = '\0';
}
+
+ effect_defn_vector_to_array(&g->effect_defs, gov.effect_defs,
+ &gov.effect_defs_count);
lsend_packet_ruleset_government(dest, &gov);
@@ -2965,15 +2868,16 @@
**************************************************************************/
static void send_ruleset_nations(struct conn_list *dest)
{
- struct packet_ruleset_nation packet;
- struct nation_type *n;
- int i, k;
+ int k;
+
+ for (k = 0; k < game.nation_count; k++) {
+ struct nation_type *n = get_nation_by_idx(k);
+ struct packet_ruleset_nation packet;
+ int i;
- assert(sizeof(packet.init_techs) == sizeof(n->init_techs));
- assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n->init_techs));
+ assert(sizeof(packet.init_techs) == sizeof(n->init_techs));
+ assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n->init_techs));
- for( k=0; k<game.nation_count; k++) {
- n = get_nation_by_idx(k);
packet.id = k;
sz_strlcpy(packet.name, n->name_orig);
sz_strlcpy(packet.name_plural, n->name_plural_orig);
@@ -2989,6 +2893,9 @@
sz_strlcpy(packet.class, n->class);
sz_strlcpy(packet.legend, n->legend);
+ effect_defn_vector_to_array(&n->effect_defs, packet.effect_defs,
+ &packet.effect_defs_count);
+
lsend_packet_ruleset_nation(dest, &packet);
}
}
@@ -3119,3 +3026,191 @@
lsend_packet_thaw_hint(dest);
conn_list_do_unbuffer(dest);
}
+
+/**************************************************************************
+ initialize an effect_defn_vector and fill it with all definitions in
+ section 'sec'
+**************************************************************************/
+static void fill_effect_defs(struct section_file *file, char *sec, char *name,
+ struct effect_defn_vector *vec, int count,
+ enum effect_class class)
+{
+ int j;
+ char *item;
+ const char *filename = secfile_filename(file);
+
+ /* initialize list */
+ effect_defn_vector_init(vec);
+ effect_defn_vector_reserve(vec, count);
+
+ for (j = 0; j < count; j++) {
+ struct effect_defn *defn = effect_defn_vector_get(vec, j);
+
+ /* lookup type */
+ item = secfile_lookup_str(file, "%s.effect%d.type", sec, j);
+ defn->type = effect_type_from_str(item);
+ if (defn->type == EFT_LAST) {
+ freelog(LOG_ERROR,
+ "for %s effect[%d].type couldn't match type \"%s\" (%s)",
+ name, j, item, filename);
+ }
+
+ /* lookup range */
+ item = secfile_lookup_str_default(file,
+ class == EFC_UNIT ? "Local": "None",
+ "%s.effect%d.range", sec, j);
+ defn->range = effect_range_from_str(item);
+
+ if (defn->range == EFR_LAST) {
+ freelog(LOG_ERROR,
+ "for %s effect[%d].range couldn't match range \"%s\" (%s)",
+ name, j, item, filename);
+ }
+
+ /* nation, government and tech effects are homeless and must be Player
+ * or World ranged. */
+ if (class > EFC_IMPROVEMENT && defn->range < EFR_PLAYER) {
+ freelog(LOG_ERROR,
+ "for %s effect[%d].range: range \"%s\" is not allowed. "
+ "Setting to \"Player\" range. (%s)",
+ name, j, item, filename);
+ defn->range = EFR_PLAYER;
+ }
+
+ /* unit effects must be Local ranged */
+ if (class == EFC_UNIT && defn->range != EFR_LOCAL) {
+ freelog(LOG_ERROR,
+ "for %s effect[%d].range: range \"%s\" is not allowed. "
+ "Setting to \"Local\" range. (%s)",
+ name, j, item, filename);
+ defn->range = EFR_LOCAL;
+ }
+
+ /* lookup "outside" */
+ defn->outside = secfile_lookup_bool_default(file, 0, "%s.effect%d.outside",
+ sec, j);
+
+ /* lookup amount and auxillary amounts */
+ defn->amount = secfile_lookup_int_default(file, 0, "%s.effect%d.amount",
+ sec, j);
+ defn->value1 = secfile_lookup_int_default(file, 0, "%s.effect%d.value1",
+ sec, j);
+ defn->value2 = secfile_lookup_int_default(file, 0, "%s.effect%d.value2",
+ sec, j);
+
+ /* lookup cond_bldg */
+ item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_bldg",
+ sec, j);
+ if (*item != '\0') {
+ defn->cond_bldg = find_improvement_by_name(item);
+ if (defn->cond_bldg == B_LAST) {
+ freelog(LOG_ERROR, "for %s effect[%d].cond_bldg couldn't match "
+ "improvement \"%s\" (%s)", name, j, item, filename);
+ }
+ } else {
+ defn->cond_bldg = B_LAST;
+ }
+
+ /* lookup cond_nat */
+ item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_nat", sec,
j);
+ if (*item != '\0') {
+ int n = find_nation_by_name(item);
+
+ if (n == -1) {
+ freelog(LOG_ERROR, "for %s effect[%d].cond_nat couldn't match "
+ "nation \"%s\" (%s)", name, j, item, filename);
+ defn->cond_nat = -1;
+ } else {
+ defn->cond_nat = n;
+ }
+ } else {
+ defn->cond_nat = -1;
+ }
+
+ /* lookup cond_gov */
+ item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_gov", sec,
j);
+ if (*item != '\0') {
+ struct government *g = find_government_by_name(item);
+
+ if (!g) {
+ freelog(LOG_ERROR, "for %s effect[%d].cond_gov couldn't match "
+ "government \"%s\" (%s)", name, j, item, filename);
+ defn->cond_gov = game.government_count;
+ } else {
+ defn->cond_gov = g->index;
+ }
+ } else {
+ defn->cond_gov = game.government_count;
+ }
+
+ /* lookup cond_adv */
+ item = secfile_lookup_str_default(file, "None", "%s.effect%d.cond_adv",
+ sec, j);
+ if (*item != '\0') {
+ defn->cond_adv = find_tech_by_name(item);
+ if (defn->cond_adv == A_LAST) {
+ freelog(LOG_ERROR, "for %s effect[%d].cond_adv couldn't match "
+ "tech \"%s\" (%s)", name, j, item, filename);
+ }
+ } else {
+ defn->cond_adv = A_NONE;
+ }
+
+ /* lookup cond_eff */
+ item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_eff", sec,
j);
+ if (*item != '\0') {
+ defn->cond_eff = effect_type_from_str(item);
+ if (defn->cond_eff == EFT_LAST) {
+ freelog(LOG_ERROR, "for %s effect[%d].cond_eff couldn't match "
+ "effect \"%s\" (%s)", name, j, item, filename);
+ }
+ } else {
+ defn->cond_eff = EFT_LAST;
+ }
+
+ /* lookup aff_unit */
+ item = secfile_lookup_str_default(file, "", "%s.effect%d.aff_unit", sec,
j);
+ if (*item != '\0') {
+ defn->aff_unit = unit_class_from_str(item);
+ if (defn->aff_unit == UCL_LAST) {
+ freelog(LOG_ERROR, "for %s effect[%d].aff_unit couldn't match "
+ "class \"%s\" (%s)", name, j, item, filename);
+ }
+ } else {
+ defn->aff_unit = UCL_LAST;
+ }
+
+ /* lookup aff_terr */
+ item = secfile_lookup_str_default(file, "", "%s.effect%d.aff_terr", sec,
j);
+ if (*item != '\0') {
+ if (0 == strcmp("None", item)) {
+ defn->aff_terr = T_LAST;
+ } else {
+ defn->aff_terr = get_terrain_by_name(item);
+ if (defn->aff_terr >= T_UNKNOWN) {
+ freelog(LOG_ERROR, "for %s effect[%d].aff_terr couldn't match "
+ "terrain \"%s\" (%s)", name, j, item, filename);
+ defn->aff_terr = T_LAST;
+ }
+ }
+ } else {
+ defn->aff_terr = T_UNKNOWN;
+ }
+
+ /* lookup aff_spec */
+ item = secfile_lookup_str_default(file, "", "%s.effect%d.aff_spec", sec,
j);
+ if (*item != '\0') {
+ if (0 == strcmp("None", item)) {
+ defn->aff_spec = S_NO_SPECIAL;
+ } else {
+ defn->aff_spec = get_special_by_name(item);
+ if (defn->aff_spec == S_NO_SPECIAL) {
+ freelog(LOG_ERROR, "for %s effect[%d].aff_spec couldn't match "
+ "special \"%s\" (%s)", name, j, item, filename);
+ }
+ }
+ } else {
+ defn->aff_spec = S_ALL;
+ }
+ }
+}
diff -Nur -Xcvs/diff_ignore snap-pre/server/savegame.c
snap-eff/server/savegame.c
--- snap-pre/server/savegame.c 2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/server/savegame.c 2004-03-05 20:44:46.000000000 -0600
@@ -22,9 +22,12 @@
#include "capability.h"
#include "city.h"
+#include "effects.h"
#include "fcintl.h"
#include "game.h"
+#include "government.h"
#include "idex.h"
+#include "improvement.h"
#include "log.h"
#include "map.h"
#include "mem.h"
@@ -663,6 +666,12 @@
/* Add techs from game and nation, but ignore game.tech. */
init_tech(plr, 0);
+ /* FIXME: right now barbarians don't have effects */
+ if (!is_barbarian(plr)) {
+ /* add nation effects */
+ add_nation_effects(plr, FALSE);
+ }
+
/* not all players have teams */
if (section_file_lookup(file, "player%d.team", plrno)) {
char tmp[MAX_LEN_NAME];
@@ -677,6 +686,10 @@
plr->nation=game.nation_count-1;
}
plr->government=secfile_lookup_int(file, "player%d.government", plrno);
+
+ /* add government effects */
+ add_government_effects(plr, FALSE);
+
plr->embassy=secfile_lookup_int(file, "player%d.embassy", plrno);
p = secfile_lookup_str_default(file, NULL, "player%d.city_style_by_name",
@@ -773,9 +786,7 @@
"player%d.can_space", plrno);
tech_type_iterate(i) {
- if (p[i] == '1') {
- set_invention(plr, i, TECH_KNOWN);
- }
+ set_invention(plr, i, (p[i]=='1') ? TECH_KNOWN : TECH_UNKNOWN, FALSE);
} tech_type_iterate_end;
update_research(plr);
@@ -1023,9 +1034,13 @@
improvement_status_init(pcity->improvements,
ARRAY_SIZE(pcity->improvements));
+ /* Initialise city's list improvement effects. */
+ effect_vector_init(&pcity->effects);
+ effect_vector_init(&pcity->impr_effects);
+
impr_type_iterate(x) {
if (*p != '\0' && *p++=='1') {
- city_add_improvement(pcity,x);
+ city_add_improvement(pcity, x, FALSE);
}
} impr_type_iterate_end;
@@ -1694,7 +1709,9 @@
impr_type_iterate(id) {
buf[id] = (pcity->improvements[id] != I_NONE) ? '1' : '0';
} impr_type_iterate_end;
+
buf[game.num_impr_types] = '\0';
+
secfile_insert_str(file, buf, "player%d.c%d.improvements", plrno, i);
worklist_save(file, "player%d.c%d", plrno, i, &pcity->worklist);
@@ -2255,6 +2272,10 @@
/* This is done after continents are assigned, but before effects
* are added. */
allot_island_improvs();
+ allot_island_effects();
+
+ /* lots of effects are going to get added real-soon-now */
+ effects_defer_update();
for(i=0; i<game.nplayers; i++) {
player_load(&game.players[i], i, file);
@@ -2310,6 +2331,10 @@
check_city(pcity);
} city_list_iterate_end;
} players_iterate_end;
+
+ /* update effects */
+ effects_undefer_update();
+ effects_update_all();
} else {
game.nplayers = 0;
}
diff -Nur -Xcvs/diff_ignore snap-pre/server/srv_main.c
snap-eff/server/srv_main.c
--- snap-pre/server/srv_main.c 2004-02-22 11:12:07.000000000 -0600
+++ snap-eff/server/srv_main.c 2004-03-05 20:44:46.000000000 -0600
@@ -295,6 +295,7 @@
send_all_known_cities(dest);
send_all_known_units(dest);
send_player_turn_notifications(dest);
+ send_global_effects(dest);
}
/**************************************************************************
@@ -469,6 +470,47 @@
send_player_cities(pplayer);
} players_iterate_end;
+#ifdef DEBUG /* DEBUGGING FIXME: remove when commiting the effects patch */
+ players_iterate(pplayer) {
+ freelog(LOG_DEBUG, "%s:\n--------------------------------", pplayer->name);
+ city_list_iterate(pplayer->cities, pcity) {
+#if 0
+ freelog(LOG_DEBUG, " %s feels...", pcity->name);
+ city_effects_iterate(pcity, EFT_ALL, eff) {
+ freelog(LOG_DEBUG, " c: %s i: %d r: %s n: %s",
+ (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+ } city_effects_iterate_end;
+#endif
+#if 0
+{
+ int _iter;
+ struct effect *eff;
+ for (_iter = 0; _iter < effect_vector_size(&pcity->impr_effects); _iter++) {
+ eff = effect_vector_get(&pcity->impr_effects, _iter);
+ freelog(LOG_DEBUG, " c: %s i: %d r: %s n: %s",
+ (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type));
+ }
+}
+#endif
+#if 0
+ built_impr_iterate(pcity, id) {
+ freelog(LOG_DEBUG, " %d's local effects ...", id);
+ improvement_effects_iterate(pcity, id, EFT_ALL, eff) {
+ printf(" c: %s i: %d r: %s n: %s",
+ (eff->home) ? eff->home->name : "(homeless)",
+ eff->id, effect_range_name(eff->defn->range),
+ effect_type_name(eff->defn->type)); fflush(stdout);
+ } improvement_effects_iterate_end;
+ } built_impr_iterate_end;
+#endif
+ } city_list_iterate_end;
+ } players_iterate_end;
+#endif
+
flush_packets(); /* to curb major city spam */
conn_list_do_unbuffer(&game.game_connections);
@@ -1631,11 +1673,13 @@
server_state = RUN_GAME_STATE;
(void) send_server_info_to_metaserver(TRUE, FALSE);
+ effects_defer_update();
if(game.is_new_game) {
/* Before the player map is allocated (and initiailized)! */
game.fogofwar_old = game.fogofwar;
allot_island_improvs();
+ allot_island_effects();
players_iterate(pplayer) {
player_map_allocate(pplayer);
@@ -1652,6 +1696,15 @@
}
}
+ /* add nation and government effects; add immed. effects if new game */
+ players_iterate(pplayer) {
+ add_nation_effects(pplayer, game.is_new_game);
+ add_government_effects(pplayer, game.is_new_game);
+ } players_iterate_end;
+ effects_undefer_update();
+ freelog(LOG_VERBOSE, "%%%%%%%%: srv_main nat/gov effects"); /*
DEBUGGING/REMOVE */
+ effects_update_all();
+
/* Set up alliances based on team selections */
if (game.is_new_game) {
players_iterate(pplayer) {
diff -Nur -Xcvs/diff_ignore snap-eff/common/effects.c snap-imm/common/effects.c
--- snap-eff/common/effects.c 2004-03-07 12:03:32.000000000 -0600
+++ snap-imm/common/effects.c 2004-03-07 17:13:22.000000000 -0600
@@ -192,8 +192,6 @@
switch (defn->type) {
case EFT_GIVE_IMM_ADV:
case EFT_IMPROVE_REP:
- case EFT_REVEAL_CITIES: /* this could be a continuing effect, anyone? */
- case EFT_REVEAL_MAP:
case EFT_ENABLE_NUKE: /* these two effects are only immediate in that */
case EFT_ENABLE_SPACE: /* they flip bits which stay around */
return TRUE;
@@ -310,13 +308,13 @@
}
}
-/******************************************************************
+/*******************************************************************
if pcity is non-NULL, global, player, and island ranges will return for
their effect in that city and city and local ranges will be check in that
city only.
if id is not B_LAST, then all of the above applies and only id's effects in
the city are iterated through. If id is specified, pcity must also be.
-
+
*******************************************************************/
void effect_iterator_init(struct effect_iter *iter, struct player *pplayer,
struct city *pcity, struct unit *punit,
@@ -1168,7 +1166,7 @@
&& (!pcity || _eff->home == pcity) \
&& (id == B_LAST || _eff->id == id)) { \
freelog(LOG_DEBUG, "deleted effect p: %s, c: %s i: %d n: %s", \
- pplayer->name, (pcity) ? pcity->name : "(homeless)", \
+ _eff->plr->name, (pcity) ? pcity->name : "(homeless)", \
id, effect_type_name(defn->type)); \
memcpy(_eff, effect_vector_get(&(eff_list), size - 1), \
sizeof(struct effect)); \
diff -Nur -Xcvs/diff_ignore snap-eff/common/improvement.c
snap-imm/common/improvement.c
--- snap-eff/common/improvement.c 2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/common/improvement.c 2004-03-07 17:13:22.000000000 -0600
@@ -365,20 +365,13 @@
effect_defn_vector_iterate(impr->effect_defs, defn) {
/* is this improvement considered a space part? */
if (defn->type == EFT_SPACE_PART) {
- bool space_enabled = FALSE;
-
/* if spaceship is already launched, can't build it */
if (p->spaceship.state >= SSHIP_LAUNCHED) {
return FALSE;
}
/* we can't build it though unless we feel the "Enable_Space" effect */
- player_effects_iterate(p, EFT_ENABLE_SPACE, eff) {
- space_enabled = TRUE;
- break;
- } player_effects_iterate_end;
-
- if (!space_enabled) {
+ if (!p->can_space) {
return FALSE;
}
diff -Nur -Xcvs/diff_ignore snap-eff/common/unittype.c
snap-imm/common/unittype.c
--- snap-eff/common/unittype.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-imm/common/unittype.c 2004-03-07 17:13:22.000000000 -0600
@@ -444,8 +444,9 @@
if (!unit_type_exists(id))
return FALSE;
- if (unit_type_flag(id, F_NUCLEAR) && game.global_wonders[B_MANHATTEN] == 0)
+ if (unit_type_flag(id, F_NUCLEAR) && !p->can_nuke) {
return FALSE;
+ }
if (unit_type_flag(id, F_FANATIC)
&& !government_has_flag(get_gov_pplayer(p), G_FANATIC_TROOPS))
return FALSE;
diff -Nur -Xcvs/diff_ignore snap-eff/server/cityturn.c
snap-imm/server/cityturn.c
--- snap-eff/server/cityturn.c 2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/cityturn.c 2004-03-07 17:21:08.000000000 -0600
@@ -36,6 +36,7 @@
#include "unit.h"
#include "citytools.h"
+#include "gamehand.h"
#include "gamelog.h"
#include "maphand.h"
#include "plrhand.h"
@@ -956,6 +957,10 @@
space_part = FALSE;
city_add_improvement(pcity, pcity->currently_building, TRUE);
}
+
+ /* deal with any immediate effects */
+ handle_immediate_effects();
+
pcity->before_change_shields -=
impr_build_shield_cost(pcity->currently_building);
pcity->shield_stock -= impr_build_shield_cost(pcity->currently_building);
@@ -983,33 +988,6 @@
_("Game: %s has finished building %s."), pcity->name,
improvement_types[pcity->currently_building].name);
- if (pcity->currently_building == B_DARWIN) {
- Tech_Type_id first, second;
- char buffer[200];
-
- notify_player(pplayer, _("Game: %s boosts research, "
- "you gain 2 immediate advances."),
- improvement_types[B_DARWIN].name);
-
- do_free_cost(pplayer);
- first = pplayer->research.researching;
- found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE,
- A_NONE);
-
- do_free_cost(pplayer);
- second = pplayer->research.researching;
- found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE,
- A_NONE);
-
- (void) mystrlcpy(buffer, get_tech_name(pplayer, first),
- sizeof(buffer));
-
- notify_embassies(pplayer, NULL,
- _("Game: The %s have acquired %s and %s from %s."),
- get_nation_name_plural(pplayer->nation), buffer,
- get_tech_name(pplayer, second),
- improvement_types[B_DARWIN].name);
- }
if (space_part && pplayer->spaceship.state == SSHIP_NONE) {
notify_player_ex(NULL, pcity->x, pcity->y, E_SPACESHIP,
_("Game: The %s have started "
diff -Nur -Xcvs/diff_ignore snap-eff/server/gamehand.c
snap-imm/server/gamehand.c
--- snap-eff/server/gamehand.c 2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/gamehand.c 2004-03-07 17:13:22.000000000 -0600
@@ -32,6 +32,8 @@
#include "gamehand.h"
+static void handle_enable_nuke(void);
+static void handle_enable_space(void);
/****************************************************************************
Initialize the game.id variable to a random string of characters.
@@ -371,6 +373,98 @@
#include <stdio.h> /* DEBUGGING */
/**************************************************************************
+ searches for effects that enable players to build nuclear units.
+**************************************************************************/
+static void handle_enable_nuke(void)
+{
+ if (game.can_nuke) {
+ return;
+ }
+
+ /* if we find a global effect, enable_nuke and then delete
+ * all other effects that do this: they're redundant */
+ global_effects_iterate(EFT_ENABLE_NUKE, eff) {
+ game.can_nuke = TRUE;
+
+ delete_effect(NULL, NULL, NULL, B_LAST, eff->defn);
+
+ players_iterate(pplayer) {
+ pplayer->can_nuke = TRUE;
+
+ player_effects_iterate(pplayer, EFT_ENABLE_NUKE, eff) {
+ delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+ break;
+ } player_effects_iterate_end;
+ } players_iterate_end;
+
+ return;
+ } global_effects_iterate_end;
+
+ /* look for player-only effects */
+ players_iterate(pplayer) {
+ player_effects_iterate(pplayer, EFT_ENABLE_NUKE, eff) {
+ pplayer->can_nuke = TRUE;
+ delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+ break;
+ } player_effects_iterate_end;
+ } players_iterate_end;
+}
+
+/**************************************************************************
+ searches for effects that enable players to build space parts.
+**************************************************************************/
+static void handle_enable_space(void)
+{
+ if (game.can_space) {
+ return;
+ }
+
+ /* if we find a global effect, enable_space and then delete
+ * all other effects that do this: they're redundant */
+ global_effects_iterate(EFT_ENABLE_SPACE, eff) {
+ game.can_space = TRUE;
+
+ delete_effect(NULL, NULL, NULL, B_LAST, eff->defn);
+
+ players_iterate(pplayer) {
+ pplayer->can_space = TRUE;
+
+ player_effects_iterate(pplayer, EFT_ENABLE_SPACE, eff) {
+ delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+ break;
+ } player_effects_iterate_end;
+ } players_iterate_end;
+
+ return;
+ } global_effects_iterate_end;
+
+ /* look for player-only effects */
+ players_iterate(pplayer) {
+ player_effects_iterate(pplayer, EFT_ENABLE_SPACE, eff) {
+ pplayer->can_space = TRUE;
+ delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+ break;
+ } player_effects_iterate_end;
+ } players_iterate_end;
+}
+
+/**************************************************************************
+ Handle all the immediate effects. This must be done for everybody.
+ N.B. handle_reveal_cities() and handle_reveal_map() are done in
+ srv_main.c:end_turn()
+**************************************************************************/
+void handle_immediate_effects(void)
+{
+ handle_immediate_advance(); /* is first cuz new techs may recurse */
+ handle_improve_reputation();
+ handle_enable_nuke();
+ handle_enable_space();
+
+ /* update effects */
+ effects_update_all();
+}
+
+/**************************************************************************
check for changes in global effects and send them to the clients
if necessary.
**************************************************************************/
@@ -488,6 +582,9 @@
if (eff->plr == pplayer) {
continue; /* don't send effects that the player knows about */
}
+ if (is_immediate_effect(eff->defn)) {
+ continue; /* don't send immediate effects */
+ }
send_global_effect(pplayer, eff, is_effect_emitting(eff, NULL));
} players_iterate_end;
diff -Nur -Xcvs/diff_ignore snap-eff/server/gamehand.h
snap-imm/server/gamehand.h
--- snap-eff/server/gamehand.h 2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/gamehand.h 2004-03-07 17:13:22.000000000 -0600
@@ -23,6 +23,9 @@
void send_start_turn_to_clients(void);
int update_timeout(void);
+
+void handle_immediate_effects(void);
+
void send_global_effects(struct conn_list *dest);
#endif /* FC__GAMEHAND_H */
diff -Nur -Xcvs/diff_ignore snap-eff/server/maphand.c snap-imm/server/maphand.c
--- snap-eff/server/maphand.c 2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/maphand.c 2004-03-07 17:13:22.000000000 -0600
@@ -203,6 +203,51 @@
}
/**************************************************************************
+ This is an immediate effect in that it is done immediately after the effect
+ has been activated, but the effect is not deleted until the origin of the
+ effect has been destroyed.
+
+ Right now this is a Player or World ranged effect only.
+ TODO: It's certainly possible to make this an Island ranged effect.
+**************************************************************************/
+void handle_reveal_cities(void)
+{
+ players_iterate(pplayer) {
+ player_effects_iterate(pplayer, EFT_REVEAL_CITIES, eff) {
+ players_iterate(other_player) {
+ city_list_iterate(other_player->cities, pcity) {
+ show_area(pplayer, pcity->x, pcity->y, 0);
+ } city_list_iterate_end;
+ } players_iterate_end;
+
+ break; /* only need to do for the first such effect */
+ } player_effects_iterate_end;
+ } players_iterate_end;
+}
+
+/**************************************************************************
+ This is an immediate effect in that it is done immediately after the effect
+ has been activated, but the effect is not deleted until the origin of the
+ effect has been destroyed.
+
+ Right now this is a Player or World ranged effect only.
+**************************************************************************/
+void handle_reveal_map(void)
+{
+ players_iterate(pplayer) {
+ player_effects_iterate(pplayer, EFT_REVEAL_MAP, eff) {
+
+ /* map_know_all will mark all unknown tiles as known and send
+ * tile, unit, and city updates as necessary. No other actions are
+ * needed. */
+ map_know_all(pplayer);
+
+ break; /* only need to do this for the first such effect */
+ } player_effects_iterate_end;
+ } players_iterate_end;
+}
+
+/**************************************************************************
Return TRUE iff the player me really gives shared vision to player them.
**************************************************************************/
static bool really_gives_vision(struct player *me, struct player *them)
diff -Nur -Xcvs/diff_ignore snap-eff/server/maphand.h snap-imm/server/maphand.h
--- snap-eff/server/maphand.h 2003-12-14 18:20:53.000000000 -0600
+++ snap-imm/server/maphand.h 2004-03-07 17:13:22.000000000 -0600
@@ -51,6 +51,10 @@
void global_warming(int effect);
void nuclear_winter(int effect);
+
+void handle_reveal_cities(void);
+void handle_reveal_map(void);
+
void give_map_from_player_to_player(struct player *pfrom, struct player
*pdest);
void give_seamap_from_player_to_player(struct player *pfrom, struct player
*pdest);
void give_citymap_from_player_to_player(struct city *pcity,
diff -Nur -Xcvs/diff_ignore snap-eff/server/plrhand.c snap-imm/server/plrhand.c
--- snap-eff/server/plrhand.c 2004-03-07 20:12:51.441764507 -0600
+++ snap-imm/server/plrhand.c 2004-03-07 20:12:31.130640221 -0600
@@ -265,6 +265,102 @@
}
/**************************************************************************
+ Gain a new tech from the Give_Imm_Adv effect. We delete the effect
+ afterwords. Because new techs may activate more Give_Imm_Adv effects,
+ we may need to do this several times.
+
+ Only Player and World ranged effects need apply.
+**************************************************************************/
+void handle_immediate_advance(void)
+{
+ bool new_tech;
+ int i;
+
+ do {
+ new_tech = FALSE;
+
+ effects_defer_update(); /* don't let found_new_tech() recurse */
+
+ /* must give all players the tech[s] before deleting the effect */
+ global_effects_iterate(EFT_GIVE_IMM_ADV, eff) {
+ new_tech = TRUE;
+
+ players_iterate(pplayer) {
+ for (i = 0; i < eff->defn->amount; i++) {
+ if (!is_future_tech(pplayer->research.researching)) {
+ notify_embassies(pplayer, NULL,
+ _("Game: The %s have discovered %s."),
+ get_nation_name_plural(pplayer->nation),
+ advances[pplayer->research.researching].name);
+
+ gamelog(GAMELOG_TECH, _("%s discover %s"),
+ get_nation_name_plural(pplayer->nation),
+ advances[pplayer->research.researching].name);
+ } else {
+ notify_embassies(pplayer, NULL,
+ _("Game: The %s have dicovered Future Tech. %d."),
+ get_nation_name_plural(pplayer->nation),
+ pplayer->future_tech);
+
+ gamelog(GAMELOG_TECH, _("%s discover Future Tech %d"),
+ get_nation_name_plural(pplayer->nation),
+ pplayer->future_tech);
+ }
+
+ do_free_cost(pplayer);
+ found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE,
+ A_NONE);
+ }
+ } players_iterate_end;
+
+ delete_effect(NULL, NULL, NULL, B_LAST, eff->defn);
+
+ } global_effects_iterate_end;
+
+ /* there should be no more global EFT_GIVE_IMM_ADV effects left */
+ players_iterate(pplayer) {
+ player_effects_iterate(pplayer, EFT_GIVE_IMM_ADV, eff) {
+ new_tech = TRUE;
+
+ for (i = 0; i < eff->defn->amount; i++) {
+ if (!is_future_tech(pplayer->research.researching)) {
+ notify_embassies(pplayer, NULL,
+ _("Game: The %s have discovered %s."),
+ get_nation_name_plural(pplayer->nation),
+ advances[pplayer->research.researching].name);
+
+ gamelog(GAMELOG_TECH, _("%s discover %s"),
+ get_nation_name_plural(pplayer->nation),
+ advances[pplayer->research.researching].name);
+ } else {
+ notify_embassies(pplayer, NULL,
+ _("Game: The %s have dicovered Future Tech. %d."),
+ get_nation_name_plural(pplayer->nation),
+ pplayer->future_tech);
+
+ gamelog(GAMELOG_TECH, _("%s discover Future Tech %d"),
+ get_nation_name_plural(pplayer->nation),
+ pplayer->future_tech);
+ }
+
+ do_free_cost(pplayer);
+ found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE,
+ A_NONE);
+ }
+
+ delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+ } player_effects_iterate_end;
+ } players_iterate_end;
+
+ effects_undefer_update();
+
+ if (new_tech) {
+ effects_update_all();
+ }
+ } while (new_tech);
+}
+
+/**************************************************************************
Player has a new technology (from somewhere). was_discovery is passed
on to upgrade_city_rails. Logging & notification is not done here as
it depends on how the tech came. If next_tech is other than A_NONE, this
@@ -500,6 +596,9 @@
/* do all the updates needed after finding new tech */
found_new_tech(plr, plr->research.researching, TRUE, FALSE, A_NONE);
+
+ /* deal with any immediate effects */
+ handle_immediate_effects();
}
/**************************************************************************
@@ -866,6 +965,10 @@
}
check_player_government_rates(pplayer);
+
+ /* deal with any immediate effects */
+ handle_immediate_effects();
+
global_city_refresh(pplayer);
send_player_info(pplayer, pplayer);
}
@@ -943,6 +1046,31 @@
}
/**************************************************************************
+ handles the Improve_Rep effect
+**************************************************************************/
+void handle_improve_reputation(void)
+{
+ /* must give all players the reputation boost before deleting the effect */
+ global_effects_iterate(EFT_IMPROVE_REP, eff) {
+ players_iterate(pplayer) {
+ pplayer->reputation = MIN(GAME_MAX_REPUTATION,
+ pplayer->reputation + pplayer->reputation * eff->defn->amount/100);
+ } players_iterate_end;
+
+ delete_effect(NULL, NULL, NULL, B_LAST, eff->defn);
+ } global_effects_iterate_end
+
+ players_iterate(pplayer) {
+ player_effects_iterate(pplayer, EFT_IMPROVE_REP, eff) {
+ pplayer->reputation = MIN(GAME_MAX_REPUTATION,
+ pplayer->reputation + pplayer->reputation * eff->defn->amount/100);
+
+ delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+ } player_effects_iterate_end;
+ } players_iterate_end;
+}
+
+/**************************************************************************
Handles a player cancelling a "pact" with another player.
packet.id is id of player we want to cancel a pact with
@@ -1736,6 +1864,13 @@
cplayer->revolution = 1;
cplayer->capital = TRUE;
+ if (game.can_space || pplayer->can_space) {
+ cplayer->can_space = TRUE;
+ }
+ if (game.can_nuke || pplayer->can_nuke) {
+ cplayer->can_nuke = TRUE;
+ }
+
/* This should probably be DS_NEUTRAL when AI knows about diplomacy,
* but for now AI players are always at war.
*/
diff -Nur -Xcvs/diff_ignore snap-eff/server/plrhand.h snap-imm/server/plrhand.h
--- snap-eff/server/plrhand.h 2004-02-22 11:12:06.000000000 -0600
+++ snap-imm/server/plrhand.h 2004-03-07 17:16:15.000000000 -0600
@@ -36,6 +36,7 @@
void update_revolution(struct player *pplayer);
void great_library(struct player *pplayer);
void check_player_government_rates(struct player *pplayer);
+void handle_improve_reputation(void);
void make_contact(struct player *pplayer1, struct player *pplayer2, int x,
int y);
void maybe_make_contact(int x, int y, struct player *pplayer);
@@ -62,6 +63,7 @@
struct conn_list *player_reply_dest(struct player *pplayer);
+void handle_immediate_advance(void);
void found_new_tech(struct player *plr, int tech_found, bool was_discovery,
bool saving_bulbs, int next_tech);
void found_new_future_tech(struct player *pplayer);
diff -Nur -Xcvs/diff_ignore snap-eff/server/srv_main.c
snap-imm/server/srv_main.c
--- snap-eff/server/srv_main.c 2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/srv_main.c 2004-03-07 17:13:22.000000000 -0600
@@ -301,31 +301,6 @@
/**************************************************************************
...
**************************************************************************/
-static void do_apollo_program(void)
-{
- struct city *pcity = find_city_wonder(B_APOLLO);
-
- if (pcity) {
- struct player *pplayer = city_owner(pcity);
-
- if (game.civstyle == 1) {
- players_iterate(other_player) {
- city_list_iterate(other_player->cities, pcity) {
- show_area(pplayer, pcity->x, pcity->y, 0);
- } city_list_iterate_end;
- } players_iterate_end;
- } else {
- /* map_know_all will mark all unknown tiles as known and send
- * tile, unit, and city updates as necessary. No other actions are
- * needed. */
- map_know_all(pplayer);
- }
- }
-}
-
-/**************************************************************************
-...
-**************************************************************************/
static void marco_polo_make_contact(void)
{
struct city *pcity = find_city_wonder(B_MARCO);
@@ -569,7 +544,11 @@
&game.nuclearwinter, &game.coolinglevel,
nuclear_winter);
update_diplomatics();
- do_apollo_program();
+
+ /* these need to be done every turn */
+ handle_reveal_cities();
+ handle_reveal_map();
+
marco_polo_make_contact();
make_history_report();
send_player_turn_notifications(NULL);
diff -Nur -Xcvs/diff_ignore snap-imm/common/city.c snap-city/common/city.c
--- snap-imm/common/city.c 2004-03-05 20:46:34.000000000 -0600
+++ snap-city/common/city.c 2004-03-07 17:25:21.158584707 -0600
@@ -36,6 +36,7 @@
#include "speclist_c.h"
/* start helper functions for generic_city_refresh */
+static void city_init_tile_modifiers(struct city *pcity);
static int content_citizens(struct player *pplayer);
static void set_tax_income(struct city *pcity);
static void add_buildings_effect(struct city *pcity);
@@ -514,6 +515,117 @@
}
/**************************************************************************
+ initialize tile modifier structs
+**************************************************************************/
+static void city_init_tile_modifiers(struct city *pcity)
+{
+ struct tile_modifier *modptr;
+
+ city_map_iterate(x, y) {
+ modptr = &pcity->tile_bonus[x][y];
+ modptr->trade = modptr->shields = modptr->food = 0;
+
+ modptr = &pcity->tile_add[x][y];
+ modptr->trade = modptr->shields = modptr->food = 0;
+
+ modptr = &pcity->tile_pct[x][y];
+ modptr->trade = modptr->shields = modptr->food = 100;
+ } city_map_iterate_end;
+}
+
+/**************************************************************************
+ used by effects_update_all()
+**************************************************************************/
+void update_city_per_tile_modifiers(struct city *pcity)
+{
+ enum tile_special_type tile_spec[CITY_MAP_SIZE][CITY_MAP_SIZE];
+ enum tile_terrain_type tile_terr[CITY_MAP_SIZE][CITY_MAP_SIZE];
+
+ city_init_tile_modifiers(pcity);
+
+ city_effects_iterate(pcity, EFT_ALL, eff) {
+ switch(eff->defn->type) {
+ case EFT_TRADE_ADD_TILE:
+ case EFT_TRADE_INC_TILE:
+ case EFT_TRADE_PER_TILE:
+ case EFT_PROD_ADD_TILE:
+ case EFT_PROD_INC_TILE:
+ case EFT_PROD_PER_TILE:
+ case EFT_FOOD_ADD_TILE:
+ case EFT_FOOD_INC_TILE:
+ case EFT_FOOD_PER_TILE:
+ city_map_iterate(x, y) {
+ struct tile_type *type;
+ int map_x, map_y, is_real;
+
+ /* fill tile_spec and tile_terr with this tile */
+ is_real = city_map_to_map(&map_x, &map_y, pcity, x, y);
+ if (is_real) {
+ tile_spec[x][y] = map_get_special(map_x, map_y);
+ tile_terr[x][y] = map_get_terrain(map_x, map_y);
+ } else {
+ tile_spec[x][y] = S_NO_SPECIAL;
+ tile_terr[x][y] = T_UNKNOWN;
+ }
+
+ type = get_tile_type(tile_terr[x][y]);
+
+ /* FIXME: is there a better place for this to be?? -mck */
+ /* City centre counts as farmland if we have the necessary tech */
+ if (is_city_center(x, y)
+ && tile_terr[x][y] == type->irrigation_result
+ && terrain_control.may_irrigate
+ && player_knows_techs_with_flag(city_owner(pcity), TF_FARMLAND)) {
+ tile_spec[x][y] |= S_FARMLAND;
+ }
+
+ /* check .aff_spec and .aff_terr */
+ if ((contains_special(tile_spec[x][y], eff->defn->aff_spec)
+ || eff->defn->aff_spec == S_NO_SPECIAL)
+ && (tile_terr[x][y] == eff->defn->aff_terr
+ || eff->defn->aff_terr == T_UNKNOWN)) {
+ int amount = eff->defn->amount;
+
+ switch(eff->defn->type) {
+ case EFT_TRADE_ADD_TILE:
+ pcity->tile_add[x][y].trade += amount;
+ break;
+ case EFT_TRADE_INC_TILE:
+ pcity->tile_bonus[x][y].trade += amount;
+ break;
+ case EFT_TRADE_PER_TILE:
+ pcity->tile_pct[x][y].trade *= amount / 100;
+ break;
+ case EFT_PROD_ADD_TILE:
+ pcity->tile_add[x][y].shields += amount;
+ break;
+ case EFT_PROD_INC_TILE:
+ pcity->tile_bonus[x][y].shields += amount;
+ break;
+ case EFT_PROD_PER_TILE:
+ pcity->tile_pct[x][y].shields *= amount / 100;
+ break;
+ case EFT_FOOD_ADD_TILE:
+ pcity->tile_add[x][y].food += amount;
+ break;
+ case EFT_FOOD_INC_TILE:
+ pcity->tile_bonus[x][y].food += amount;
+ break;
+ case EFT_FOOD_PER_TILE:
+ pcity->tile_pct[x][y].food *= amount / 100;
+ break;
+ default:
+ break;
+ }
+ }
+ } city_map_iterate_end;
+ default:
+ break;
+ }
+ } city_effects_iterate_end;
+}
+
+/**************************************************************************
...
**************************************************************************/
int get_shields_tile(int x, int y)
@@ -580,11 +692,14 @@
}
if (contains_special(spec_t, S_RAILROAD))
s+=(s*terrain_control.rail_shield_bonus)/100;
- if (city_affected_by_wonder(pcity, B_RICHARDS))
- s++;
- if (is_ocean(tile_t) && city_got_building(pcity, B_OFFSHORE)) {
- s++;
+
+ /* add tile modifiers from effects */
+ s += pcity->tile_bonus[x][y].shields;
+ if (s > 0) {
+ s += pcity->tile_add[x][y].shields;
}
+ s *= pcity->tile_pct[x][y].shields / 100;
+
/* government shield bonus & penalty */
if (s > 0)
s += (is_celebrating ? g->celeb_shield_bonus : g->shield_bonus);
@@ -674,6 +789,19 @@
if (contains_special(spec_t, S_ROAD)) {
t += (get_tile_type(tile_t))->road_trade_incr;
}
+
+
+ /* add tile modifiers from effects */
+ t += pcity->tile_bonus[x][y].trade;
+ if (t > 0) {
+ t += pcity->tile_add[x][y].trade;
+ }
+ /* FIXME: are we sure? and if so, why not food and shields? -mck */
+ if (t < 0) {
+ t = 0; /* Don't want tiles producing negative trade */
+ }
+ t *= pcity->tile_pct[x][y].trade / 100;
+
if (t > 0) {
int before_penalty = (is_celebrating ? g->celeb_trade_before_penalty
: g->trade_before_penalty);
@@ -686,11 +814,6 @@
if (t > 0)
t += (is_celebrating ? g->celeb_trade_bonus : g->trade_bonus);
- if(city_affected_by_wonder(pcity, B_COLLOSSUS))
- t++;
- if(contains_special(spec_t, S_ROAD) && city_got_building(pcity,
B_SUPERHIGHWAYS))
- t+=(t*terrain_control.road_superhighway_trade_bonus)/100;
-
/* government trade penalty -- SKi */
if (before_penalty > 0 && t > before_penalty)
t--;
@@ -785,17 +908,14 @@
if (contains_special(spec_t, S_IRRIGATION) || city_auto_water) {
f += type->irrigation_food_incr;
- if ((contains_special(spec_t, S_FARMLAND) ||
- (city_auto_water &&
- player_knows_techs_with_flag(city_owner(pcity), TF_FARMLAND))) &&
- city_got_building(pcity, B_SUPERMARKET)) {
- f += (f * terrain_control.farmland_supermarket_food_bonus) / 100;
- }
}
- if (is_ocean(tile_t) && city_got_building(pcity, B_HARBOUR)) {
- f++;
+ /* add tile modifiers from effects */
+ f += pcity->tile_bonus[x][y].food;
+ if (f > 0) {
+ f += pcity->tile_add[x][y].food;
}
+ f *= pcity->tile_pct[x][y].food / 100;
if (contains_special(spec_t, S_RAILROAD))
f+=(f*terrain_control.rail_food_bonus)/100;
@@ -2608,6 +2728,8 @@
pcity->tax_bonus = 100;
pcity->science_bonus = 100;
+ city_init_tile_modifiers(pcity);
+
unit_list_init(&pcity->units_supported);
pcity->debug = FALSE;
diff -Nur -Xcvs/diff_ignore snap-imm/common/city.h snap-city/common/city.h
--- snap-imm/common/city.h 2004-03-05 20:44:46.000000000 -0600
+++ snap-city/common/city.h 2004-03-07 17:25:21.160584238 -0600
@@ -207,6 +207,12 @@
* all units coming to kill us. */
};
+struct tile_modifier {
+ int trade;
+ int shields;
+ int food;
+};
+
struct city {
int id;
int owner;
@@ -237,6 +243,11 @@
int trade_prod, corruption, tile_trade;
int shield_bonus, tax_bonus, science_bonus; /* more CPU savings! */
+ /* per tile production bonuses from effects */
+ struct tile_modifier tile_bonus[CITY_MAP_SIZE][CITY_MAP_SIZE];
+ struct tile_modifier tile_add[CITY_MAP_SIZE][CITY_MAP_SIZE];
+ struct tile_modifier tile_pct[CITY_MAP_SIZE][CITY_MAP_SIZE];
+
/* the totals */
int luxury_total, tax_total, science_total;
@@ -392,6 +403,8 @@
bool city_map_to_map(int *map_x, int *map_y, const struct city *const pcity,
int city_map_x, int city_map_y);
+void update_city_per_tile_modifiers(struct city *pcity);
+
/* shield on spot */
int city_get_shields_tile(int x, int y, struct city *pcity);
int base_city_get_shields_tile(int x, int y, struct city *pcity,
diff -Nur -Xcvs/diff_ignore snap-imm/common/effects.c snap-city/common/effects.c
--- snap-imm/common/effects.c 2004-03-07 17:13:22.000000000 -0600
+++ snap-city/common/effects.c 2004-03-07 17:25:21.162583770 -0600
@@ -487,6 +487,11 @@
} city_list_iterate_end;
} players_iterate_end;
}
+
+ /* update per tile modifiers */
+ cities_iterate(pcity) {
+ update_city_per_tile_modifiers(pcity);
+ } cities_iterate_end;
}
/*******************************************************************
|
|