...
[xonotic/netradiant.git] / contrib / ufoai / ufoai_level.cpp
1 /*
2 This file is part of GtkRadiant.
3
4 GtkRadiant is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 GtkRadiant is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GtkRadiant; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #include "ufoai_level.h"
20 #include "ufoai_filters.h"
21
22 #include "ibrush.h"
23 #include "ientity.h"
24 #include "iscenegraph.h"
25
26 #include "string/string.h"
27 #include <list>
28
29 class Level;
30
31 /**
32  * @brief find entities by class
33  * @note from radiant/map.cpp
34  */
35 class EntityFindByClassname : public scene::Graph::Walker
36 {
37         const char* m_name;
38         Entity*& m_entity;
39 public:
40         EntityFindByClassname(const char* name, Entity*& entity) : m_name(name), m_entity(entity)
41         {
42                 m_entity = 0;
43         }
44         bool pre(const scene::Path& path, scene::Instance& instance) const
45         {
46                 if(m_entity == 0)
47                 {
48                         Entity* entity = Node_getEntity(path.top());
49                         if(entity != 0 && string_equal(m_name, entity->getKeyValue("classname")))
50                         {
51                                 m_entity = entity;
52                         }
53                 }
54                 return true;
55         }
56 };
57
58 /**
59  * @brief
60  */
61 Entity* Scene_FindEntityByClass(const char* name)
62 {
63         Entity* entity = NULL;
64         GlobalSceneGraph().traverse(EntityFindByClassname(name, entity));
65         return entity;
66 }
67
68 /**
69  * @brief finds start positions
70  */
71 class EntityFindTeams : public scene::Graph::Walker
72 {
73         const char *m_classname;
74         int *m_count;
75         int *m_team;
76
77 public:
78         EntityFindTeams(const char *classname, int *count, int *team) : m_classname(classname), m_count(count), m_team(team)
79         {
80         }
81         bool pre(const scene::Path& path, scene::Instance& instance) const
82         {
83                 const char *str;
84                 Entity* entity = Node_getEntity(path.top());
85                 if(entity != 0 && string_equal(m_classname, entity->getKeyValue("classname")))
86                 {
87                         if (m_count)
88                                 (*m_count)++;
89                         // now get the highest teamnum
90                         if (m_team)
91                         {
92                                 str = entity->getKeyValue("team");
93                                 if (!string_empty(str))
94                                 {
95                                         if (atoi(str) > *m_team)
96                                                 (*m_team) = atoi(str);
97                                 }
98                         }
99                 }
100                 return true;
101         }
102 };
103
104 /**
105  * @brief
106  */
107 void get_team_count (const char *classname, int *count, int *team)
108 {
109         GlobalSceneGraph().traverse(EntityFindTeams(classname, count, team));
110         globalOutputStream() << "UFO:AI: classname: " << classname << ": #" << (*count) << "\n";
111 }
112
113 /**
114  * @brief Some default values to worldspawn like maxlevel, maxteams and so on
115  */
116 void assign_default_values_to_worldspawn (bool override, bool day, char **returnMsg)
117 {
118         static char message[1024];
119         Entity* worldspawn;
120         int teams = 0;
121         int count = 0;
122         char str[64];
123
124         worldspawn = Scene_FindEntityByClass("worldspawn");
125         if (!worldspawn)
126         {
127                 globalOutputStream() << "UFO:AI: Could not find worldspawn.\n";
128                 *returnMsg = "Could not find worldspawn";
129                 return;
130         }
131
132         *message = '\0';
133         *str = '\0';
134
135         get_team_count("info_player_start", &count, &teams);
136
137         // TODO: Get highest brush - a level has 64 units
138         worldspawn->setKeyValue("maxlevel", "5");
139
140         if (string_empty(worldspawn->getKeyValue("maxteams"))
141          || atoi(worldspawn->getKeyValue("maxteams")) != teams)
142         {
143                 snprintf(str, sizeof(str) - 1, "%i", teams);
144                 worldspawn->setKeyValue("maxteams", str);
145                 strncat(message, "Worldspawn: Set maxteams to ", sizeof(message) - 1);
146                 strncat(message, str, sizeof(message) - 1);
147                 strncat(message, "\n", sizeof(message) - 1);
148         }
149
150         if (day)
151         {
152                 if (override)
153                 {
154                         worldspawn->setKeyValue("light", "160");
155                         worldspawn->setKeyValue("_color", "1 0.8 0.8");
156                         worldspawn->setKeyValue("angles", "30 210");
157                         worldspawn->setKeyValue("ambient", "0.4 0.4 0.4");
158                 }
159                 else
160                 {
161                         if (string_empty(worldspawn->getKeyValue("light")))
162                         {
163                                 worldspawn->setKeyValue("light", "160");
164                                 snprintf(&message[strlen(message)], sizeof(message) - 1 - strlen(message), "Set ambient to: %s", worldspawn->getKeyValue("ambient"));
165                         }
166                         if (string_empty(worldspawn->getKeyValue("_color")))
167                         {
168                                 worldspawn->setKeyValue("_color", "1 0.8 0.8");
169                                 snprintf(&message[strlen(message)], sizeof(message) - 1 - strlen(message), "Set ambient to: %s", worldspawn->getKeyValue("ambient"));
170                         }
171                         if (string_empty(worldspawn->getKeyValue("angles")))
172                         {
173                                 worldspawn->setKeyValue("angles", "30 210");
174                                 snprintf(&message[strlen(message)], sizeof(message) - 1 - strlen(message), "Set ambient to: %s", worldspawn->getKeyValue("ambient"));
175                         }
176                         if (string_empty(worldspawn->getKeyValue("ambient")))
177                         {
178                                 worldspawn->setKeyValue("ambient", "0.4 0.4 0.4");
179                                 snprintf(&message[strlen(message)], sizeof(message) - 1 - strlen(message), "Set ambient to: %s", worldspawn->getKeyValue("ambient"));
180                         }
181                 }
182         }
183         else
184         {
185                 if (override)
186                 {
187                         worldspawn->setKeyValue("light", "60");
188                         worldspawn->setKeyValue("_color", "0.8 0.8 1");
189                         worldspawn->setKeyValue("angles", "15 60");
190                         worldspawn->setKeyValue("ambient", "0.25 0.25 0.275");
191                 }
192                 else
193                 {
194                         if (string_empty(worldspawn->getKeyValue("light")))
195                         {
196                                 worldspawn->setKeyValue("light", "60");
197                                 snprintf(&message[strlen(message)], sizeof(message) - 1 - strlen(message), "Set ambient to: %s", worldspawn->getKeyValue("ambient"));
198                         }
199                         if (string_empty(worldspawn->getKeyValue("_color")))
200                         {
201                                 worldspawn->setKeyValue("_color", "0.8 0.8 1");
202                                 snprintf(&message[strlen(message)], sizeof(message) - 1 - strlen(message), "Set ambient to: %s", worldspawn->getKeyValue("ambient"));
203                         }
204                         if (string_empty(worldspawn->getKeyValue("angles")))
205                         {
206                                 worldspawn->setKeyValue("angles", "15 60");
207                                 snprintf(&message[strlen(message)], sizeof(message) - 1 - strlen(message), "Set ambient to: %s", worldspawn->getKeyValue("ambient"));
208                         }
209                         if (string_empty(worldspawn->getKeyValue("ambient")))
210                         {
211                                 worldspawn->setKeyValue("ambient", "0.25 0.25 0.275");
212                                 snprintf(&message[strlen(message)], sizeof(message) - 1 - strlen(message), "Set ambient to: %s", worldspawn->getKeyValue("ambient"));
213                         }
214                 }
215         }
216
217         if (override)
218         {
219                 snprintf(&message[strlen(message)], sizeof(message) - 1 - strlen(message),
220                         "Set light to: %s\n"
221                         "Set _color to: %s\n"
222                         "Set angles to: %s\n"
223                         "Set ambient to: %s\n",
224                         worldspawn->getKeyValue("light"),
225                         worldspawn->getKeyValue("_color"),
226                         worldspawn->getKeyValue("angles"),
227                         worldspawn->getKeyValue("ambient")
228                 );
229         }
230
231         // no errors - no warnings
232         if (!strlen(message))
233                 return;
234
235         *returnMsg = message;
236 }
237
238 /**
239  * @brief Will check e.g. the map entities for valid values
240  * @todo: Check whether all misc_model and func_breakable have spawnflags
241  * @todo: check for maxlevel
242  */
243 void check_map_values (char **returnMsg)
244 {
245         static char message[1024];
246         int count = 0;
247         int teams = 0;
248         Entity* worldspawn;
249         char str[64];
250
251         worldspawn = Scene_FindEntityByClass("worldspawn");
252         if (!worldspawn)
253         {
254                 globalOutputStream() << "UFO:AI: Could not find worldspawn.\n";
255                 *returnMsg = "Could not find worldspawn";
256                 return;
257         }
258
259         *message = '\0';
260         *str = '\0';
261
262         // multiplayer start positions
263         get_team_count("info_player_start", &count, &teams);
264         if (!count)
265                 strncat(message, "No multiplayer start positions (info_player_start)\n", sizeof(message) - 1);
266         else if (string_empty(worldspawn->getKeyValue("maxteams")))
267         {
268                 snprintf(message, sizeof(message) - 1, "Worldspawn: No maxteams defined (#info_player_start) (set to: %i)\n", teams);
269                 snprintf(str, sizeof(str) - 1, "%i", teams);
270                 worldspawn->setKeyValue("maxteams", str);
271         }
272         else if (teams != atoi(worldspawn->getKeyValue("maxteams")))
273                 snprintf(message, sizeof(message) - 1, "Worldspawn: Settings for maxteams (%s) doesn't match team count (%i)\n", worldspawn->getKeyValue("maxteams"), teams);
274
275         // singleplayer map?
276         count = 0;
277         get_team_count("info_human_start", &count, NULL);
278         if (!count)
279                 strncat(message, "No singleplayer start positions (info_human_start)\n", sizeof(message) - 1);
280
281         // search for civilians
282         count = 0;
283         get_team_count("info_civilian_start", &count, NULL);
284         if (!count)
285                 strncat(message, "No civilian start positions (info_civilian_start)\n", sizeof(message) - 1);
286
287         // check maxlevel
288         if (string_empty(worldspawn->getKeyValue("maxlevel")))
289                 strncat(message, "Worldspawn: No maxlevel defined\n", sizeof(message) - 1);
290         else if (atoi(worldspawn->getKeyValue("maxlevel")) > 8)
291         {
292                 strncat(message, "Worldspawn: Highest maxlevel is 8\n", sizeof(message) - 1);
293                 worldspawn->setKeyValue("maxlevel", "8");
294         }
295         // no errors - no warnings
296         if (!strlen(message))
297                 return;
298
299         *returnMsg = message;
300 }