1 /*--
2 	ForgottenHeights
3 	Author: Mimmo_O
4 
5 	Last man Standing on sky islands for up to 12 players.
6 --*/
7 
8 
9 static Overcast_air_particles;
10 
Initialize()11 protected func Initialize()
12 {
13 	// Goal.
14 	CreateObject(Goal_LastManStanding);
15 	CreateObject(Rule_KillLogs);
16 	CreateObject(Rule_Gravestones);
17 	GetRelaunchRule()->SetLastWeaponUse(false);
18 
19 	//Enviroment.
20 	Cloud->Place(25);
21 	SetSkyAdjust(RGBa(250,250,255,128),RGB(200,200,220));
22 	Sound("Environment::BirdsLoop", true, 100, nil, 1);
23 
24 	// Brick edges at horizontal moving bricks.
25 	var x = [524, 436, 436, 524, 812, 812, 716, 716, 572, 572, 212, 212];
26 	var y = [692, 676, 692, 676, 652, 668, 500, 484, 500, 484, 676, 692];
27 	var d = [1, 3, 2, 0, 3, 2, 2, 3, 1, 0, 0, 1];
28 	for (var i = 0; i < GetLength(x); i++)
29 		DrawMaterialTriangle("Brick-brick", x[i], y[i], d[i]);
30 
31 	// Vertically moving bricks
32 	var brick = CreateObjectAbove(MovingBrick, 660, 90);
33 	brick->SetSize(3);
34 	brick->MoveVertical(80, 144);
35 
36 	var brick = CreateObjectAbove(MovingBrick, 592, 270);
37 	brick->SetSize(2);
38 	brick->MoveVertical(264, 344);
39 	var brick = CreateObjectAbove(MovingBrick, 632, 285);
40 	brick->SetSize(2);
41 	brick->MoveVertical(272, 352);
42 	var brick = CreateObjectAbove(MovingBrick, 672, 300);
43 	brick->SetSize(2);
44 	brick->MoveVertical(280, 360);
45 
46 	var brick = CreateObjectAbove(MovingBrick, 270, 430);
47 	brick->SetSize(2);
48 	brick->MoveVertical(416, 488);
49 	var brick = CreateObjectAbove(MovingBrick, 310, 440);
50 	brick->SetSize(2);
51 	brick->MoveVertical(424, 496);
52 	var brick = CreateObjectAbove(MovingBrick, 350, 450);
53 	brick->SetSize(2);
54 	brick->MoveVertical(432, 504);
55 
56 	var brick = CreateObjectAbove(MovingBrick, 932, 240);
57 	brick->SetSize(4);
58 	brick->MoveVertical(232, 536);
59 
60 	var brick = CreateObjectAbove(MovingBrick, 368, 200);
61 	brick->SetSize(3);
62 	brick->MoveVertical(152, 288);
63 
64 	var brick = CreateObjectAbove(MovingBrick, 184, 320);
65 	brick->SetSize(2);
66 	brick->MoveVertical(240, 368);
67 
68 	var brick = CreateObjectAbove(MovingBrick, 498, 560);
69 	brick->SetSize(2);
70 	brick->MoveVertical(480, 680);
71 	DrawMaterialQuad("Tunnel-Brickback", 478, 478, 497, 478, 497, 552, 478, 552);
72 	DrawMaterialQuad("Tunnel-Brickback", 478, 670, 497, 670, 497, 680, 478, 680);
73 
74 	var brick = CreateObjectAbove(MovingBrick, 170, 600);
75 	brick->SetSize(2);
76 	brick->MoveVertical(528, 680);
77 	DrawMaterialQuad("Tunnel-Brickback", 150, 524, 169, 524, 169, 576, 150, 576);
78 	DrawMaterialQuad("Tunnel-Brickback", 150, 670, 169, 670, 169, 680, 150, 680);
79 
80 	// Horizontally moving bricks.
81 	var brick = CreateObjectAbove(MovingBrick, 600, 496);
82 	brick->SetSize(4);
83 	brick->MoveHorizontal(552, 736);
84 
85 	var brick = CreateObjectAbove(MovingBrick, 656, 688);
86 	brick->SetSize(3);
87 	brick->MoveHorizontal(504, 668);
88 	var brick = CreateObjectAbove(MovingBrick, 688, 664);
89 	brick->SetSize(3);
90 	brick->MoveHorizontal(668, 832);
91 
92 	var brick = CreateObjectAbove(MovingBrick, 320, 688);
93 	brick->SetSize(3);
94 	brick->MoveHorizontal(192, 456);
95 
96 	// Chests with weapons.
97 	var chest;
98 	chest = CreateObjectAbove(Chest, 764, 128, NO_OWNER);
99 	chest->MakeInvincible();
100 	AddEffect("FillChest", chest, 100, 72);
101 	chest = CreateObjectAbove(Chest, 732, 336, NO_OWNER);
102 	chest->MakeInvincible();
103 	AddEffect("FillChest", chest, 100, 72);
104 	chest = CreateObjectAbove(Chest, 116, 400, NO_OWNER);
105 	chest->MakeInvincible();
106 	AddEffect("FillChest", chest, 100, 72);
107 	chest = CreateObjectAbove(Chest, 272, 152, NO_OWNER);
108 	chest->MakeInvincible();
109 	AddEffect("FillChest", chest, 100, 72);
110 	chest = CreateObjectAbove(Chest, 424, 480, NO_OWNER);
111 	chest->MakeInvincible();
112 	AddEffect("FillChest", chest, 100, 72);
113 	chest = CreateObjectAbove(Chest, 872, 520, NO_OWNER);
114 	chest->MakeInvincible();
115 	AddEffect("FillChest", chest, 100, 72);
116 	chest = CreateObjectAbove(Chest, 72, 208, NO_OWNER);
117 	chest->MakeInvincible();
118 	AddEffect("FillChest", chest, 100, 72);
119 
120 	// Some columns as decoration.
121 	CreateObjectAbove(Column, 736, 480, NO_OWNER);
122 	CreateObjectAbove(Column, 860, 392, NO_OWNER);
123 	CreateObjectAbove(Column, 420, 280, NO_OWNER);
124 	CreateObjectAbove(Column, 200, 144, NO_OWNER);
125 	CreateObjectAbove(Column, 556, 480, NO_OWNER);
126 	CreateObjectAbove(Column, 452, 672, NO_OWNER);
127 	CreateObjectAbove(Column, 192, 672, NO_OWNER);
128 
129 	// Grass as decoration.
130 	var x=[813, 820, 856, 833, 827, 838, 844, 869, 872, 882, 853, 861, 506, 466, 527, 524, 514, 510, 517, 502, 436, 437, 441, 448, 457, 463, 177, 139, 121, 126, 199, 190, 181, 213, 206, 133, 147, 196, 104, 175, 116, 108, 126, 135, 155, 201, 195, 188, 43, 52, 58, 406, 410, 551, 554, 550, 547, 538, 723, 838, 802, 808, 836, 690, 781, 787, 745, 869, 861, 825, 829, 849, 720, 910, 908, 901, 795, 803, 819, 875, 855, 830, 813, 869, 894, 886, 844, 796, 789, 787, 729, 764, 779, 770, 755, 749, 741, 574, 533, 574, 566, 559, 546, 426, 429, 414, 407, 397, 390, 387, 380, 376, 218, 210, 97, 104, 118, 123, 131, 139, 144, 154, 212, 194, 209, 205, 198, 188, 181, 174, 216, 221, 291, 313, 298, 305, 307, 296, 301, 284, 269, 103, 84, 132, 124, 148, 146, 140, 118, 107, 91, 332, 330, 328, 314, 298, 281, 184, 236, 227, 213, 268, 292, 307, 315, 322, 365, 362, 370, 378, 578, 582, 589, 731, 734, 740, 759, 773, 787, 833, 826, 806, 818, 832, 842, 864, 851, 887, 892, 906, 877, 732, 729, 709, 704, 757, 769, 717, 892, 899, 922, 907, 857, 842, 832];
131 	var y=[648, 646, 645, 634, 636, 629, 623, 628, 633, 640, 620, 621, 668, 669, 673, 666, 655, 648, 660, 643, 675, 664, 658, 653, 646, 646, 669, 655, 673, 662, 661, 653, 652, 672, 670, 660, 645, 500, 518, 493, 508, 516, 499, 500, 484, 519, 517, 493, 207, 205, 204, 283, 277, 282, 289, 275, 268, 259, 127, 137, 258, 254, 223, 336, 343, 331, 333, 389, 374, 394, 387, 372, 479, 522, 513, 508, 484, 486, 484, 498, 474, 483, 477, 493, 500, 500, 469, 472, 469, 464, 476, 468, 460, 462, 467, 468, 469, 482, 453, 475, 470, 468, 460, 460, 451, 461, 460, 460, 462, 469, 477, 483, 412, 405, 403, 398, 382, 377, 373, 374, 373, 373, 398, 376, 389, 384, 381, 373, 372, 372, 235, 229, 232, 272, 271, 270, 255, 243, 250, 226, 220, 191, 192, 207, 204, 223, 216, 213, 193, 188, 187, 126, 119, 147, 140, 121, 131, 141, 131, 132, 125, 131, 124, 116, 116, 116, 88, 93, 84, 75, 77, 84, 92, 116, 112, 108, 107, 108, 108, 131, 111, 108, 107, 204, 196, 197, 188, 193, 196, 212, 179, 318, 316, 310, 316, 317, 323, 307, 372, 369, 367, 363, 372, 372, 379];
132 	var r=[-50, 0, 0, -50, 0, -50, -30, 90, 50, 60, 0, 0, 0, 0, 60, 60, 60, 45, 0, 0, -45, -45, -45, 0, 0, 0, 0, -45, -45, -45, 0, 0, 0, 45, 0, 0, 0, 85, -35, 0, 0, 0, 0, 0, 0, 35, 0, 0, -35, 0, 0, -85, 0, 45, 95, 95, 95, 0, -45, 45, -45, 0, -45, -45, 45, 95, 0, 0, 0, -35, -95, 0, -35, 75, 75, 0, 45, 0, 90, 90, 60, 0, 0, 0, 0, 0, 0, 60, 0, 60, 0, 0, 0, 0, 0, 0, 0, 45, 90, 90, 0, 0, 0, 0, -90, 0, 0, 0, -40, 0, -40, -40, 40, 30, -30, 0, -30, -30, 0, 0, 0, 0, 90, 40, 40, 40, 0, 0, 0, 0, -40, -20, 50, 50, 50, 0, 50, 50, 50, 0, 0, -40, -40, 50, 0, 90, 50, 0, 50, 0, 0, 90, 55, 55, 0, -35, -35, 0, 0, 0, 0, 0, 0, 0, 0, 0, -55, 0, 0, 0, 55, 0, 0, 0, -35, 0, 0, 0, 0, 35, 35, 0, 0, -35, 0, 0, 0, 35, 0, 0, 0, 0, 0, -35, -45, 0, 0, 0, 0, -45, 45, 0, 10, 0, -50];
133 	for (var i = 0; i < GetLength(x); i++)
134 	{
135 		var grass = CreateObjectAbove(Grass, x[i], y[i] + 5, NO_OWNER);
136 		grass->SetR(r[i]);
137 	}
138 
139 	// Blue chest with wind bag
140 	var chest_blue = CreateObjectAbove(Chest, 850, 648, NO_OWNER);
141 	chest_blue->SetClrModulation(RGB(100,180,255));
142 	AddEffect("FillBlueChest", chest_blue, 100, 72);
143 
144 	// Red chest with club.
145 	var chest_red = CreateObjectAbove(Chest, 124, 520, NO_OWNER);
146 	chest_red->SetClrModulation(RGB(255, 100, 100));
147 	AddEffect("FillRedChest", chest_red, 100, 72);
148 
149 	// Wind channel.
150 	AddEffect("WindChannel", nil, 100, 1);
151 
152 	Overcast_air_particles =
153 	{
154 		Prototype = Particles_Air(),
155 		Size = PV_KeyFrames(0, 0, 0, 100, PV_Random(5, 10), 1000, 0),
156 		OnCollision = PC_Die()
157 	};
158 	return;
159 }
160 
InitializePlayer(int plr)161 protected func InitializePlayer(int plr)
162 {
163 	// This scenario does not have shadows.
164 	SetFoW(false, plr);
165 	return;
166 }
167 
168 /*-- Wind channel --*/
169 
FxWindChannelStart(object target,proplist effect,int temporary)170 global func FxWindChannelStart(object target, proplist effect, int temporary)
171 {
172 	if (temporary == 0)
173 		effect.Divider = 1;
174 	return 1;
175 }
176 
FxWindChannelTimer(object target,proplist effect)177 global func FxWindChannelTimer(object target, proplist effect)
178 {
179 	// Channel divided into three parts.
180 
181 	// First shaft with upward wind.
182 	for (var obj in FindObjects(Find_InRect(464, 288, 40, 152)))
183 	{
184 		var speed = obj->GetYDir(100);
185 		if (speed < -360)
186 			continue;
187 		obj->SetYDir(speed - 36, 100);
188 	}
189 	CreateParticle("Air", 464+Random(40), 344+Random(112), RandomX(-1,1), -30, PV_Random(10, 40), Overcast_air_particles);
190 
191 	// Divider with random wind.
192 	if (!Random(100))
193 		effect.Divider = Random(3);
194 	for (var obj in FindObjects(Find_InRect(464, 240, 40, 48)))
195 	{
196 		if (effect.Divider == 1)
197 		{
198 			var speed = obj->GetYDir(100);
199 			if (speed < -360)
200 				continue;
201 			obj->SetYDir(speed - 36, 100);
202 		}
203 		if (effect.Divider == 0)
204 		{
205 			var speed = obj->GetXDir(100);
206 			if (speed > -360)
207 				obj->SetXDir(speed - 20, 100);
208 		}
209 		if (effect.Divider == 2)
210 		{
211 			var speed = obj->GetXDir(100);
212 			if (speed < 360)
213 				obj->SetXDir(speed + 20, 100);
214 		}
215 	}
216 	if (effect.Divider == 1)
217 		CreateParticle("Air", 464+Random(40), 280+Random(10), RandomX(-1,1), -30, PV_Random(10, 40), Overcast_air_particles);
218 	if (effect.Divider == 0)
219 		CreateParticle("Air", 464+Random(40), 280+Random(10), RandomX(-20,-10), -20, PV_Random(10, 40), Overcast_air_particles);
220 	if (effect.Divider == 2)
221 		CreateParticle("Air", 464+Random(40), 280+Random(10), RandomX(10,20), -20, PV_Random(10, 40), Overcast_air_particles);
222 
223 	// Second shaft with upward wind.
224 	for (var obj in FindObjects(Find_InRect(464, 96, 40, 144)))
225 	{
226 		// Divert at top.
227 		if (obj->GetY() < 104)
228 		{
229 			if (obj->GetX() < 484)
230 			{
231 				var speed = obj->GetXDir(100);
232 				if (speed > -200)
233 				obj->SetXDir(speed - 16, 100);
234 			}
235 			else
236 			{
237 				var speed = obj->GetXDir(100);
238 				if (speed < 200)
239 				obj->SetXDir(speed + 16, 100);
240 			}
241 			//continue;
242 		}
243 		var speed = obj->GetYDir(100);
244 		if (speed < -360)
245 			continue;
246 		obj->SetYDir(speed - 36, 100);
247 	}
248 	CreateParticle("Air", 464+Random(40), 160+Random(96), RandomX(-1,1), -30, PV_Random(10, 40), Overcast_air_particles);
249 
250 	return 1;
251 }
252 
253 /*-- Chest contents --*/
254 
FxFillChestStart(object target,proplist effect,int temporary)255 global func FxFillChestStart(object target, proplist effect, int temporary)
256 {
257 	if (temporary)
258 		return 1;
259 	var w_list = [Shield, Javelin, FireballScroll, Bow, Blunderbuss, WindScroll, TeleportScroll];
260 	for (var i = 0; i < 4; i++)
261 		target->CreateChestContents(w_list[Random(GetLength(w_list))]);
262 	return 1;
263 }
264 
FxFillChestTimer(object target,proplist effect)265 global func FxFillChestTimer(object target, proplist effect)
266 {
267 	if (Random(5))
268 		return 1;
269 	var w_list = [Balloon, Boompack, IronBomb, Shield, Javelin, Bow, Blunderbuss, Boompack, IronBomb, Shield, Javelin, Bow, Blunderbuss, TeleportScroll, WindScroll, FireballScroll];
270 
271 	if (target->ContentsCount() < 6)
272 		target->CreateChestContents(w_list[Random(GetLength(w_list))]);
273 	return 1;
274 }
275 
FxFillBlueChestStart(object target,proplist effect,int temporary)276 global func FxFillBlueChestStart(object target, proplist effect, int temporary)
277 {
278 	if (temporary)
279 		return 1;
280 	target->CreateContents(WindBag);
281 	var w_list = [Firestone, Boompack, Balloon, FireballScroll, WindScroll];
282 	for (var i = 0; i < 4; i++)
283 		target->CreateContents(w_list[Random(GetLength(w_list))]);
284 	return 1;
285 }
286 
FxFillBlueChestTimer(object target,proplist effect)287 global func FxFillBlueChestTimer(object target, proplist effect)
288 {
289 	if (Random(5))
290 		return 1;
291 	var w_list = [Firestone, Boompack, FireballScroll, WindScroll];
292 	if (target->ContentsCount() < 6)
293 		target->CreateContents(w_list[Random(GetLength(w_list))]);
294 
295 	if (!FindObject(Find_ID(WindBag)))
296 		target->CreateContents(WindBag);
297 	return 1;
298 }
299 
FxFillRedChestStart(object target,proplist effect,int temporary)300 global func FxFillRedChestStart(object target, proplist effect, int temporary)
301 {
302 	if (temporary)
303 		return 1;
304 	target->CreateContents(Club);
305 	var w_list = [Firestone, Boompack, FireballScroll, WindScroll];
306 	for (var i = 0; i < 4; i++)
307 		target->CreateContents(w_list[Random(GetLength(w_list))]);
308 	return 1;
309 }
310 
FxFillRedChestTimer(object target,proplist effect)311 global func FxFillRedChestTimer(object target, proplist effect)
312 {
313 	if (Random(5))
314 		return 1;
315 	var w_list = [Firestone, Boompack, FireballScroll, WindScroll];
316 	if (target->ContentsCount() < 6)
317 		target->CreateContents(w_list[Random(GetLength(w_list))]);
318 
319 	if (!FindObject(Find_ID(Club)))
320 		target->CreateContents(Club);
321 
322 	return 1;
323 }
324 
CreateChestContents(id obj_id)325 global func CreateChestContents(id obj_id)
326 {
327 	if (!this)
328 		return;
329 	var obj = CreateObjectAbove(obj_id);
330 	if (obj_id == Bow)
331 		obj->CreateContents(Arrow);
332 	if (obj_id == Blunderbuss)
333 		obj->CreateContents(LeadBullet);
334 	obj->Enter(this);
335 	return;
336 }
337 
338 /*-- Player control --*/
339 
340 // GameCall from RelaunchContainer.
OnClonkLeftRelaunch(object clonk)341 func OnClonkLeftRelaunch(object clonk)
342 {
343 	CreateParticle("Air", clonk->GetX(),clonk->GetY(), PV_Random(-20, 20), PV_Random(-20, 20), PV_Random(5, 10), Overcast_air_particles, 25);
344 	return;
345 }
346 
RelaunchPosition()347 public func RelaunchPosition()
348 {
349 	return [[432,270],[136,382],[200,134],[864,190],[856,382],[840,518],[408,86],[536,470]];
350 
351 }
352 
GetRandomSpawn()353 global func GetRandomSpawn()
354 {
355 	return RandomElement(Scenario->RelaunchPosition());
356 }
357 
KillsToRelaunch()358 func KillsToRelaunch() { return 0; }
RelaunchWeaponList()359 func RelaunchWeaponList() { return [Bow, Javelin, Blunderbuss, FireballScroll, WindScroll, TeleportScroll]; }
360