1 /**
2  * @file
3  * @brief Campaign mission
4  */
5 
6 /*
7 Copyright (C) 2002-2013 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 */
25 
26 #include "../../../cl_shared.h"
27 #include "../cp_campaign.h"
28 #include "../cp_geoscape.h"
29 #include "../cp_ufo.h"
30 #include "../cp_missions.h"
31 #include "../cp_time.h"
32 #include "../cp_xvi.h"
33 #include "../cp_alien_interest.h"
34 
35 /**
36  * @brief Harvesting mission is over and is a success: change interest values.
37  * @note Harvesting mission
38  */
CP_HarvestMissionIsSuccess(mission_t * mission)39 static void CP_HarvestMissionIsSuccess (mission_t* mission)
40 {
41 	INT_ChangeIndividualInterest(-0.3f, INTERESTCATEGORY_HARVEST);
42 	INT_ChangeIndividualInterest(0.2f, INTERESTCATEGORY_RECON);
43 	INT_ChangeIndividualInterest(0.05f, INTERESTCATEGORY_BUILDING);
44 	if (CP_IsXVIStarted())
45 		INT_ChangeIndividualInterest(0.1f, INTERESTCATEGORY_XVI);
46 
47 	CP_MissionRemove(mission);
48 }
49 
50 /**
51  * @brief Harvesting mission is over and is a failure: change interest values.
52  * @note Harvesting mission
53  */
CP_HarvestMissionIsFailure(mission_t * mission)54 void CP_HarvestMissionIsFailure (mission_t* mission)
55 {
56 	INT_ChangeIndividualInterest(0.1f, INTERESTCATEGORY_INTERCEPT);
57 	INT_ChangeIndividualInterest(0.03f, INTERESTCATEGORY_BASE_ATTACK);
58 	INT_ChangeIndividualInterest(0.03f, INTERESTCATEGORY_TERROR_ATTACK);
59 
60 	CP_MissionRemove(mission);
61 }
62 
63 /**
64  * @brief Start Harvesting mission.
65  * @note Harvesting mission -- Stage 2
66  */
CP_HarvestMissionStart(mission_t * mission)67 static void CP_HarvestMissionStart (mission_t* mission)
68 {
69 	const date_t minMissionDelay = {2, 0};
70 	const date_t missionDelay = {3, 0};
71 
72 	mission->stage = STAGE_HARVEST;
73 
74 	if (mission->ufo) {
75 		mission->finalDate = Date_Add(ccs.date, Date_Random(minMissionDelay, missionDelay));
76 		/* ufo becomes invisible on geoscape, but don't remove it from ufo global array (may reappear)*/
77 		CP_UFORemoveFromGeoscape(mission, false);
78 	} else {
79 		/* Go to next stage on next frame */
80 		mission->finalDate = ccs.date;
81 	}
82 
83 	/* mission appear on geoscape, player can go there */
84 	CP_MissionAddToGeoscape(mission, false);
85 }
86 
87 /**
88  * @brief Choose nation if needed for given mission.
89  * @param[in] mission Pointer to the mission we are creating.
90  * @param[out] nationList linkedList that will contain the name of the nation where the mission should take place.
91  * @note nationList should be empty if no nation should be favoured.
92  * @return True if nationList has been filled, false else.
93  */
CP_ChooseNation(const mission_t * mission,linkedList_t ** nationList)94 static bool CP_ChooseNation (const mission_t* mission, linkedList_t** nationList)
95 {
96 	int randomNumber, max = 0;
97 	/* Increase this factor to make probability to select non-infected nation higher
98 	 * Used to make sure that non-infected nation can still be attacked */
99 	const int OFFSET = 1;
100 	int i;
101 
102 	if (mission->ufo)
103 		return false;
104 
105 	/* favour mission with higher XVI level */
106 	for (i = 0; i < ccs.numNations; i++) {
107 		const nation_t* nation = NAT_GetNationByIDX(i);
108 		const nationInfo_t* stats = NAT_GetCurrentMonthInfo(nation);
109 		max += OFFSET + stats->xviInfection;
110 	}
111 
112 	randomNumber = (int) (frand() * (float) max);
113 
114 	/* Select the corresponding nation */
115 	for (i = 0; i < ccs.numNations; i++) {
116 		const nation_t* nation = NAT_GetNationByIDX(i);
117 		const nationInfo_t* stats = NAT_GetCurrentMonthInfo(nation);
118 		randomNumber -= OFFSET + stats->xviInfection;
119 		if (randomNumber < 0) {
120 			cgi->LIST_AddString(nationList, nation->id);
121 			return true;
122 		}
123 	}
124 
125 	return false;
126 }
127 
128 /**
129  * @brief Set Harvest mission, and go to mission pos.
130  * @note Harvesting attack mission -- Stage 1
131  * @todo Remove me when CP_XVIMissionGo will be implemented
132  * This function should take a location close to an XVI infection point
133  * see gameplay proposal on wiki
134  */
CP_HarvestMissionGo(mission_t * mission)135 void CP_HarvestMissionGo (mission_t* mission)
136 {
137 	mission->stage = STAGE_MISSION_GOTO;
138 
139 	/* Choose a map */
140 	if (CP_ChooseMap(mission, nullptr)) {
141 		int counter;
142 		linkedList_t* nationList = nullptr;
143 		const bool nationTest = CP_ChooseNation(mission, &nationList);
144 		for (counter = 0; counter < MAX_POS_LOOP; counter++) {
145 			if (!CP_GetRandomPosOnGeoscapeWithParameters(mission->pos, mission->mapDef->terrains, mission->mapDef->cultures, mission->mapDef->populations, nationTest ? nationList : nullptr))
146 				continue;
147 			if (GEO_PositionCloseToBase(mission->pos))
148 				continue;
149 			mission->posAssigned = true;
150 			break;
151 		}
152 		if (counter >= MAX_POS_LOOP) {
153 			Com_Printf("CP_HarvestMissionGo: Error, could not set position.\n");
154 			CP_MissionRemove(mission);
155 			return;
156 		}
157 		cgi->LIST_Delete(&nationList);
158 	} else {
159 		Com_Printf("CP_HarvestMissionGo: No map found, remove mission.\n");
160 		CP_MissionRemove(mission);
161 		return;
162 	}
163 
164 	if (mission->ufo) {
165 		CP_MissionDisableTimeLimit(mission);
166 		UFO_SendToDestination(mission->ufo, mission->pos);
167 	} else {
168 		/* Go to next stage on next frame */
169 		mission->finalDate = ccs.date;
170 	}
171 }
172 
173 /**
174  * @brief Fill an array with available UFOs for Harvesting mission type.
175  * @param[in] mission Pointer to the mission we are currently creating.
176  * @param[out] ufoTypes Array of ufoType_t that may be used for this mission.
177  * @note Harvesting mission -- Stage 0
178  * @return number of elements written in @c ufoTypes
179  */
CP_HarvestMissionAvailableUFOs(const mission_t * mission,ufoType_t * ufoTypes)180 int CP_HarvestMissionAvailableUFOs (const mission_t* mission, ufoType_t* ufoTypes)
181 {
182 	int num = 0;
183 
184 	if (UFO_ShouldAppearOnGeoscape(UFO_HARVESTER))
185 		ufoTypes[num++] = UFO_HARVESTER;
186 
187 	return num;
188 }
189 
190 /**
191  * @brief Determine what action should be performed when a Harvesting mission stage ends.
192  * @param[in] mission Pointer to the mission which stage ended.
193  */
CP_HarvestMissionNextStage(mission_t * mission)194 void CP_HarvestMissionNextStage (mission_t* mission)
195 {
196 	switch (mission->stage) {
197 	case STAGE_NOT_ACTIVE:
198 		/* Create Harvesting mission */
199 		CP_MissionBegin(mission);
200 		break;
201 	case STAGE_COME_FROM_ORBIT:
202 		/* Go to mission */
203 		CP_HarvestMissionGo(mission);
204 		break;
205 	case STAGE_MISSION_GOTO:
206 		/* just arrived on a new Harvesting mission: start it */
207 		CP_HarvestMissionStart(mission);
208 		break;
209 	case STAGE_HARVEST:
210 		/* Leave earth */
211 		CP_ReconMissionLeave(mission);
212 		break;
213 	case STAGE_RETURN_TO_ORBIT:
214 		/* mission is over, remove mission */
215 		CP_HarvestMissionIsSuccess(mission);
216 		break;
217 	default:
218 		Com_Printf("CP_HarvestMissionNextStage: Unknown stage: %i, removing mission.\n", mission->stage);
219 		CP_MissionRemove(mission);
220 		break;
221 	}
222 }
223