1 /*
2 Copyright (C) 2004 by James Gregory
3 Part of the GalaxyHack project
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY.
9
10 See the COPYING file for more details.
11 */
12
13 #include "PreBattle.h"
14 #include "Globals.h"
15 #include "Group.h"
16 #include "Menu_Base.h"
17 #include "Stuff.h"
18 #include "RTS.h"
19 #include "Inlines.h"
20 #include "TerrainTile.h"
21 #include "Random.h"
22
23 #include <string>
24 #include <algorithm>
25
26 using std::string;
27 using std::find;
28
29 namespace PreBattle {
30 //global to this namespace
31 PBState pbState;
32
PreBattle_State()33 PreBattle_State::PreBattle_State() {
34 radarDragging = false;
35 viewSide = -1;
36
37 SeedRandom(globalSettings.randomSeed);
38
39 globalSettings.rememberFleets.clear();
40 for (int i = 0; i != sides.size(); ++i)
41 globalSettings.rememberFleets.push_back(sides[i].name);
42 while (globalSettings.rememberFleets.size() < maxPlayers)
43 globalSettings.rememberFleets.push_back("");
44
45 SetStartingRects();
46
47 SetupTerrain();
48
49 //FIXME
50 for (int i = 0; i != sides.size(); ++i)
51 sides[i].myFlag = i;
52
53 for (int i = 0; i != sides.size(); ++i) {
54 for (int j = 0; j != sides[i].groups.size(); ++j)
55 sides[i].groups[j].SetLaunchWait();
56 }
57
58 for (int i = 0; i != sides.size(); ++i) {
59 for (int j = 0; j != sides[i].groups.size(); ++j) {
60 sides[i].groups[j].ToggleDrawBound();
61 sides[i].groups[j].ToggleDrawNumber();
62 }
63 }
64
65 int totalGroups = 0;
66
67 for (int i = 0; i != sides.size(); ++i)
68 totalGroups += sides[i].groups.size();
69
70 int groupsPerFrame = totalGroups / staggerFrames;
71
72 //ensure scripts all start within the first 10 frames
73 //also ensure that groupsPerFrame is not 0 (i.e. if there are less than staggerFrames groups)
74 while (staggerFrames * groupsPerFrame < totalGroups)
75 ++groupsPerFrame;
76
77 int currentOpenFrame = 0;
78
79 vector<CoordsInt> doneGroups;
80
81 while (doneGroups.size() != totalGroups) {
82 int ranSide = Random() % sides.size();
83 int ranGroup = Random() % sides[ranSide].groups.size();
84
85 CoordsInt thisGroup = {ranSide, ranGroup};
86
87 if (find(doneGroups.begin(), doneGroups.end(), thisGroup) != doneGroups.end())
88 continue;
89 else {
90 sides[ranSide].groups[ranGroup].InitAI(currentOpenFrame);
91 doneGroups.push_back(thisGroup);
92 }
93
94 if (doneGroups.size() % groupsPerFrame == 0)
95 ++currentOpenFrame;
96 }
97
98 topRightBoxRect.x = globalSettings.screenWidth - 210;
99 topRightBoxRect.y = 10;
100 topRightBoxRect.w = 200;
101 topRightBoxRect.h = 200;
102
103 radarRect.x = topRightBoxRect.x + smallBorderSize;
104 radarRect.y = topRightBoxRect.y + smallBorderSize;
105 radarRect.w = topRightBoxRect.w - (smallBorderSize << 1);
106 radarRect.h = topRightBoxRect.h - (smallBorderSize << 1);
107
108 radarSurface = SDL_CreateRGBSurface(SDL_HWSURFACE, radarRect.w, radarRect.h, screenBPP, 0, 0, 0, 0);
109
110 SetStartingPositions();
111
112 SDL_Rect& myStartRect = sides[0].startingRect;
113
114 viewx = myStartRect.x + (myStartRect.w >> 1);
115 viewy = myStartRect.y + (myStartRect.h >> 1);
116
117 frameCounter = 0;
118
119 JSDL.LoadMusic(globalSettings.bdp + "music/corruptor.ogg");
120 JSDL.PlayMusic();
121 }
122
~PreBattle_State()123 PreBattle_State::~PreBattle_State() {
124 for (int i = 0; i != sides.size(); ++i) {
125 for (int j = 0; j != sides[i].groups.size(); ++j)
126 sides[i].groups[j].ResetForBattle();
127 }
128
129 //GST_PreBattle case to catch exceptions
130 if (gsTo == GST_MainMenu || gsTo == GST_PreBattle)
131 Unload();
132 }
133
Main()134 void PreBattle_State::Main() {
135 if (globalSettings.batch)
136 gsTo = GST_Battle;
137 RTS::ScrollAndDrag();
138
139 RTS::DrawWorld();
140
141 DrawAllWindows();
142 }
143
MouseD(Uint8 button,Uint16 x,Uint16 y)144 void PreBattle_State::MouseD(Uint8 button, Uint16 x, Uint16 y) {
145 RTS::RTSMouseD(button, x, y);
146 }
147
MouseU(Uint8 button,Uint16 x,Uint16 y)148 void PreBattle_State::MouseU(Uint8 button, Uint16 x, Uint16 y) {
149 RTS::RTSMouseU(button, x, y);
150 }
151
MouseM(Uint8 state,Uint16 x,Uint16 y)152 void PreBattle_State::MouseM(Uint8 state, Uint16 x, Uint16 y) {
153 RTS::RTSMouseM(state, x, y);
154 }
155
Keyboard(SDL_keysym & keysym)156 void PreBattle_State::Keyboard(SDL_keysym& keysym) {
157 RTS::RTSKeyboard(keysym);
158
159 if (keysym.sym == SDLK_s)
160 gsTo = GST_Battle;
161 }
162
SetStartingRects()163 void SetStartingRects() {
164 worldWidth = startingRectDim * 6;
165 worldHeight = startingRectDim * 6;
166
167 sides[0].startingRect.x = startingRectDim;
168 if (sides.size() < 3)
169 sides[0].startingRect.y = static_cast<float>(worldHeight * 0.5) - (startingRectDim / 2);
170 else
171 sides[0].startingRect.y = startingRectDim;
172
173 if (sides.size() > 1) {
174 sides[1].startingRect.x = worldWidth - startingRectDim * 2;
175 if (sides.size() < 3)
176 sides[1].startingRect.y = static_cast<float>(worldHeight * 0.5) - (startingRectDim / 2);
177 else
178 sides[1].startingRect.y = startingRectDim;
179 }
180
181 if (sides.size() == 3) {
182 sides[2].startingRect.x = static_cast<float>(worldWidth * 0.5) - (startingRectDim / 2);
183 sides[2].startingRect.y = worldHeight - startingRectDim * 2;
184 }
185 else if (sides.size() == 4) {
186 sides[2].startingRect.x = startingRectDim;
187 sides[2].startingRect.y = worldHeight - startingRectDim * 2;
188
189 sides[3].startingRect.x = worldWidth - startingRectDim * 2;
190 sides[3].startingRect.y = worldHeight - startingRectDim * 2;
191 }
192 }
193
SetStartingPositions()194 void SetStartingPositions() {
195 //start off by placing everyone outside world so we don't get false collisions with as yet unplaced groups
196 for (int i = 0; i != sides.size(); ++i) {
197 for (int j = 0; j != sides[i].groups.size(); ++j)
198 sides[i].groups[j].SetPos(worldWidth, worldHeight);
199 }
200
201 for (int i = 0; i != sides.size(); ++i) {
202 vector<bool> placedGroups(sides[i].groups.size(), false);
203
204 for (int j = 0; j != sides[i].groups.size(); ++j) {
205 if (sides[i].groups[j].GoToStartCoords())
206 placedGroups[j] = true;
207 }
208
209 for (int j = 0; j != placedGroups.size(); ++j) {
210 if (placedGroups[j] == false) {
211 if (pbState == PBS_Position)
212 FitGroupsInRemainingSpace(placedGroups);
213 else {
214 string errorMsg = sides[i].name + " have illegally positioned units";
215 throw runtime_error(errorMsg.c_str());
216 }
217 }
218 }
219 }
220 }
221
FitGroupsInRemainingSpace(vector<bool> placedGroups,bool ignoreOverlap)222 void FitGroupsInRemainingSpace(vector<bool> placedGroups, bool ignoreOverlap) {
223 /*
224 starting at offset (100, 100) try to place new groups
225 wherever they fit. After each placement check for overlap
226 or outside rect. if so, re-place. If we end up at
227 bottom of rect still with leftover groups then just
228 place all remaining evenly spaced from top left
229 of rectangle, tough luck if they overlap
230 */
231
232 int tempWidth, tempHeight;
233 int border = 100;
234
235 int x = sides[0].startingRect.x + border;
236 int y = sides[0].startingRect.y + border;
237
238 for (int i = 0; i != placedGroups.size(); ++i) {
239 //deal with ships with parents first. They always return 1
240 //to set pos, even if they/their parent is invalidly placed
241 if (sides[0].groups[i].GetParentCaSh() != -1) {
242 sides[0].groups[i].GoToStartCoords();
243 continue;
244 }
245
246 if (placedGroups[i] == true)
247 continue;
248
249 if (x > sides[0].startingRect.x + sides[0].startingRect.w - HCSWidth - border) {
250 y += 300;
251 x = sides[0].startingRect.x + border;
252 }
253
254 if (y > sides[0].startingRect.y + sides[0].startingRect.h - HCSHeight - border) {
255 if (ignoreOverlap)
256 throw runtime_error("Couldn't fit all the groups in the starting rect");
257 else
258 break;
259 }
260
261 if (sides[0].groups[i].SetPos(x, y) || ignoreOverlap) {
262 placedGroups[i] = true;
263 sides[0].groups[i].ChangeStartCoords(x, y);
264 } else
265 --i;
266
267 if (i > -1)
268 sides[0].groups[i].GetDimensions(tempWidth, tempHeight);
269 else
270 tempWidth = FrWidth;
271
272 x += tempWidth + border;
273 }
274
275 //any left over are placed ignoring any overlapping
276 for (int i = 0; i != placedGroups.size(); ++i) {
277 if (placedGroups[i] == false)
278 FitGroupsInRemainingSpace(placedGroups, 1);
279 }
280 }
281
SetupTerrain()282 void SetupTerrain() {
283 //load bitmaps into surfaces
284 terrainPictures.push_back(JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/spacetile.png", 0, 0, 4, 4, lightBlue));
285 terrainPictures.push_back(JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/spacetile2.png", 0, 0, 4, 4, lightBlue));
286
287 int total_tiles = (worldWidth/100)*(worldHeight/100);
288 int num_areas = std::sqrt(static_cast<float>(total_tiles));
289 int areas_per_side = std::sqrt(static_cast<float>(num_areas));
290 int area_dim = worldWidth / areas_per_side;
291 //not num_areas, because num_areas may well not have an exact square root so we need slightly more terrain areas to cover
292 //everywhere
293 int vector_size = (areas_per_side + 1) * (areas_per_side + 1);
294 terrainTree.resize(vector_size);
295
296 int x = 0;
297 int y = 0;
298
299 for (int i = 0; i != terrainTree.size(); ++i) {
300 terrainTree[i].rect.x = x;
301 terrainTree[i].rect.y = y;
302 terrainTree[i].rect.w = area_dim;
303 terrainTree[i].rect.h = area_dim;
304
305 terrainTree[i].tiles.reserve(vector_size);
306
307 for (int j = 0; j != vector_size; ++j) {
308 SDL_Rect tile_rect;
309 tile_rect.x = Random() % area_dim + x;
310 tile_rect.y = Random() % area_dim + y;
311 tile_rect.w = 4;
312 tile_rect.h = 4;
313 terrainTree[i].tiles.push_back(TerrainTile(terrainPictures[Random() % 2], tile_rect));
314 }
315
316 x += area_dim;
317 if (x > worldWidth) {
318 x = 0;
319 y += area_dim;
320 }
321 }
322 }
323
324
Unload()325 void Unload() {
326 UnloadGraphics();
327 sides.clear();
328 KillAllWindows();
329 }
330
UnloadGraphics()331 void UnloadGraphics() {
332 for (int i = 0; i != terrainPictures.size(); ++i)
333 SDL_FreeSurface(terrainPictures[i]);
334
335 terrainPictures.clear();
336 terrainTree.clear();
337
338 SDL_FreeSurface(radarSurface);
339 radarSurface = 0;
340 }
341
342 } //end namespace
343
344
345