-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOP2Helper.cpp
More file actions
267 lines (223 loc) · 8.4 KB
/
OP2Helper.cpp
File metadata and controls
267 lines (223 loc) · 8.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#include "OP2Helper.h"
#include <utility>
#include <functional>
// (Workers, Scientists, Kids, Food, Common Ore, [Rare Ore]) (Zero-fill to end if list is short)
const ResourceSet CES1ResourceSet = {
{
{ 28, 13, 15, 3000, 5000 }, // Easy
{ 26, 13, 15, 2000, 4000 }, // Medium
{ 23, 13, 15, 1000, 3000 }, // Hard
}
};
const ResourceSet MultiResourceSet = {
{
{ 27, 18, 22, 3000, 6000 }, // Easy
{ 24, 15, 20, 2000, 4000 }, // Medium
{ 20, 12, 18, 1000, 2000 }, // Hard
}
};
// Perform function discretely along a line or L shape
void ExecuteAcrossLine(LOCATION loc1, LOCATION loc2, const std::function <void(int x, int y)>& function);
// Assuming loc1 and loc2 form a rectangle:
// Set loc1 to the top left
// Set loc2 to the bottom right
void SwapLocations(LOCATION& loc1, LOCATION& loc2);
// Initializes player starting resources including:
// Workers, Scientists, Children, Food Stored, Common Ore, Rare Ore
void InitPlayerResources(int playerNum, const ResourceSet& resourceSet)
{
// Cache a reference to the specified Player
_Player &player = Player[playerNum];
// Cache a reference to the resource settings for Player's difficulty level
const Resources& resources = resourceSet.level[player.Difficulty()];
// Set the player's resources
player.SetWorkers(resources.workers);
player.SetScientists(resources.scientists);
player.SetKids(resources.kids);
player.SetFoodStored(resources.food);
player.SetOre(resources.commonOre);
player.SetRareOre(resources.rareOre);
}
void CreateTubeLine(LOCATION loc1, LOCATION loc2)
{
ExecuteAcrossLine(loc1, loc2,
[](int x, int y) { TethysGame::CreateWallOrTube(x, y, 0, map_id::mapTube); }
);
}
void CreateWallLine(LOCATION loc1, LOCATION loc2)
{
ExecuteAcrossLine(loc1, loc2,
[](int x, int y) { TethysGame::CreateWallOrTube(x, y, 0, map_id::mapWall); }
);
}
void CreateLavaWallLine(LOCATION loc1, LOCATION loc2)
{
ExecuteAcrossLine(loc1, loc2,
[](int x, int y) { TethysGame::CreateWallOrTube(x, y, 0, map_id::mapLavaWall); }
);
}
void CreateMicrobeWallLine(LOCATION loc1, LOCATION loc2)
{
ExecuteAcrossLine(loc1, loc2,
[](int x, int y) { TethysGame::CreateWallOrTube(x, y, 0, map_id::mapMicrobeWall); }
);
}
void RecordTubeLine(BuildingGroup& buildingGroup, LOCATION loc1, LOCATION loc2)
{
ExecuteAcrossLine(loc1, loc2,
[ &buildingGroup ] (int x, int y) { LOCATION location(x, y); buildingGroup.RecordTube(location); }
);
}
void RecordWallLine(BuildingGroup& buildingGroup, const LOCATION& loc1, const LOCATION& loc2)
{
ExecuteAcrossLine(loc1, loc2,
[ &buildingGroup ] (int x, int y) { LOCATION location(x, y); buildingGroup.RecordWall(location, map_id::mapWall); }
);
}
void RecordLavaWallLine(BuildingGroup& buildingGroup, const LOCATION& loc1, const LOCATION& loc2)
{
ExecuteAcrossLine(loc1, loc2,
[ &buildingGroup ] (int x, int y) { LOCATION location(x, y); buildingGroup.RecordWall(location, map_id::mapLavaWall); }
);
}
void RecordMicrobeWallLine(BuildingGroup& buildingGroup, const LOCATION& loc1, const LOCATION& loc2)
{
ExecuteAcrossLine(loc1, loc2,
[ &buildingGroup ] (int x, int y) { LOCATION location(x, y); buildingGroup.RecordWall(location, map_id::mapMicrobeWall); }
);
}
void ExecuteAcrossLine(LOCATION loc1, LOCATION loc2, const std::function <void(int x, int y)>& function)
{
// Determine edges to record along
const int vertEdge = loc2.x;
const int horizEdge = loc1.y;
SwapLocations(loc1, loc2);
// Record horizontal section
for (int x = loc1.x; x <= loc2.x; ++x) {
function(x, horizEdge);
}
// Record vertical section
for (int y = loc1.y; y <= loc2.y; ++y) {
function(vertEdge, y);
}
}
void SwapLocations(LOCATION& loc1, LOCATION& loc2)
{
// Make sure (x1 <= x2) and (y1 <= y2)
if (loc1.x > loc2.x) {
std::swap(loc1.x, loc2.x);
}
if (loc1.y > loc2.y) {
std::swap(loc1.y, loc2.y);
}
}
// Create a line of wall or tube
// Draws along the horizontal first:
// If coordinates represent a bent wall/tube then it draws
// horizontal between x1 and x2 (along y1) and then
// vertical between y1 and y2 (along x2)
void CreateTubeOrWallLine(int x1, int y1, int x2, int y2, map_id type)
{
const LOCATION loc1(x1, y1);
const LOCATION loc2(x2, y2);
switch (type)
{
case mapTube: {
CreateTubeLine(loc1, loc2);
return;
}
case mapWall: {
CreateWallLine(loc1, loc2);
return;
}
case mapLavaWall: {
CreateLavaWallLine(loc1, loc2);
return;
}
case mapMicrobeWall: {
CreateMicrobeWallLine(loc1, loc2);
return;
}
}
}
void CreateStarshipVictoryCondition()
{
Trigger trigger;
// Create victory conditions for - Colony, Starship
trigger = CreateCountTrigger(1, 1, -1, mapEvacuationModule, mapAny, 1, cmpGreaterEqual, "NoResponseToTrigger");
CreateVictoryCondition(1, 1, trigger, "Evacuate 200 colonists to spacecraft");
trigger = CreateCountTrigger(1, 1, -1, mapFoodCargo, mapAny, 1, cmpGreaterEqual, "NoResponseToTrigger");
CreateVictoryCondition(1, 1, trigger, "Evacuate 10000 units of food to spacecraft");
trigger = CreateCountTrigger(1, 1, -1, mapCommonMetalsCargo, mapAny, 1, cmpGreaterEqual, "NoResponseToTrigger");
CreateVictoryCondition(1, 1, trigger, "Evacuate 10000 units of Commom Metals to spacecraft");
trigger = CreateCountTrigger(1, 1, -1, mapRareMetalsCargo, mapAny, 1, cmpGreaterEqual, "NoResponseToTrigger");
CreateVictoryCondition(1, 1, trigger, "Evacuate 10000 units of Rare Metals to spacecraft");
}
// For use in multiplayer. Note: Computer controlled opponents do not count towards this.
// You win when there is only one human opponent left or all surviving human players are allied.
// This also creates corresponding failure conditions
void CreateLastOneStandingVictoryCondition()
{
Trigger trigger = CreateOnePlayerLeftTrigger(1, 1, "NoResponseToTrigger");
CreateVictoryCondition(1, 1, trigger, "Eliminate your opponents.");
}
// Fail if the number of active Command Centers becomes equal to 0.
void CreateNoCommandCenterFailureCondition(int playerNum)
{
Trigger trigger = CreateOperationalTrigger(1, 1, playerNum, mapCommandCenter, 0, cmpEqual, "NoResponseToTrigger");
CreateFailureCondition(1, 1, trigger, "");
}
LOCATION& operator+= (LOCATION& loc1, const LOCATION& loc2) {
loc1.x += loc2.x;
loc1.y += loc2.y;
return loc1;
}
LOCATION& operator-= (LOCATION& loc1, const LOCATION& loc2) {
loc1.x -= loc2.x;
loc1.y -= loc2.y;
return loc1;
}
LOCATION operator+ (LOCATION loc1, const LOCATION &loc2) {
return loc1 += loc2;
}
LOCATION operator- (LOCATION loc1, const LOCATION &loc2) {
return loc1 -= loc2;
}
bool operator== (const LOCATION& loc1, const LOCATION &loc2) {
return (loc1.x == loc2.x && loc1.y == loc2.y);
}
bool operator!= (const LOCATION& loc1, const LOCATION &loc2) {
return !(loc1 == loc2);
}
// Centers the local player's view on their CommandCenter, if they have one.
void CenterViewOnPlayerCC() {
Unit commandCenter;
int localPlayer = TethysGame::LocalPlayer();
PlayerBuildingEnum commandCenterEnum(localPlayer, mapCommandCenter);
// Find first Command Center (if one exists)
if (commandCenterEnum.GetNext(commandCenter)) {
LOCATION commandCenterLoc = commandCenter.Location();
Player[localPlayer].CenterViewOn(commandCenterLoc.x, commandCenterLoc.y);
}
}
void CenterViewOn(enum PlayerNum playerNum, const LOCATION& location) {
Player[playerNum].CenterViewOn(location.x, location.y);
}
void AddMapMessage(const char* message, const Unit& sourceUnit, int soundIndex, int toPlayerNum) {
// Message is not modified by Outpost 2, but was not declared as const. Cast to avoid warnings/errors.
TethysGame::AddMessage(sourceUnit, const_cast<char*>(message), toPlayerNum, soundIndex);
}
void AddMapMessage(const char* message, const LOCATION& location, int soundIndex, int toPlayerNum)
{
// Convert location from tiles to pixels
AddMapMessage(message, location.x * 32 + 16, location.y * 32 + 16, soundIndex, toPlayerNum);
}
void AddMapMessage(const char* message, int pixelX, int pixelY, int soundIndex, int toPlayerNum)
{
// Message is not modified by Outpost 2, but was not declared as const. Cast to avoid warnings/errors.
TethysGame::AddMessage(pixelX, pixelY, const_cast<char*>(message), toPlayerNum, soundIndex);
}
void AddGameMessage(const char* message, int soundIndex, int toPlayerNum)
{
AddMapMessage(message, -1, -1, soundIndex, toPlayerNum);
}