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