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