1 /**
2 Horrid Highway
3 Players need to completely excavate the sky island far away.
4
5 @author Maikel
6 */
7
8
9 // Whether the intro has been initialized.
10 static intro_init;
11
Initialize()12 protected func Initialize()
13 {
14 // Show wealth in HUD.
15 GUI_Controller->ShowWealth();
16
17 // Goal: locomotive highway.
18 var goal = CreateObject(Goal_LocomotiveHighway);
19 goal.LocomotiveGoal = 8 * SCENPAR_Difficulty;
20
21 // Rules: team account and buying at flagpole.
22 CreateObject(Rule_TeamAccount);
23 CreateObject(Rule_BuyAtFlagpole);
24
25 // Allow for base respawns.
26 var relaunch_rule = GetRelaunchRule();
27 relaunch_rule->SetInventoryTransfer(false);
28 relaunch_rule->SetLastClonkRespawn(true);
29 relaunch_rule->SetFreeCrew(false);
30 relaunch_rule->SetAllowPlayerRestart(true);
31 relaunch_rule->SetBaseRespawn(true);
32 relaunch_rule->SetRespawnDelay(0);
33
34 // Initialize different parts of the scenario.
35 InitEnvironment(SCENPAR_Difficulty);
36 InitVegetation();
37 InitAnimals(SCENPAR_Difficulty);
38 InitBridges();
39 InitLeftIsland();
40 InitMiddleIsland();
41 InitRightIsland();
42 InitDisasters(SCENPAR_Difficulty);
43 return;
44 }
45
OnGoalsFulfilled()46 protected func OnGoalsFulfilled()
47 {
48 // Give the remaining players their achievement.
49 GainScenarioAchievement("Done", BoundBy(SCENPAR_Difficulty, 1, 3));
50 return false;
51 }
52
53
54 /*-- Player Initialization --*/
55
InitializePlayer(int plr)56 protected func InitializePlayer(int plr)
57 {
58 // Zoom range.
59 SetPlayerZoomByViewRange(plr, 1200, nil, PLRZOOM_LimitMax);
60 SetPlayerZoomByViewRange(plr, 500, nil, PLRZOOM_Direct | PLRZOOM_Set);
61 SetPlayerViewLock(plr, true);
62
63 // Position and materials.
64 var i, crew;
65 for (i = 0; crew = GetCrew(plr, i); ++i)
66 {
67 crew->SetPosition(100, LandscapeHeight() / 2 - 10);
68 crew->CreateContents(Shovel);
69 }
70
71 // Give the player its knowledge.
72 GivePlayerBasicKnowledge(plr);
73 GivePlayerPumpingKnowledge(plr);
74 GivePlayerFarmingKnowledge(plr);
75 GivePlayerWeaponryKnowledge(plr);
76 GivePlayerArtilleryKnowledge(plr);
77 GivePlayerAdvancedKnowledge(plr);
78 GivePlayerAirKnowledge(plr);
79
80 // Give the player its base materials.
81 GivePlayerElementaryBaseMaterial(plr);
82 GivePlayerToolsBaseMaterial(plr);
83 GivePlayerSpecificBaseMaterial(plr, [[Dynamite, 20, 10]]);
84
85 // Claim ownership of structures, last player who joins owns all the flags.
86 for (var structure in FindObjects(Find_Or(Find_Category(C4D_Structure), Find_Func("IsFlagpole"))))
87 structure->SetOwner(plr);
88
89 // Ensure mimimum player wealth.
90 var add_wealth = Max(0, 75 - 25 * SCENPAR_Difficulty - GetWealth(plr));
91 DoWealth(plr, add_wealth);
92
93 // Initialize the intro sequence if not yet started.
94 if (!intro_init)
95 {
96 StartSequence("Intro", 0);
97 intro_init = true;
98 }
99 return;
100 }
101
102
103 /*-- Scenario Initialization --*/
104
105 // Initializes environment and disasters.
InitEnvironment(int difficulty)106 private func InitEnvironment(int difficulty)
107 {
108 // Init time and have normal cycle.
109 Time->Init();
110
111 // Set a certain parallax.
112 SetSkyParallax(0, 20, 20);
113
114 // Adjust sky dependent on difficulty setting.
115 if (difficulty == 3)
116 SetSkyAdjust(RGBa(225, 255, 205, 191), RGB(63, 200, 0));
117
118 // Clouds and rain.
119 Cloud->Place(15);
120 Cloud->SetPrecipitation("Water", 60);
121 if (difficulty == 3)
122 Cloud->SetPrecipitation("Acid", 60);
123 return;
124 }
125
126 // Initializes grass, trees and in-earth objects.
InitVegetation()127 private func InitVegetation()
128 {
129 // Grass on all islands.
130 Grass->Place(100);
131
132 // Vegetation around all islands.
133 Flower->Place(20);
134 Mushroom->Place(20);
135 Fern->Place(12);
136 Branch->Place(30);
137 Trunk->Place(8);
138 Vine->Place(18, nil, {attach_material = Loc_Or(Loc_Material("Granite"), Loc_Material("Rock"), Loc_Material("Everrock"), Loc_Material("Gold"))});
139 Cotton->Place(8);
140 Wheat->Place(8);
141
142 // Some objects in the earth.
143 PlaceObjects(Rock, 40, "Earth");
144 PlaceObjects(Firestone, 40, "Earth");
145 PlaceObjects(Loam, 30, "Earth");
146
147 // Place some trees.
148 Tree_Deciduous->Place(20, Rectangle(0, 0, 600, LandscapeHeight() / 3));
149 Tree_Deciduous->Place(20, Rectangle(LandscapeWidth() - 600, 0, 600, LandscapeHeight() / 3));
150 Tree_Coniferous2->Place(12, Rectangle(0, 0, 600, LandscapeHeight() / 3));
151 Tree_Coniferous2->Place(12, Rectangle(LandscapeWidth() - 600, 0, 600, LandscapeHeight() / 3));
152 return;
153 }
154
155 // Initializes animals.
InitAnimals(int difficulty)156 private func InitAnimals(int difficulty)
157 {
158 // Some fireflies attracted to trees.
159 Firefly->Place(6);
160 // Place some bats depending on difficulties.
161 var bat_region = Rectangle(LandscapeWidth() - 600, 0, 600, LandscapeHeight());
162 if (difficulty >= 2)
163 bat_region = Rectangle(LandscapeWidth() / 2 - 300, 0, LandscapeWidth() / 2 + 300, LandscapeHeight());
164 Bat->Place(10 * difficulty + 5 * difficulty**2, bat_region, {tunnel_only = true});
165 // Place zaps on higher difficulties.
166 if (difficulty >= 2)
167 Zaphive->Place(2 * difficulty);
168 return;
169 }
170
InitBridges()171 private func InitBridges()
172 {
173 // Create four indestructible bridges to connect.
174 var height = LandscapeHeight() / 2 + 6;
175 var x4 = 4;
176 while (GetMaterial(x4, height) == Material("Brick"))
177 x4 += 8;
178 var x1 = x4;
179 while (GetMaterial(x4, height) != Material("Brick") || x4 < LandscapeWidth() / 4)
180 x4 += 8;
181 var x2 = x4;
182 while (GetMaterial(x4, height) == Material("Brick") || x4 < LandscapeWidth() / 2)
183 x4 += 8;
184 var x3 = x4;
185 while (GetMaterial(x4, height) != Material("Brick") || 3 * x4 < LandscapeWidth() / 4)
186 x4 += 8;
187 var bridge;
188 bridge = CreateObject(WoodenBridge, x1 + 20, height);
189 bridge->MakeInvincible();
190 bridge->SetClrModulation(RGB(80, 120, 200));
191 bridge = CreateObject(WoodenBridge, x2 - 20, height);
192 bridge->MakeInvincible();
193 bridge->SetClrModulation(RGB(80, 120, 200));
194 bridge = CreateObject(WoodenBridge, x3 + 20, height);
195 bridge->MakeInvincible();
196 bridge->SetClrModulation(RGB(80, 120, 200));
197 bridge = CreateObject(WoodenBridge, x4 - 20, height);
198 bridge->MakeInvincible();
199 bridge->SetClrModulation(RGB(80, 120, 200));
200 return;
201 }
202
InitLeftIsland()203 private func InitLeftIsland()
204 {
205 var switch = CreateObjectAbove(Switch, 20, LandscapeHeight() / 2);
206 var goal = FindObject(Find_ID(Goal_LocomotiveHighway));
207 goal->SetPlrViewOnSignalChange(false);
208 switch->SetSwitchTarget(goal);
209 switch->SetSwitchDir(-1);
210
211 var guidepost = CreateObjectAbove(EnvPack_Guidepost2, 40, LandscapeHeight() / 2);
212 guidepost->SetInscription("$MsgHorridHighwayEast$");
213 guidepost.MeshTransformation = EnvPack_Guidepost2.MeshTransformation;
214
215 var lorry = CreateObjectAbove(Lorry, 80, LandscapeHeight() / 2 - 2);
216 lorry->CreateContents(Shovel, 2);
217 lorry->CreateContents(Hammer, 2);
218 lorry->CreateContents(Axe, 2);
219 lorry->CreateContents(Barrel, 2);
220
221 var elevator = CreateObjectAbove(Elevator, 180, 384);
222 elevator->CreateShaft(196);
223 CreateObjectAbove(Compensator, 230, 384);
224
225 var workshop = CreateObjectAbove(ToolsWorkshop, 156, 480);
226 workshop->CreateContents(Wood, 8);
227 workshop->CreateContents(Metal, 8);
228
229 var chemical_lab = CreateObjectAbove(ChemicalLab, 160, 584);
230 chemical_lab->CreateContents(Firestone, 8);
231 chemical_lab->CreateContents(Coal, 8);
232 CreateObjectAbove(Flagpole, 120, 584);
233
234 var bridge = FindObject(Find_ID(WoodenBridge), Sort_Distance(0, LandscapeHeight() / 2));
235 bridge->CreateObjectAbove(WindGenerator, 0, -4);
236 bridge->CreateObjectAbove(Flagpole, -36, -4);
237 bridge->CreateObjectAbove(Catapult, 6, -6);
238 return;
239 }
240
InitMiddleIsland()241 private func InitMiddleIsland()
242 {
243 var lorry = CreateObjectAbove(Lorry, LandscapeWidth() / 2 + RandomX(-20, 20), LandscapeHeight() / 2 - 2);
244 lorry->CreateContents(Firestone, 12);
245 lorry->CreateContents(Dynamite, 12);
246 lorry->CreateContents(DynamiteBox, 8);
247 lorry->CreateContents(PowderKeg, 8);
248 lorry->CreateContents(Pickaxe, 2);
249
250 var guidepost = CreateObjectAbove(EnvPack_Guidepost2, LandscapeWidth() / 2 + 40, LandscapeHeight() / 2);
251 guidepost->SetInscription("$MsgResourcesWest$");
252 guidepost.MeshTransformation = EnvPack_Guidepost2.MeshTransformation;
253
254 var diamond_cnt = 12;
255 for (var cnt = 0; cnt < diamond_cnt; cnt++)
256 {
257 var pos = FindLocation(Loc_Material("Gold"));
258 if (pos)
259 {
260 CreateObject(Diamond_Socket, pos.x, pos.y);
261 }
262 }
263 return;
264 }
265
InitRightIsland()266 private func InitRightIsland()
267 {
268 var guidepost = CreateObjectAbove(EnvPack_Guidepost2, LandscapeWidth() - 40, LandscapeHeight() / 2);
269 guidepost->SetInscription("$MsgHorridHighwayWest$");
270 guidepost.MeshTransformation = EnvPack_Guidepost2.MeshTransformation;
271
272 var elevator = CreateObjectAbove(Elevator, LandscapeWidth() - 180, 384);
273 elevator->CreateShaft(196);
274
275 var foundry = CreateObjectAbove(Foundry, LandscapeWidth() - 100, 384);
276 foundry->CreateContents(Coal, 8);
277
278 CreateObjectAbove(WoodenCabin, LandscapeWidth() - 100, 480);
279 return;
280 }
281
InitDisasters(int difficulty)282 private func InitDisasters(int difficulty)
283 {
284 // Lightning: clouds are already inited.
285 Cloud->SetLightning(3 * difficulty**2 + difficulty + 2);
286 // Rockfall: appears around the central sky island.
287 if (difficulty >= 2)
288 {
289 Rockfall->SetChance(10 * (difficulty - 1));
290 Rockfall->SetArea(Rectangle(LandscapeWidth() / 2 - 200, 0, 400, 20));
291 if (difficulty >= 3)
292 Rockfall->SetExplosiveness(100);
293 }
294 // Meteors: controlled by effect to happen between the main islands.
295 CreateEffect(FxControlMeteors, 100, 1, difficulty);
296 return;
297 }
298
299 static const FxControlMeteors = new Effect
300 {
func(int difficulty)301 Construction = func(int difficulty)
302 {
303 this.difficulty = difficulty;
304 this.chance = 9 * difficulty + 3 * difficulty**2;
305 this.Interval = 10;
306 // Find spawn range according to outer bridges.
307 var bridge_left = FindObject(Find_ID(WoodenBridge), Sort_Distance(0, LandscapeHeight() / 2));
308 var bridge_right = FindObject(Find_ID(WoodenBridge), Sort_Distance(LandscapeWidth(), LandscapeHeight() / 2));
309 this.spawn_range = [bridge_left->GetX() + 134, bridge_right->GetX() - 134];
310 return FX_OK;
311 },
312 Timer = func(int time)
313 {
314 if (Random(100) >= 100 - this.chance)
315 {
316 var x = RandomX(this.spawn_range[0], this.spawn_range[1]);
317 var spawn_id = nil;
318 if (this.difficulty >= 3 && !Random(3))
319 spawn_id = Chippie_Egg;
320 LaunchMeteor(x, -12, RandomX(40, 60), RandomX(-15, 15), RandomX(40, 50), spawn_id);
321 }
322 return FX_OK;
323 }
324 };
325
326