1 /**
2  * @file
3  * @brief Menu related functions for research.
4  *
5  */
6 
7 /*
8 Copyright (C) 2002-2013 UFO: Alien Invasion.
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 
19 See the GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24 */
25 
26 #include "../../cl_shared.h"
27 #include "cp_campaign.h"
28 #include "cp_research_callbacks.h"
29 
30 /**
31  * @brief Assign as many scientists to the research project as possible.
32  * @param[in] base The base the tech is researched in.
33  * @param[in] tech The technology you want to max out.
34  */
RS_Max_f(void)35 static void RS_Max_f (void)
36 {
37 	base_t* base = B_GetCurrentSelectedBase();
38 
39 	if (!base)
40 		return;
41 
42 	if (cgi->Cmd_Argc() < 2) {
43 		Com_Printf("Usage: %s <tech_id>\n", cgi->Cmd_Argv(0));
44 		return;
45 	}
46 	technology_t* tech = RS_GetTechByID(cgi->Cmd_Argv(1));
47 	if (!tech) {
48 		Com_Printf("RS_Max_f: Invalid tech '%s'\n", cgi->Cmd_Argv(1));
49 		return;
50 	}
51 	if (tech->base && tech->base != base) {
52 		Com_Printf("RS_Max_f: Tech '%s' is not researched in this base\n", cgi->Cmd_Argv(1));
53 		return;
54 	}
55 
56 	/* Add as many scientists as possible to this tech. */
57 	while (CAP_GetFreeCapacity(base, CAP_LABSPACE) > 0) {
58 		Employee* employee = E_GetUnassignedEmployee(base, EMPL_SCIENTIST);
59 		if (!employee)
60 			break;
61 		RS_AssignScientist(tech, base, employee);
62 		if (!employee->isAssigned())
63 			break;
64 	}
65 
66 	cgi->UI_ExecuteConfunc("ui_research_update_topic %s %d", tech->id, tech->scientists);
67 	cgi->UI_ExecuteConfunc("ui_research_update_caps %d %d %d %d", E_CountUnassigned(base, EMPL_SCIENTIST),
68 		E_CountHired(base, EMPL_SCIENTIST), CAP_GetFreeCapacity(base, CAP_LABSPACE), CAP_GetMax(base, CAP_LABSPACE));
69 }
70 
71 /**
72  * @brief Script function to add and remove a scientist to the technology entry in the research-list.
73  */
RS_Change_f(void)74 static void RS_Change_f (void)
75 {
76 	base_t* base = B_GetCurrentSelectedBase();
77 
78 	if (cgi->Cmd_Argc() < 2) {
79 		Com_Printf("Usage: %s <tech_id>\n", cgi->Cmd_Argv(0));
80 		return;
81 	}
82 	technology_t* tech = RS_GetTechByID(cgi->Cmd_Argv(1));
83 	if (!tech) {
84 		Com_Printf("RS_ChangeScientist_f: Invalid tech '%s'\n", cgi->Cmd_Argv(1));
85 		return;
86 	}
87 	if (tech->base && tech->base != base) {
88 		Com_Printf("RS_ChangeScientist_f: Tech '%s' is not researched in this base\n", cgi->Cmd_Argv(1));
89 		return;
90 	}
91 	const int diff = atoi(cgi->Cmd_Argv(2));
92 	if (diff == 0)
93 		return;
94 
95 	if (diff > 0) {
96 		RS_AssignScientist(tech, base);
97 	} else if (tech->base) {
98 		RS_RemoveScientist(tech, nullptr);
99 	}
100 
101 	cgi->UI_ExecuteConfunc("ui_research_update_topic %s %d", tech->id, tech->scientists);
102 	cgi->UI_ExecuteConfunc("ui_research_update_caps %d %d %d %d", E_CountUnassigned(base, EMPL_SCIENTIST),
103 		E_CountHired(base, EMPL_SCIENTIST), CAP_GetFreeCapacity(base, CAP_LABSPACE), CAP_GetMax(base, CAP_LABSPACE));
104 }
105 
106 /**
107  * @brief Removes all scientists from the selected research-list entry.
108  */
RS_Stop_f(void)109 static void RS_Stop_f (void)
110 {
111 	const base_t* base = B_GetCurrentSelectedBase();
112 
113 	if (cgi->Cmd_Argc() < 2) {
114 		Com_Printf("Usage: %s <tech_id>\n", cgi->Cmd_Argv(0));
115 		return;
116 	}
117 	technology_t* tech = RS_GetTechByID(cgi->Cmd_Argv(1));
118 	if (!tech) {
119 		Com_Printf("RS_Stop_f: Invalid tech '%s'\n", cgi->Cmd_Argv(1));
120 		return;
121 	}
122 	if (!tech->base) {
123 		return;
124 	}
125 	if (tech->base != base) {
126 		Com_Printf("RS_Stop_f: Tech '%s' is not researched in this base\n", cgi->Cmd_Argv(1));
127 		return;
128 	}
129 
130 	RS_StopResearch(tech);
131 
132 	cgi->UI_ExecuteConfunc("ui_research_update_topic %s %d", tech->id, tech->scientists);
133 	cgi->UI_ExecuteConfunc("ui_research_update_caps %d %d %d %d", E_CountUnassigned(base, EMPL_SCIENTIST),
134 		E_CountHired(base, EMPL_SCIENTIST), CAP_GetFreeCapacity(base, CAP_LABSPACE), CAP_GetMax(base, CAP_LABSPACE));
135 }
136 
137 /**
138  * @brief Shows research image/model and title on the research screen
139  */
RS_GetDetails_f(void)140 static void RS_GetDetails_f (void)
141 {
142 	if (cgi->Cmd_Argc() < 2) {
143 		Com_Printf("Usage: %s <tech_id>\n", cgi->Cmd_Argv(0));
144 		return;
145 	}
146 	const technology_t* tech = RS_GetTechByID(cgi->Cmd_Argv(1));
147 	if (!tech) {
148 		Com_Printf("RS_GetDetails_f: Invalid tech '%s'\n", cgi->Cmd_Argv(1));
149 		return;
150 	}
151 	cgi->UI_ExecuteConfunc("ui_research_details \"%s\" \"%s\" \"%s\"", _(tech->name), tech->image ? tech->image : "", tech->mdl ? tech->mdl : "");
152 }
153 
154 /**
155  * @brief Fills technology list on research UI
156  */
RS_FillTechnologyList_f(void)157 static void RS_FillTechnologyList_f (void)
158 {
159 	base_t* base = B_GetCurrentSelectedBase();
160 
161 	if (!base)
162 		return;
163 
164 	RS_MarkResearchable(base);
165 
166 	cgi->UI_ExecuteConfunc("ui_research_update_caps %d %d %d %d", E_CountUnassigned(base, EMPL_SCIENTIST),
167 		E_CountHired(base, EMPL_SCIENTIST), CAP_GetFreeCapacity(base, CAP_LABSPACE), CAP_GetMax(base, CAP_LABSPACE));
168 	cgi->UI_ExecuteConfunc("ui_techlist_clear");
169 	cgi->UI_ExecuteConfunc("ui_research_details \"\" \"\" \"\"");
170 	for (int i = 0; i < ccs.numTechnologies; i++) {
171 		technology_t* tech = RS_GetTechByIDX(i);
172 		/* Don't show technologies with time == 0 - those are NOT separate research topics. */
173 		if (tech->time == 0)
174 			continue;
175 		/* hide finished research */
176 		if (tech->statusResearch == RS_FINISH)
177 			continue;
178 
179 		int percentage = 0;
180 		if (tech->overallTime > 0.0) {
181 			percentage = std::min(100, std::max(0, 100 - int(round(tech->time * 100.0 / tech->overallTime))));
182 		}
183 
184 		/* show researches that are running */
185 		if (tech->base && tech->scientists > 0) {
186 			if (tech->base == base) {
187 				cgi->UI_ExecuteConfunc("ui_techlist_add %s \"%s\" %d %d", tech->id, _(tech->name), tech->scientists, percentage);
188 			} else {
189 				cgi->UI_ExecuteConfunc("ui_techlist_add %s \"%s\" %d %d base %d \"%s\"", tech->id, _(tech->name), tech->scientists,
190 					percentage, tech->base->idx, tech->base->name);
191 			}
192 			continue;
193 		}
194 		/* show topics that are researchable on this base */
195 		const bool req = RS_RequirementsMet(tech, base);
196 		if (tech->statusResearchable && req) {
197 			cgi->UI_ExecuteConfunc("ui_techlist_add %s \"%s\" %d %d", tech->id, _(tech->name), tech->scientists, percentage);
198 			continue;
199 		}
200 		if (tech->statusCollected && !req) {
201 			cgi->UI_ExecuteConfunc("ui_techlist_add %s \"%s\" %d %d missing", tech->id, _(tech->name), tech->scientists, percentage);
202 			continue;
203 		}
204 	}
205 }
206 
RS_InitCallbacks(void)207 void RS_InitCallbacks (void)
208 {
209 	cgi->Cmd_AddCommand("ui_research_fill", RS_FillTechnologyList_f, "Fill research screen with list of researchable technologies");
210 	cgi->Cmd_AddCommand("ui_research_getdetails", RS_GetDetails_f, "Show technology image/model in reseach screen");
211 	cgi->Cmd_AddCommand("ui_research_stop", RS_Stop_f, "Stops the research");
212 	cgi->Cmd_AddCommand("ui_research_change", RS_Change_f, "Change number of scientists working on the research");
213 	cgi->Cmd_AddCommand("ui_research_max", RS_Max_f, "Allocates as much scientist on the research as possible");
214 }
215 
RS_ShutdownCallbacks(void)216 void RS_ShutdownCallbacks (void)
217 {
218 	cgi->Cmd_RemoveCommand("ui_research_fill");
219 	cgi->Cmd_RemoveCommand("ui_research_getdetails");
220 	cgi->Cmd_RemoveCommand("ui_research_stop");
221 	cgi->Cmd_RemoveCommand("ui_research_change");
222 	cgi->Cmd_RemoveCommand("ui_research_max");
223 }
224