1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: actgib.cpp
5 	Desc: behavior function for gibs
6 
7 	Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 	See LICENSE for details.
9 
10 -------------------------------------------------------------------------------*/
11 
12 #include "main.hpp"
13 #include "game.hpp"
14 #include "stat.hpp"
15 #include "monster.hpp"
16 #include "entity.hpp"
17 #include "net.hpp"
18 #include "collision.hpp"
19 #include "player.hpp"
20 
21 /*-------------------------------------------------------------------------------
22 
23 	act*
24 
25 	The following function describes an entity behavior. The function
26 	takes a pointer to the entity that uses it as an argument.
27 
28 -------------------------------------------------------------------------------*/
29 
30 #define GIB_VELX my->vel_x
31 #define GIB_VELY my->vel_y
32 #define GIB_VELZ my->vel_z
33 #define GIB_GRAVITY my->fskill[3]
34 #define GIB_LIFESPAN my->skill[4]
35 
actGib(Entity * my)36 void actGib(Entity* my)
37 {
38 	// don't update gibs that have no velocity
39 	if ( my->z == 8 && fabs(GIB_VELX) < .01 && fabs(GIB_VELY) < .01 )
40 	{
41 		list_RemoveNode(my->mynode);
42 		return;
43 	}
44 
45 	// remove gibs that have exceeded their life span
46 	if ( my->ticks > GIB_LIFESPAN && GIB_LIFESPAN )
47 	{
48 		list_RemoveNode(my->mynode);
49 		return;
50 	}
51 
52 	if ( my->flags[OVERDRAW]
53 		&& players[clientnum] && players[clientnum]->entity && players[clientnum]->entity->skill[3] == 1 )
54 	{
55 		// debug cam, don't draw overdrawn.
56 		my->flags[INVISIBLE] = true;
57 	}
58 
59 	// horizontal motion
60 	my->yaw += sqrt(GIB_VELX * GIB_VELX + GIB_VELY * GIB_VELY) * .05;
61 	my->x += GIB_VELX;
62 	my->y += GIB_VELY;
63 	GIB_VELX = GIB_VELX * .95;
64 	GIB_VELY = GIB_VELY * .95;
65 
66 	// gravity
67 	if ( my->z < 8 )
68 	{
69 		GIB_VELZ += GIB_GRAVITY;
70 		my->z += GIB_VELZ;
71 		my->roll += 0.1;
72 	}
73 	else
74 	{
75 		if ( my->x >= 0 && my->y >= 0 && my->x < map.width << 4 && my->y < map.height << 4 )
76 		{
77 			if ( !map.tiles[(int)(floor(my->y / 16)*MAPLAYERS + floor(my->x / 16)*MAPLAYERS * map.height)] )
78 			{
79 				GIB_VELZ += GIB_GRAVITY;
80 				my->z += GIB_VELZ;
81 				my->roll += 0.1;
82 			}
83 			else
84 			{
85 				GIB_VELZ = 0;
86 				my->z = 8;
87 				my->roll = PI / 2.0;
88 			}
89 		}
90 		else
91 		{
92 			GIB_VELZ += GIB_GRAVITY;
93 			my->z += GIB_VELZ;
94 			my->roll += 0.1;
95 		}
96 	}
97 
98 	// gibs disappear after falling to a certain point
99 	if ( my->z > 128 )
100 	{
101 		list_RemoveNode(my->mynode);
102 		return;
103 	}
104 }
105 
106 /*-------------------------------------------------------------------------------
107 
108 	spawnGib
109 
110 	Spawns a gib with a random velocity for the entity supplied as an
111 	argument
112 
113 -------------------------------------------------------------------------------*/
114 
spawnGib(Entity * parentent,int customGibSprite)115 Entity* spawnGib(Entity* parentent, int customGibSprite)
116 {
117 	Entity* entity = nullptr;
118 	Stat* parentstats = nullptr;
119 	double vel;
120 	int gibsprite = 5;
121 
122 	if ( !parentent )
123 	{
124 		return nullptr;
125 	}
126 
127 	if ( (parentstats = parentent->getStats()) != nullptr )
128 	{
129 		if ( multiplayer == CLIENT )
130 		{
131 			printlog("[%s:%d spawnGib()] spawnGib() called on client, got clientstats. Probably bad?", __FILE__, __LINE__);
132 		}
133 
134 		if ( customGibSprite != -1 )
135 		{
136 			gibsprite = customGibSprite;
137 		}
138 		else
139 		{
140 			switch ( gibtype[(int)parentstats->type] )
141 			{
142 				case 0:
143 					return nullptr;
144 				case 1:
145 					gibsprite = 5;
146 					break;
147 				case 2:
148 					gibsprite = 211;
149 					break;
150 				case 3:
151 					if ( parentent->sprite == 210 )
152 					{
153 						gibsprite = 211;
154 					}
155 					else
156 					{
157 						gibsprite = 215;
158 					}
159 					break;
160 				case 4:
161 					gibsprite = 683;
162 					break;
163 				//TODO: Gear gibs for automatons, and crystal gibs for golem.
164 				default:
165 					gibsprite = 5;
166 					break;
167 			}
168 		}
169 	}
170 	else if ( parentent->behavior == &actThrown )
171 	{
172 		if ( customGibSprite != -1 )
173 		{
174 			gibsprite = customGibSprite;
175 		}
176 	}
177 
178 	entity = newEntity(gibsprite, 1, map.entities, nullptr); //Gib entity.
179 	if ( !entity )
180 	{
181 		return nullptr;
182 	}
183 	entity->x = parentent->x;
184 	entity->y = parentent->y;
185 	entity->z = parentent->z;
186 	entity->parent = parentent->getUID();
187 	entity->sizex = 2;
188 	entity->sizey = 2;
189 	entity->yaw = (rand() % 360) * PI / 180.0;
190 	entity->pitch = (rand() % 360) * PI / 180.0;
191 	entity->roll = (rand() % 360) * PI / 180.0;
192 	vel = (rand() % 10) / 10.f;
193 	entity->vel_x = vel * cos(entity->yaw);
194 	entity->vel_y = vel * sin(entity->yaw);
195 	entity->vel_z = -.5;
196 	entity->fskill[3] = 0.04;
197 	entity->behavior = &actGib;
198 	entity->flags[PASSABLE] = true;
199 	entity->flags[NOUPDATE] = true;
200 	entity->flags[UNCLICKABLE] = true;
201 	if ( !spawn_blood && customGibSprite == -1 )
202 	{
203 		entity->flags[INVISIBLE] = true;
204 	}
205 	if ( multiplayer != CLIENT )
206 	{
207 		entity_uids--;
208 	}
209 	entity->setUID(-3);
210 
211 	return entity;
212 }
213 
spawnGibClient(Sint16 x,Sint16 y,Sint16 z,Sint16 sprite)214 Entity* spawnGibClient(Sint16 x, Sint16 y, Sint16 z, Sint16 sprite)
215 {
216 	double vel;
217 
218 	Entity* entity = newEntity(sprite, 1, map.entities, nullptr); //Gib entity.
219 	entity->x = x;
220 	entity->y = y;
221 	entity->z = z;
222 	entity->sizex = 2;
223 	entity->sizey = 2;
224 	entity->yaw = (rand() % 360) * PI / 180.0;
225 	entity->pitch = (rand() % 360) * PI / 180.0;
226 	entity->roll = (rand() % 360) * PI / 180.0;
227 	vel = (rand() % 10) / 10.f;
228 	entity->vel_x = vel * cos(entity->yaw);
229 	entity->vel_y = vel * sin(entity->yaw);
230 	entity->vel_z = -.5;
231 	entity->fskill[3] = 0.04;
232 	entity->behavior = &actGib;
233 	entity->flags[PASSABLE] = true;
234 	entity->flags[NOUPDATE] = true;
235 	entity->flags[UNCLICKABLE] = true;
236 
237 	return entity;
238 }
239 
serverSpawnGibForClient(Entity * gib)240 void serverSpawnGibForClient(Entity* gib)
241 {
242 	int c;
243 	if ( !gib )
244 	{
245 		return;
246 	}
247 	if ( multiplayer == SERVER )
248 	{
249 		for ( c = 1; c < MAXPLAYERS; c++ )
250 		{
251 			if ( client_disconnected[c] )
252 			{
253 				continue;
254 			}
255 			strcpy((char*)net_packet->data, "SPGB");
256 			SDLNet_Write16((Sint16)gib->x, &net_packet->data[4]);
257 			SDLNet_Write16((Sint16)gib->y, &net_packet->data[6]);
258 			SDLNet_Write16((Sint16)gib->z, &net_packet->data[8]);
259 			SDLNet_Write16((Sint16)gib->sprite, &net_packet->data[10]);
260 			net_packet->data[12] = gib->flags[SPRITE];
261 			net_packet->address.host = net_clients[c - 1].host;
262 			net_packet->address.port = net_clients[c - 1].port;
263 			net_packet->len = 13;
264 			sendPacketSafe(net_sock, -1, net_packet, c - 1);
265 		}
266 	}
267 }
268