1 /**
2 	Bullet trail
3 	Draws a trail to any object. That object should fly straight or so fast
4 	that it looks like it because the trail itself is only drawn straight.
5 	Any projectile can use the trail by calling (after creating it):
6 
7 	Set(object bullet, int width, int length)
8 
9 	while width is the width of the trail, length the length of the trail and
10 	projectile itself. The trail will be removed when the projectile is gone.
11 	The color is always a light-grey. However each frame, ~TrailColor(int time)
12 	is called in the projectile which can return the color modulation.
13 
14 	@author Newton, Maikel
15 */
16 
17 local for_bullet;
18 local width, length;
19 local speed, rotation;
20 local orig_x, orig_y;
21 
Set(object bullet,int wdt,int lgt)22 public func Set(object bullet, int wdt, int lgt)
23 {
24 	// Store the bullet for which this trail is made.
25 	for_bullet = bullet;
26 
27 	// Change plane to be just behind bullet.
28 	this.Plane = for_bullet.Plane - 1;
29 
30 	// Store trail properties.
31 	width = 1000 * wdt / ActMap.Travel.Wdt;
32 	length = 1000 * lgt / ActMap.Travel.Hgt;
33 	var xdir = for_bullet->GetXDir(1000);
34 	var ydir = for_bullet->GetYDir(1000);
35 	speed = Distance(0, 0, xdir, ydir) / Sqrt(1000);
36 	rotation = Angle(0, 0, xdir, ydir);
37 	orig_x = for_bullet->GetX();
38 	orig_y = for_bullet->GetY();
39 
40 	// Copy bullet's motion.
41 	SetAction("Travel");
42 	SetComDir(COMD_None);
43 	SetPosition(orig_x, orig_y);
44 	SetXDir(xdir, 1000);
45 	SetYDir(ydir, 1000);
46 	return;
47 }
48 
UpdateTrail()49 private func UpdateTrail()
50 {
51 	// Remove trail if the bullet is gone or the trail is out of the landscape borders.
52 	if (!for_bullet)
53 		return Remove();
54 	if ((GetX() <= 0 && GetXDir() < 0) || (GetX() >= LandscapeWidth() && GetXDir() > 0) || (GetY() <= 0 && GetYDir() < 0) || (GetY() >= LandscapeHeight() && GetYDir() > 0))
55 		return Remove();
56 
57 	// Display.
58 	DrawTransform();
59 	// Adjust trail color as specified in bullet.
60 	if (for_bullet)
61 	{
62 		var trail_color = for_bullet->~TrailColor(GetActTime());
63 		if (trail_color != nil)
64 			SetClrModulation(for_bullet->~TrailColor(GetActTime()));
65 	}
66 	return;
67 }
68 
RemoveTrail()69 public func RemoveTrail()
70 {
71 	// Reduce trail length by its speed every frame.
72 	length = Max(0, length - speed);
73 	// Display.
74 	DrawTransform();
75 	// Remove trail if its length is zero.
76 	if (length <= 0)
77 		return RemoveObject();
78 	return;
79 }
80 
Hit()81 public func Hit()
82 {
83 	// Remove trail if it hit something.
84 	return Remove();
85 }
86 
Remove()87 private func Remove()
88 {
89 	SetXDir(0);
90 	SetYDir(0);
91 	return SetAction("Remove");
92 }
93 
DrawTransform()94 public func DrawTransform()
95 {
96 	// Determine length, width and position of the trail.
97 	var distance = Distance(orig_x, orig_y, GetX(), GetY());
98 	var relative_length = 1000 * distance / ActMap.Travel.Hgt;
99 
100 	var h = Min(length, relative_length);
101 
102 	var fsin = -Sin(rotation, 1000);
103 	var fcos = Cos(rotation, 1000);
104 
105 	var xoff = -ActMap.Travel.Wdt * width / 2 + 750;
106 	var yoff = 0;
107 
108 	// Set object draw transformation.
109 	var draw_width = +fcos * width / 1000;
110 	var draw_height = +fcos * h / 1000;
111 	var xskew = +fsin * h / 1000;
112 	var yskew = -fsin * width / 1000;
113 	var xadjust = (+fcos * xoff + fsin * yoff) / 1000;
114 	var yadjust = (-fsin * xoff + fcos * yoff) / 1000;
115 	return SetObjDrawTransform(draw_width, xskew, xadjust, yskew, draw_height, yadjust);
116 }
117 
SaveScenarioObject()118 public func SaveScenarioObject() { return false; }
119 
120 
121 /*-- Properties --*/
122 
123 local Plane = 300;
124 
125 local ActMap = {
126 	Travel = {
127 		Prototype = Action,
128 		Name = "Travel",
129 		Procedure = DFA_FLOAT,
130 		NextAction = "Travel",
131 		Length = 1,
132 		Delay = 1,
133 		X = 0,
134 		Y = 0,
135 		Wdt = 5,
136 		Hgt = 25,
137 		OffX = 0,
138 		OffY = 2,
139 		StartCall = "UpdateTrail"
140 	},
141 	Remove = {
142 		Prototype = Action,
143 		Name = "Remove",
144 		Procedure = DFA_FLOAT,
145 		NextAction = "Remove",
146 		Length = 1,
147 		Delay = 1,
148 		X = 0,
149 		Y = 0,
150 		Wdt = 5,
151 		Hgt = 25,
152 		OffX = 0,
153 		OffY = 2,
154 		StartCall = "RemoveTrail"
155 	}
156 };
157