1 /*
2 Arrow
3 The arrow is the standard ammo for the bow and base object for all other
4 types of arrows. This object is stackable (up to 15) as it is required
5 from the bow.
6 The arrow employs the HitCheck effect (in System.ocg/HitChecks.c) originally
7 from Hazard to search for targets during flight.
8
9 @author Newton
10 */
11
12 #include Library_Stackable
13 #include Library_Flammable
14
15
Construction()16 protected func Construction()
17 {
18 SetR(90);
19 return _inherited(...);
20 }
21
Launch(int angle,int str,object shooter,object weapon)22 public func Launch(int angle, int str, object shooter, object weapon)
23 {
24 SetShape(-2, -2, 4, 11);
25 SetVertex(0, VTX_Y, 3, 1);
26 SetVertex(1, VTX_Y, 4, 1);
27 SetVertex(2, VTX_Y, -2, 1);
28 SetPosition(GetX(), GetY() - 2);
29 var xdir = Sin(angle,str);
30 var ydir = Cos(angle,-str);
31 SetXDir(xdir);
32 SetYDir(ydir);
33 SetR(angle);
34 Sound("Objects::Arrow::Shoot?");
35 // Shooter controls the arrow for correct kill tracing.
36 SetController(shooter->GetController());
37
38 AddEffect("HitCheck", this, 1,1, nil, nil, shooter);
39 AddEffect("InFlight", this, 1,1, this);
40 return;
41 }
42
Stick()43 private func Stick()
44 {
45 if (GetEffect("InFlight",this))
46 {
47 RemoveEffect("HitCheck",this);
48 RemoveEffect("InFlight",this);
49
50 SetXDir(0);
51 SetYDir(0);
52 SetRDir(0);
53
54 var x = Sin(GetR(), 9);
55 var y = -Cos(GetR(), 9);
56 var mat = GetMaterial(x, y);
57 // Stick in any material.
58 if (mat != -1)
59 SetVertex(2, VTX_Y, -10, 1);
60 }
61 return;
62 }
63
HitObject(object obj)64 public func HitObject(object obj)
65 {
66 // Determine damage to obj from speed and arrow strength.
67 var relx = GetXDir() - obj->GetXDir();
68 var rely = GetYDir() - obj->GetYDir();
69 var speed = Sqrt(relx * relx + rely * rely);
70 var dmg = ArrowStrength() * speed * 1000 / 100;
71
72 if (WeaponCanHit(obj))
73 {
74 if (obj->GetAlive())
75 Sound("Hits::ProjectileHitLiving?");
76 else
77 Sound("Objects::Arrow::HitGround");
78
79 obj->~OnProjectileHit(this);
80 WeaponDamage(obj, dmg, FX_Call_EngObjHit, true);
81 WeaponTumble(obj, this->TumbleStrength());
82 }
83
84 // Stick does something unwanted to controller.
85 if (this)
86 Stick();
87 return;
88 }
89
Hit()90 public func Hit()
91 {
92 if (GetEffect("InFlight",this))
93 Sound("Objects::Arrow::HitGround");
94 Stick();
95 }
96
97 // The flight effect rotates the arrow according to its speed.
FxInFlightStart(object target,proplist effect,int temp)98 public func FxInFlightStart(object target, proplist effect, int temp)
99 {
100 if (temp)
101 return 1;
102 effect.x = target->GetX();
103 effect.y = target->GetY();
104 return 1;
105 }
106
FxInFlightTimer(object target,proplist effect,int time)107 public func FxInFlightTimer(object target, proplist effect, int time)
108 {
109 var oldx = effect.x;
110 var oldy = effect.y;
111 var newx = GetX();
112 var newy = GetY();
113
114 // And additionally, we need one check: If the arrow has no speed
115 // anymore but is still in flight, we'll remove the hit check.
116 if (oldx == newx && oldy == newy)
117 {
118 // But we give the arrow 10 frames to speed up again.
119 effect.var2++;
120 if (effect.var2 >= 10)
121 return Hit();
122 }
123 else
124 effect.var2 = 0;
125
126 // Rotate arrow according to speed.
127 var anglediff = Normalize(Angle(oldx, oldy, newx, newy) - GetR(), -180);
128 SetRDir(anglediff / 2);
129 effect.x = newx;
130 effect.y = newy;
131 return 1;
132 }
133
UpdatePicture()134 protected func UpdatePicture()
135 {
136 var arrow_count = GetStackCount();
137 if (arrow_count >= 9)
138 SetGraphics(nil);
139 else
140 SetGraphics(Format("%d", arrow_count));
141 _inherited(...);
142 }
143
Entrance()144 protected func Entrance()
145 {
146 // Reset the sticky-vertex.
147 SetVertex(2, VTX_Y, 0, 1);
148 }
149
RejectEntrance()150 protected func RejectEntrance()
151 {
152 // Can't be collected while flying.
153 if (GetEffect("InFlight",this))
154 return true;
155 return _inherited(...);
156 }
157
IsArrow()158 public func IsArrow() { return true; }
MaxStackCount()159 public func MaxStackCount() { return 15; }
ArrowStrength()160 public func ArrowStrength() { return 10; }
TumbleStrength()161 public func TumbleStrength() { return 100; }
IsArmoryProduct()162 public func IsArmoryProduct() { return true; }
163
164
165 /*-- Properties --*/
166
167 local Name = "$Name$";
168 local Description = "$Description$";
169 local Collectible = 1;
170 local Components = {Wood = 3};
171 local BlastIncinerate = 5;
172 local ContactIncinerate = 1;
173