Another issue that's come up: money. There are a few issues with it.
1) As has already been mentioned, the battle rewards rarely even pay for the battle.
2) Battle rewards (and missed battle penalties) are miniscule compared to everything else (construction costs, foreign-country income, etc). They're almost irrelevant. Is there even a point to keeping battle rewards? Shouldn't battles just be the "cost of business" of keeping your country sponsors happy?
3) Countries don't seem to care what you do. Perhaps it was just me, but it seems that you can be rolling in the cash without ever going to a mission. Shouldn't countries that you don't protect get sick of you sitting around doing nothing, or become happy if you help out a lot?
UPDATE: Nope, I guess it's not me. From cl_campaign.c (code checked out yesterday evening):
/**
* @brief
*
* if expires is true a mission expires without any reaction
* this will cost money and decrease nation support for this area
* TODO: Use mis->pos to determine the position on the geoscape and get the
* TODO: Use colors for nations
*/
static void CL_HandleNationData(qboolean expires, actMis_t * mis)
{
}
That function is supposed to make them happy/unhappy with you, but it's blank. One problem with filling it in is that nation_t has a funding level, but not a happiness level or "original funding" level; if you change funding, it'd be hard to know what range to allow it to change in. I'd propose changing the struct (in client/cl_campaign.h) to:
typedef struct nation_s {
char id[MAX_VAR];
char name[MAX_VAR];
int funding;
float happiness;
vec4_t color;
float alienFriendly;
int soldiers;
int scientists;
char names[MAX_VAR];
} nation_t;
Modifying the initialization in client/cl_campaign.c to start them out at half maximum happiness:
value_t nation_vals[] = {
{"name", V_TRANSLATION_STRING, offsetof(nation_t, name)}
,
{"color", V_COLOR, offsetof(nation_t, color)}
,
{"funding", V_INT, offsetof(nation_t, funding)}
,
{"happiness", V_FLOAT, 0.5}
,
{"alien_friendly", V_FLOAT, offsetof(nation_t, alienFriendly)}
,
{"soldiers", V_INT, offsetof(nation_t, soldiers)}
,
{"scientists", V_INT, offsetof(nation_t, scientists)}
,
{"names", V_INT, offsetof(nation_t, names)}
,
{NULL, 0, 0}
,
};
Modifying mission_t in cl/cl_campaign.h to have a nation string in it:
typedef struct mission_s {
char *text;
char name[MAX_VAR];
char map[MAX_VAR];
char param[MAX_VAR];
char location[MAX_VAR];
char nation[MAX_VAR];
char type[MAX_VAR];
char music[MAX_VAR];
char alienTeam[MAX_VAR];
char alienEquipment[MAX_VAR];
char alienArmor[MAX_VAR];
char civTeam[MAX_VAR];
char cmds[MAX_VAR];
char onwin[MAX_VAR];
char onlose[MAX_VAR];
int ugv; /* uncontrolled groun
qboolean active; /* aircraft at place? */
qboolean onGeoscape; /* already on geoscape - don't add it
qboolean storyRelated; /* auto mission play disabled when tr
vec2_t pos;
byte mask[4];
int aliens, civilians;
int recruits;
int cr_win, cr_alien, cr_civilian;
} mission_t;
Modifying the associated missions.ufo to have that as well. One example:
mission stadium
{
location "_New York"
nation "ua"
type "_Terror Attack"
text "_Damn it, you've let some of them get\away again! Re
map stadium06
music mission3
pos "74 41"
aliens 4
alienteam alien
alienequip stage3_soldiers
civilians 2
civteam european
recruits 4
$win 400
$alien 250
$civilian 200
onlose ""
onwin ""
storyrelated true
}
Then modifying client/cl_campaign.c to fill out that field:
value_t mission_vals[] = {
{"location", V_TRANSLATION_STRING, offsetof(mission_t, location)}
,
{"type", V_TRANSLATION_STRING, offsetof(mission_t, type)}
,
{"text", V_TRANSLATION_STRING, 0} /* max length is 128 */
,
{"nation", V_STRING, offsetof(mission_t, nation)}
,
{"map", V_STRING, offsetof(mission_t, map)}
,
{"param", V_STRING, offsetof(mission_t, param)}
,
{"music", V_STRING, offsetof(mission_t, music)}
,
{"pos", V_POS, offsetof(mission_t, pos)}
,
{"mask", V_RGBA, offsetof(mission_t, mask)} /* color values from map
,
{"aliens", V_INT, offsetof(mission_t, aliens)}
,
{"maxugv", V_INT, offsetof(mission_t, ugv)}
,
{"commands", V_STRING, offsetof(mission_t, cmds)} /* commands that ar
,
{"onwin", V_STRING, offsetof(mission_t, onwin)}
,
{"onlose", V_STRING, offsetof(mission_t, onlose)}
,
{"alienteam", V_STRING, offsetof(mission_t, alienTeam)}
,
{"alienarmor", V_STRING, offsetof(mission_t, alienArmor)}
,
{"alienequip", V_STRING, offsetof(mission_t, alienEquipment)}
,
{"civilians", V_INT, offsetof(mission_t, civilians)}
,
{"civteam", V_STRING, offsetof(mission_t, civTeam)}
,
{"recruits", V_INT, offsetof(mission_t, recruits)}
,
{"storyrelated", V_BOOL, offsetof(mission_t, storyRelated)}
,
{"$win", V_INT, offsetof(mission_t, cr_win)}
,
{"$alien", V_INT, offsetof(mission_t, cr_alien)}
,
{"$civilian", V_INT, offsetof(mission_t, cr_civilian)}
,
{NULL, 0, 0}
,
};
Then we fill out the empty function with something like:
static void CL_HandleNationData(qboolean expires, actMis_t * mis)
{
int i;
mission_t* mission=mis->def;
char* nation_name=mission->nation;
for (i=0; i<numNations; i++)
{
nation_t* nation=&nations[i];
if (expires)
{
if (!strcmp(nation->name, nation_name))
{ //Strong negative reaction
nation->happiness*=(nation->alienFriendly);
}
else
{ //Minor negative reaction
nation->happiness*=1-pow(1-nation->alienFriendly,5);
}
}
else
{
if (!strcmp(nation->name, nation_name))
{ //Strong positive reaction
nation->happiness/=(1-nation->alienFriendly);
nation->happiness+=nation->alienFriendly/10;
}
else
{ //Minor positive reaction
nation->happiness/=pow((1-nation->alienFriendly),0.2);
nation->happiness+=nation->alienFriendly/50;
}
if (nation->happiness > 1.0)
{ //Can't be more than 100% happy with you.
nation->happiness=1.0;
}
}
}
}
And we must make sure that it gets called properly, not just on loss (client/cl_campaign.c):
/* give reward */
if (won)
{
CL_UpdateCredits(ccs.credits + mis->cr_win + (mis->cr_alien * mis->aliens));
CL_HandleNationData(false, mis)
}
else
{
CL_UpdateCredits(ccs.credits + mis->cr_win - (mis->cr_civilian * mis->civilians));
CL_HandleNationData(true, mis)
}
Same thing, further down:
/* check for win */
if (Cmd_Argc() < 2) {
Com_Printf("Usage: game_results <won>\n");
return;
}
won = atoi(Cmd_Argv(1));
CL_HandleNationData(true, selMis)
Lastly, we need to adjust the funding that they give you in client/cl_campaign.c by their happiness and get rid of the random nonpayments since they're no longer needed:
/**
* @brief
*
* Update the nation data from all parsed nation each month
* give us nation support by:
* * credits
* * new soldiers
* * new scientists
* Called from CL_CampaignRun
* @sa CL_CampaignRun
*/
static void CL_UpdateNationData(void)
{
int i;
char message[1024];
nation_t *nation;
for (i = 0; i < numNations; i++) {
float funding;
nation = &nations[i];
funding=nation->funding * nation->happiness;
Com_sprintf(message, sizeof(message), _("Gained %i credits from nation %s"), funding, _(nation->name));
MN_AddNewMessage(_("Notice"), message, qfalse, MSG_STANDARD, NULL);
CL_UpdateCredits(ccs.credits + funding);
}
}
Anyone want to try this out?
- Karen Pease (meme@daughtersoftiresias.org)