1 /*--
2 	Thunderous Skies
3 	Author: Mimmo_O
4 
5 	King of the hill high in the skies.
6 --*/
7 
8 
9 static ThunderousSkies_air_particles, ThunderousSkies_air_particles_red;
10 
Initialize()11 protected func Initialize()
12 {
13 	// Goal.
14 	CreateObject(Rule_ObjectFade)->DoFadeTime(8 * 36);
15 	var goal = CreateObject(Goal_KingOfTheHill, 450, 380, NO_OWNER);
16 	goal->SetRadius(90);
17 	goal->SetPointLimit(5);
18 	AddEffect("BlessTheKing",goal,100,1,nil);
19 	CreateObject(Rule_KillLogs);
20 	CreateObject(Rule_Gravestones);
21 	GetRelaunchRule()
22 		->SetLastWeaponUse(false)
23 		->SetDefaultRelaunchCount(nil);
24 
25 	//Enviroment.
26 	//SetSkyAdjust(RGBa(250,250,255,128),RGB(200,200,220));
27 	SetSkyParallax(1, 20,20, 0,0, nil, nil);
28 	Sound("Environment::BirdsLoop",true,100,nil,+1);
29 
30 	CreateObjectAbove(Column,650,379);
31 	CreateObjectAbove(Column,350,409);
32 	CreateObjectAbove(Column,160,229);
33 	CreateObjectAbove(Column,448,269);
34 	CreateObjectAbove(Column,810,179);
35 
36 	// Chests with weapons.
37 	CreateObjectAbove(Chest, 175, 200, NO_OWNER)->MakeInvincible();
38 	CreateObjectAbove(Chest, 800, 150, NO_OWNER)->MakeInvincible();
39 	CreateObjectAbove(Chest, 430, 240, NO_OWNER)->MakeInvincible();
40 	CreateObjectAbove(Chest, 610, 340, NO_OWNER)->MakeInvincible();
41 	CreateObjectAbove(Chest, 355, 390, NO_OWNER)->MakeInvincible();
42 
43 	AddEffect("IntFillChests", nil, 100, 2 * 36, nil);
44 	AddEffect("ChanneledWind", nil, 1, 1, nil);
45 	AddEffect("Balloons", nil, 100, 100, nil);
46 
47 	// Moving bricks.
48 	var brick;
49 	brick = CreateObjectAbove(MovingBrick,370,424);
50 	brick->MoveHorizontal(344, 544);
51 	brick = CreateObjectAbove(MovingBrick,550,250);
52 	brick->MoveVertical(240, 296);
53 
54 	// Smooth brick edges.
55 	DrawMaterialTriangle("Brick-brick", 380, 412, 0);
56 
57 	PlaceGras();
58 
59 	ThunderousSkies_air_particles =
60 	{
61 		Prototype = Particles_Air(),
62 		Size = PV_KeyFrames(0, 0, 0, 100, PV_Random(2, 5), 1000, 0),
63 		Stretch = PV_Speed(2000, 0),
64 		OnCollision = PC_Stop(),
65 		ForceY = -20,
66 		Attach = ATTACH_Back | ATTACH_MoveRelative
67 	};
68 
69 	ThunderousSkies_air_particles_red =
70 	{
71 		Prototype = ThunderousSkies_air_particles,
72 		R = 255,
73 		G = PV_KeyFrames(0, 0, 255, 250, 255, 500, 0),
74 		B = PV_KeyFrames(0, 0, 255, 250, 255, 500, 0)
75 	};
76 	return;
77 }
FxLifestealDamage(object target,effect,int damage,int cause,int from)78 global func FxLifestealDamage(object target, effect, int damage, int cause, int from)
79 {
80 	var goal = FindObject(Find_ID(KingOfTheHill_Location));
81 	if (!goal) return damage;
82 	var king = goal->GetKing();
83 	if (!king) return damage;
84 	if (from == -1) return damage;
85 	if (damage > 0) return damage;
86 	if (target->GetOwner() == from) return damage;
87 	if (king->GetOwner() == from)
88 		AddEffect("Lifedrain",king,100,1,nil,nil,damage/3);
89 	return damage;
90 }
FxLifedrainStart(object target,effect,int temporary,damage)91 global func FxLifedrainStart(object target, effect, int temporary,damage)
92 {
93 	if(temporary) return 1;
94 	effect.drain=damage/10;
95 }
FxLifedrainAdd(object target,effect,string new_name,int new_timer,damage)96 global func FxLifedrainAdd(object target, effect, string new_name, int new_timer, damage)
97 {
98 	effect.drain+=damage/10;
99 }
FxLifedrainTimer(object target,effect,int timer)100 global func FxLifedrainTimer(object target, effect, int timer)
101 {
102 	if(effect.drain>0) return -1;
103 	target->DoEnergy(+100,1,0,-1);
104 	effect.drain+=10;
105 }
FxBlessTheKingTimer(object target,effect,int timer)106 global func FxBlessTheKingTimer(object target, effect, int timer)
107 {
108 	if(!FindObject(Find_ID(KingOfTheHill_Location))) return 1;
109 	if(FindObject(Find_ID(KingOfTheHill_Location))->GetKing() == nil) return 1;
110 
111 	var king=FindObject(Find_ID(KingOfTheHill_Location))->GetKing();
112 	var particles = ThunderousSkies_air_particles;
113 	var duration = 10;
114 	if (GetEffect("Lifedrain", king))
115 	{
116 		particles = ThunderousSkies_air_particles_red;
117 		duration *= 2;
118 	}
119 	king->CreateParticle("Air", 0, 8, PV_Random(-10, 10),PV_Random(0, 10), PV_Random(duration, 2 * duration), particles, 4);
120 	return 1;
121 }
122 
ApplyChanneledWindEffects(x,y,w,h,bottom)123 public func ApplyChanneledWindEffects(x, y, w, h, bottom)
124 {
125 	for(var obj in FindObjects(Find_InRect(x, y, w, h)))
126 	{
127 		obj->SetYDir(Max(obj->GetYDir()-5,-50));
128 		var x_dir = -1;
129 		if (obj->GetXDir() > 0)
130 			x_dir = +1;
131 		else if (obj->GetXDir() == 0)
132 			x_dir = RandomX(-2, 2);
133 		obj->SetXDir(obj->GetXDir() + x_dir);
134 	}
135 	CreateParticle("Air", x+Random(w),bottom,RandomX(-1,1),-30, PV_Random(10, 30), ThunderousSkies_air_particles);
136 }
137 
FxChanneledWindTimer()138 global func FxChanneledWindTimer()
139 {
140 	Scenario->ApplyChanneledWindEffects(230, 300, 40, 90, 398);
141 	Scenario->ApplyChanneledWindEffects(700, 250, 60, 100, 348);
142 }
143 
FxBalloonsTimer()144 global func FxBalloonsTimer()
145 {
146 	if(ObjectCount(Find_ID(TargetBalloon)) > 2 )
147 	{
148 		return 1;
149 	}
150 	if(ObjectCount(Find_ID(TargetBalloon)) )
151 	{
152 		if(Random(6)) return 1;
153 	}
154 
155 	if(Random(2)) return 1;
156 
157 	var x = Random(300)+50;
158 	if(Random(2)) x = LandscapeWidth() - x;
159 	var y = Random(50) + 100;
160 	var target;
161 
162 	var r = Random(3);
163 	if (r == 0) { target = CreateObjectAbove(Boompack, x, y, NO_OWNER); target->SetR(180); }
164 	if (r == 1) { target = CreateObjectAbove(DynamiteBox, x, y, NO_OWNER); target->SetR(180); }
165 	if (r == 2) { target = CreateObjectAbove(Arrow, x, y, NO_OWNER); target->SetObjDrawTransform(1000,0,0,0,1000,-7500); }
166 
167 
168 	var balloon = CreateObjectAbove(TargetBalloon, x, y-30, NO_OWNER);
169 	balloon->SetProperty("load",target);
170 	target->SetAction("Attach", balloon);
171 	CreateParticle("Flash", x, y, 0, 0, 8, Particles_Flash());
172 	AddEffect("HorizontalMoving", balloon, 1, 1, balloon);
173 	balloon->SetXDir(((Random(2)*2)-1) * (Random(4)+3));
174 }
175 
PlaceGras()176 global func PlaceGras()
177 {
178 	var x=[747, 475, 474, 359, 244, 216, 324, 705, 754, 758, 828, 828, 235, 266, 266, 269, 177, 194, 204, 223, 348, 273, 284, 365, 369, 375, 379, 285, 281, 274, 233, 390, 229, 401, 388, 414, 476, 468, 463, 457, 422, 482, 493, 615, 609, 625, 631, 700, 704, 687, 761, 763, 771, 777, 619, 615, 621, 696, 789, 766, 356, 228, 188];
179 	var y=[280, 376, 384, 299, 279, 224, 290, 244, 226, 215, 175, 169, 328, 319, 310, 327, 205, 212, 213, 227, 292, 306, 294, 409, 407, 413, 414, 399, 396, 390, 388, 264, 392, 249, 256, 247, 252, 249, 241, 246, 246, 245, 363, 347, 376, 349, 348, 348, 335, 350, 337, 346, 349, 351, 249, 255, 254, 237, 178, 212, 291, 305, 227];
180 	var r=[-91, -93, -93, 89, 93, 93, 88, 89, -92, -92, 88, 93, 93, -88, -87, -93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 43, 46, 44, 48, -43, -48, -48, -45, -43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -48, -44, -45, 48, 46, 48, 45, 0, 0, 0, 0, 0, 0, 0, 44, 0];
181 	for (var i = 0; i < GetLength(x); i++)
182 	{
183 		var edge=CreateObjectAbove(Grass, x[i], y[i] + 5, NO_OWNER);
184 		edge->SetR(r[i]);
185 		edge->Initialize();
186 	}
187 	return 1;
188 }
189 
190 // Refill/fill chests.
FxIntFillChestsStart(object target,effect,int temporary)191 global func FxIntFillChestsStart(object target, effect, int temporary)
192 {
193 	if(temporary) return 1;
194 	var chests = FindObjects(Find_ID(Chest),Find_InRect(0,0,LandscapeWidth(),610));
195 	var w_list = [Shield, Javelin, FireballScroll, Bow, Blunderbuss, WindScroll, ThunderScroll];
196 
197 	for(var chest in chests)
198 		for(var i=0; i<4; ++i)
199 			chest->CreateChestContents(w_list[Random(GetLength(w_list))]);
200 	return 1;
201 }
202 
FxIntFillChestsTimer()203 global func FxIntFillChestsTimer()
204 {
205 	SetTemperature(100);
206 	var chest = FindObjects(Find_ID(Chest), Sort_Random())[0];
207 	var w_list = [Javelin, Bow, Blunderbuss, Boompack, IronBomb, Shield, WindScroll, FireballScroll, ThunderScroll, Club, Sword];
208 	var maxcount = [1,1,1,1,2,1,1,2,2,1,1];
209 
210 	var contents;
211 	for(var i=0; i<chest->GetLength(w_list); i++)
212 		contents+=chest->ContentsCount(w_list[i]);
213 	if(contents > 5) return 1;
214 
215 	if(!FindObject(Find_ID(Clonk),Find_Distance(20,chest->GetX(),chest->GetY())) && chest->ContentsCount()>2)
216 	{
217 		var r=chest->Random(chest->ContentsCount());
218 		var remove=true;
219 		for(var i=0; i<GetLength(w_list); i++)
220 			if(chest->Contents(r)->GetID() == w_list[i]) remove=false;
221 		if(remove) chest->Contents(r)->RemoveObject();
222 	}
223 
224 	for(var i=0; i<2 ; i++)
225 	{
226 		var r = Random(GetLength(w_list));
227 		if (chest->ContentsCount(w_list[r]) < maxcount[r])
228 		{
229 			chest->CreateChestContents(w_list[r]);
230 			i=3;
231 		}
232 	}
233 	return 1;
234 }
235 
CreateChestContents(id obj_id)236 global func CreateChestContents(id obj_id)
237 {
238 if (!this)
239 		return;
240 	var obj = CreateObjectAbove(obj_id);
241 	if (obj_id == Bow)
242 		obj->CreateContents(Arrow);
243 	if (obj_id == Blunderbuss)
244 		obj->CreateContents(LeadBullet);
245 	obj->Enter(this);
246 	return;
247 }
248 
InitializePlayer(int plr)249 protected func InitializePlayer(int plr)
250 {
251 	// This scenario does not have shadows.
252 	SetFoW(false, plr);
253 }
254 
RelaunchPosition()255 public func RelaunchPosition()
256 {
257 	return [[180,150],[310,300],[600,290],[650,180],[790,110],[440,190]];
258 }
259 
KillsToRelaunch()260 func KillsToRelaunch() { return 0; }
RelaunchWeaponList()261 func RelaunchWeaponList() { return [Bow,  Javelin, Blunderbuss, FireballScroll, WindScroll, ThunderScroll]; }
262