1 /*--
2 Powder Keg
3 A barrel filled with black powder.
4
5 @author Ringwaul
6 */
7
8 #include Library_CarryHeavy
9
10 local count;
11 local TimeToExplode = 90; // Number of frames to pass until keg explodes
12 local MaxContentsCount = 12;
13
GetCarryTransform(clonk)14 public func GetCarryTransform(clonk)
15 {
16 if(GetCarrySpecial(clonk))
17 return Trans_Translate(1000, -6500, 0);
18
19 return Trans_Mul(Trans_Translate(1500, 0, -1500),Trans_Rotate(180,1,0,0));
20 }
GetCarryPhase()21 public func GetCarryPhase() { return 900; }
22
Construction()23 protected func Construction()
24 {
25 SetPowderCount(MaxContentsCount);
26 }
27
GetPowderCount()28 public func GetPowderCount()
29 {
30 return count;
31 }
32
SetPowderCount(newcount)33 public func SetPowderCount(newcount)
34 {
35 count = newcount;
36 this.Description = Format("%s||$RemainingPowder$: %d", this.Prototype.Description, this.count);
37 if (count == 0)
38 ScheduleCall(this, "CheckEmpty", 1, 0);
39 return;
40 }
41
DoPowderCount(int change)42 public func DoPowderCount(int change)
43 {
44 if (count == nil)
45 return;
46 return SetPowderCount(GetPowderCount() + change);
47 }
48
CheckEmpty()49 private func CheckEmpty()
50 {
51 if (count == 0)
52 {
53 ChangeDef(Barrel);
54 this.Description = this.Prototype.Description;
55 this->~Initialize();
56 }
57 }
58
59 // Do not put differently filled kegs on top of each other.
CanBeStackedWith(object other)60 public func CanBeStackedWith(object other)
61 {
62 if (this.count != other.count) return false;
63 return inherited(other, ...);
64 }
65
66 // Display the powder as a bar over the keg icon.
GetInventoryIconOverlay()67 public func GetInventoryIconOverlay()
68 {
69 if (this.count >= MaxContentsCount) return nil;
70
71 var percentage = 100 - 100 * this.count / this.MaxContentsCount;
72
73 // Overlay a usage bar.
74 var overlay =
75 {
76 Bottom = "0.75em", Margin = ["0.1em", "0.25em"],
77 BackgroundColor = RGB(0, 0, 0),
78 margin =
79 {
80 Margin = "0.05em",
81 bar =
82 {
83 BackgroundColor = RGB(150, 50, 50),
84 Right = Format("%d%%", percentage),
85 }
86 }
87 };
88
89 return overlay;
90 }
91
Incineration(int caused_by)92 public func Incineration(int caused_by)
93 {
94 SetController(caused_by);
95 AddEffect("Fuse", this, 1, 1, this);
96 }
97
FxFuseTimer(object target,effect,int timer)98 public func FxFuseTimer(object target, effect, int timer)
99 {
100 // Particle effect
101 var lifetime = PV_Random(10, 40);
102 var amount = 6;
103 if (Contained() && Contained()->~IsClonk())
104 {
105 var prec = 10;
106 // Position, is always the same regardless of rotation
107 var x = 2, y = -6;
108 // Needs a loop for now, because CreateParticleAtBone seems to not use the PV_Random values in the dir array
109 for (var i = 0; i < amount; ++i)
110 {
111 // Positions for array: [-y, 0, -x]
112 Contained()->CreateParticleAtBone("Fire", "pos_tool1", [2 - y, 0, -1 - x], [prec * RandomX(-10, 20), 0, prec * RandomX(-10, 10)], lifetime, Particles_Glimmer(), 1);
113 }
114 }
115 else
116 {
117 var x, y;
118
119 if (Contained())
120 {
121 // Display at the center if contained, because the fuse vertex might not be visible
122 x = 0; y = 0;
123 }
124 else
125 {
126 // Display at a vertex, because this is easier than calculating the correct rotated position
127 var fuse_vertex = 1;
128 x = GetVertex(fuse_vertex, 0);
129 y = GetVertex(fuse_vertex, 1);
130 }
131 CreateParticle("Fire", x, y, PV_Random(-10, 10), PV_Random(-20, 10), lifetime, Particles_Glimmer(), amount);
132 }
133 // Explosion after timeout
134 if (timer > TimeToExplode)
135 {
136 Explode(GetExplosionStrength());
137 }
138 }
139
140 // Powderkeg explosion strength ranges from 17-32.
GetExplosionStrength()141 public func GetExplosionStrength() { return Sqrt(64 * (4 + count)); }
142
IsProjectileTarget()143 public func IsProjectileTarget()
144 {
145 return true;
146 }
147
Damage(int change,int cause,int by_player)148 public func Damage(int change, int cause, int by_player)
149 {
150 Incinerate(100, by_player);
151 }
152
OnProjectileHit(object projectile)153 public func OnProjectileHit(object projectile)
154 {
155 Incinerate(100, projectile->GetController());
156 }
157
Hit()158 func Hit()
159 {
160 Sound("Hits::Materials::Wood::DullWoodHit?");
161 }
162
SaveScenarioObject(props)163 public func SaveScenarioObject(props)
164 {
165 if (!inherited(props, ...)) return false;
166 var v = GetPowderCount();
167 if (v != MaxContentsCount) props->AddCall("Powder", this, "SetPowderCount", v);
168 return true;
169 }
170
IsChemicalProduct()171 func IsChemicalProduct() { return true; }
AlchemyProcessTime()172 func AlchemyProcessTime() { return 100; }
IsExplosive()173 public func IsExplosive() { return true; }
174
175
176 /*-- Properties --*/
177
178 local Collectible = true;
179 local Name = "$Name$";
180 local Description = "$Description$";
181 local BlastIncinerate = 1;
182 local NoBurnDecay = true;
183 local ContactIncinerate = 2;
184 local Components = {Barrel = 1, Coal = 1};
185