Since FSPort has promotion debriefings that differ from the other FSPort debriefing personas, I decided to make a patch that allows for different personas to have different promotion text. Here's the patch:
Index: code/missionui/missiondebrief.cpp
===================================================================
--- code/missionui/missiondebrief.cpp (revision 10046)
+++ code/missionui/missiondebrief.cpp (working copy)
@@ -916,10 +916,8 @@
// Goober5000
// V sez: "defaults to number 9 (Petrarch) for non-volition missions
// this is an ugly, nasty, hateful way of doing this, but it saves us changing the missions at this point"
-void debrief_choose_voice(char *voice_dest, char *voice_base, int default_to_base = 0)
+void debrief_choose_voice(char *voice_dest, char *voice_base, int persona_index, int default_to_base = 0)
{
- // see if we have a persona
- int persona_index = debrief_find_persona_index();
if (persona_index >= 0)
{
// get voice file
@@ -1001,11 +999,19 @@
debrief_choose_medal_variant(buf, Rank_medal_index, Promoted);
Rank_bitmap = bm_load(buf);
- Promotion_stage.text = Ranks[Promoted].promotion_text;
+ // see if we have a persona
+ int persona_index = debrief_find_persona_index();
+
+ // use persona-specific promotion text if it exists; otherwise, use default
+ if (Ranks[Promoted].promotion_text.find(persona_index) != Ranks[Promoted].promotion_text.end()) {
+ Promotion_stage.text = Ranks[Promoted].promotion_text[persona_index];
+ } else {
+ Promotion_stage.text = Ranks[Promoted].promotion_text[-1];
+ }
Promotion_stage.recommendation_text = "";
// choose appropriate promotion voice for this mission
- debrief_choose_voice(Promotion_stage.voice, Ranks[Promoted].promotion_voice_base);
+ debrief_choose_voice(Promotion_stage.voice, Ranks[Promoted].promotion_voice_base, persona_index);
debrief_add_award_text(Ranks[Promoted].name);
}
@@ -1016,11 +1022,19 @@
debrief_choose_medal_variant(buf, Player->stats.m_badge_earned, Player->stats.medal_counts[Player->stats.m_badge_earned] - 1);
Badge_bitmap = bm_load(buf);
- Badge_stage.text = Medals[Player->stats.m_badge_earned].promotion_text;
+ // see if we have a persona
+ int persona_index = debrief_find_persona_index();
+
+ // use persona-specific badge text if it exists; otherwise, use default
+ if (Ranks[Promoted].promotion_text.find(persona_index) != Ranks[Promoted].promotion_text.end()) {
+ Badge_stage.text = Medals[Player->stats.m_badge_earned].promotion_text[persona_index];
+ } else {
+ Badge_stage.text = Medals[Player->stats.m_badge_earned].promotion_text[-1];
+ }
Badge_stage.recommendation_text = "";
// choose appropriate badge voice for this mission
- debrief_choose_voice(Badge_stage.voice, Medals[Player->stats.m_badge_earned].voice_base);
+ debrief_choose_voice(Badge_stage.voice, Medals[Player->stats.m_badge_earned].voice_base, persona_index);
debrief_add_award_text(Medals[Player->stats.m_badge_earned].name);
}
@@ -1082,7 +1096,7 @@
// }
// Goober5000
- debrief_choose_voice(stagep->voice, traitor_voice_file, 1);
+ debrief_choose_voice(stagep->voice, traitor_voice_file, debrief_find_persona_index(), 1);
required_string("$Recommendation text:");
stuff_string( stagep->recommendation_text, F_MULTITEXT, NULL);
Index: code/stats/medals.cpp
===================================================================
--- code/stats/medals.cpp (revision 10046)
+++ code/stats/medals.cpp (working copy)
@@ -190,10 +190,13 @@
kills_needed = m.kills_needed;
memcpy(voice_base, m.voice_base, MAX_FILENAME_LEN);
- if (m.promotion_text)
- promotion_text = vm_strdup(m.promotion_text);
- else
- promotion_text = NULL;
+ promotion_text.clear();
+ SCP_map<int, char*>::const_iterator it;
+ for (it = m.promotion_text.begin(); it != m.promotion_text.end(); it++) {
+ if (it->second) {
+ promotion_text[it->first] = vm_strdup(it->second);
+ }
+ }
}
// assignment operator
@@ -200,10 +203,13 @@
const medal_stuff &medal_stuff::operator=(const medal_stuff &m)
{
if (this != &m) {
- if (promotion_text) {
- vm_free(promotion_text);
- promotion_text = NULL;
+ SCP_map<int, char*>::iterator it;
+ for (it = promotion_text.begin(); it != promotion_text.end(); it++) {
+ if (it->second) {
+ vm_free(it->second);
+ }
}
+ promotion_text.clear();
clone(m);
}
@@ -340,6 +346,7 @@
// this medal is a badge and should be treated specially
if ( optional_string("+Num Kills:") ) {
char buf[MULTITEXT_LENGTH];
+ int persona;
stuff_int( &temp_medal.kills_needed );
if (optional_string("$Wavefile 1:"))
@@ -351,9 +358,23 @@
if (optional_string("$Wavefile Base:"))
stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN);
- required_string("$Promotion Text:");
- stuff_string(buf, F_MULTITEXT, sizeof(buf));
- temp_medal.promotion_text = vm_strdup(buf);
+ while (check_for_string("$Promotion Text:")) {
+ required_string("$Promotion Text:");
+ stuff_string(buf, F_MULTITEXT, sizeof(buf));
+ persona = -1;
+ if (optional_string("+Persona:")) {
+ stuff_int(&persona);
+ if (persona < 0) {
+ Warning(LOCATION, "Debriefing text for %s is assigned to an invalid persona: %i (must be 0 or greater).\n", temp_medal.name, persona);
+ continue;
+ }
+ }
+ temp_medal.promotion_text[persona] = vm_strdup(buf);
+ }
+ if (temp_medal.promotion_text.find(-1) == temp_medal.promotion_text.end()) {
+ Warning(LOCATION, "%s medal is missing default debriefing text.\n", temp_medal.name);
+ temp_medal.promotion_text[-1] = "";
+ }
}
Medals.push_back(temp_medal);
Index: code/stats/medals.h
===================================================================
--- code/stats/medals.h (revision 10046)
+++ code/stats/medals.h (working copy)
@@ -35,7 +35,7 @@
//If this is a badge (kills_needed > 0)
char voice_base[MAX_FILENAME_LEN];
- char *promotion_text;
+ SCP_map<int, char*> promotion_text;
medal_stuff() {
name[0] = '\0';
@@ -45,14 +45,17 @@
version_starts_at_1 = false;
kills_needed = 0;
voice_base[0] = '\0';
- promotion_text = NULL;
+ promotion_text.clear();
}
~medal_stuff() {
- if (promotion_text) {
- vm_free(promotion_text);
- promotion_text = NULL;
+ SCP_map<int, char*>::iterator it;
+ for (it = promotion_text.begin(); it != promotion_text.end(); it++) {
+ if (it->second) {
+ vm_free(it->second);
+ }
}
+ promotion_text.clear();
}
medal_stuff(const medal_stuff &m) { clone(m); }
Index: code/stats/scoring.cpp
===================================================================
--- code/stats/scoring.cpp (revision 10046)
+++ code/stats/scoring.cpp (working copy)
@@ -58,7 +58,7 @@
{
atexit(scoreing_close);
char buf[MULTITEXT_LENGTH];
- int rval, idx;
+ int rval, idx, persona;
// open localization
lcl_ext_open();
@@ -86,11 +86,25 @@
stuff_string( Ranks[idx].bitmap, F_NAME, MAX_FILENAME_LEN );
required_string("$Promotion Voice Base:");
stuff_string( Ranks[idx].promotion_voice_base, F_NAME, MAX_FILENAME_LEN );
- required_string("$Promotion Text:");
- stuff_string(buf, F_MULTITEXT, sizeof(buf));
- drop_white_space(buf);
- compact_multitext_string(buf);
- Ranks[idx].promotion_text = vm_strdup(buf);
+ while (check_for_string("$Promotion Text:")) {
+ required_string("$Promotion Text:");
+ stuff_string(buf, F_MULTITEXT, sizeof(buf));
+ drop_white_space(buf);
+ compact_multitext_string(buf);
+ persona = -1;
+ if (optional_string("+Persona:")) {
+ stuff_int(&persona);
+ if (persona < 0) {
+ Warning(LOCATION, "Debriefing text for %s rank is assigned to an invalid persona: %i (must be 0 or greater).\n", Ranks[idx].name, persona);
+ continue;
+ }
+ }
+ Ranks[idx].promotion_text[persona] = vm_strdup(buf);
+ }
+ if (Ranks[idx].promotion_text.find(-1) == Ranks[idx].promotion_text.end()) {
+ Warning(LOCATION, "%s rank is missing default debriefing text.\n", Ranks[idx].name);
+ Ranks[idx].promotion_text[-1] = "";
+ }
idx++;
}
@@ -1513,8 +1527,13 @@
void scoreing_close()
{
+ SCP_map<int, char*>::iterator it;
for(int i = 0; i<NUM_RANKS; i++) {
- if(Ranks[i].promotion_text)
- vm_free(Ranks[i].promotion_text);
+ for (it = Ranks[i].promotion_text.begin(); it != Ranks[i].promotion_text.end(); it++) {
+ if (it->second) {
+ vm_free(it->second);
+ }
+ }
+ Ranks[i].promotion_text.clear();
}
}
Index: code/stats/scoring.h
===================================================================
--- code/stats/scoring.h (revision 10046)
+++ code/stats/scoring.h (working copy)
@@ -63,7 +63,7 @@
typedef struct rank_stuff {
char name[NAME_LENGTH]; // name of this rank
- char *promotion_text; // text to display when promoted to this rank
+ SCP_map<int, char*> promotion_text; // text to display when promoted to this rank
int points; // points needed to reach this rank
char bitmap[MAX_FILENAME_LEN]; // bitmap of this rank medal
char promotion_voice_base[MAX_FILENAME_LEN];
Here's an example of how this feature is utilized:
$Name: Lieutenant
$Points: 10000
$Bitmap: medal12b.pcx
$Promotion Voice Base: rank_b.wav
$Promotion Text:
XSTR("After reviewing your service record and the recommendations of your superior officers, Allied Command has authorized your promotion. Congratulations, Lieutenant.", 2931)
$end_multi_text
$Promotion Text:
XSTR("Per GTAR 64-2a you are hereby promoted to the rank of Lieutenant. Congratulations.", -1)
$end_multi_text
+Persona: 10
In this example, the first
$Promotion Text entry looks the same as before, making it the default text. The second entry, however, is immediately followed by
+Persona: 10, which indicates that this text should be used instead of the default text if the debriefing persona is 10.
Any number of
$Promotion Text entries may be used as long as the following conditions are adhered to: 1) There is a default entry (i.e., one without a
+Persona field), and 2) no two entries of a rank/medal are assigned as default or to the same persona. Entries may appear in any order.
This feature may be used with ranks in rank.tbl as well as the Ace medals in medals.tbl.
I have created a mod that lets you try this out. It includes two campaigns that are identical save for the debriefing persona. Each mission has a non-moving enemy fighter that you can destroy for an Ace medal. (I reduced the thresholds of the Aces to 1, 2, and 3 kills, so they should be easy to test.) At the end of each mission, you will be automatically promoted.
Here is the mod:
https://dl.dropboxusercontent.com/u/89353583/FreeSpace/PersonaSpecificDebriefings.zip(I know that there's also traitor.tbl, I have not yet been successful in doing the same with that. Since its format is different, it would probably deserve its own patch anyway.)