1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: actmagictrap.cpp
5 	Desc: implements magic trap code
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 "entity.hpp"
16 #include "sound.hpp"
17 #include "items.hpp"
18 #include "net.hpp"
19 #include "monster.hpp"
20 #include "collision.hpp"
21 #include "player.hpp"
22 #include "magic/magic.hpp"
23 
24 /*-------------------------------------------------------------------------------
25 
26 act*
27 
28 The following function describes an entity behavior. The function
29 takes a pointer to the entity that uses it as an argument.
30 
31 -------------------------------------------------------------------------------*/
actMagicTrapCeiling(Entity * my)32 void actMagicTrapCeiling(Entity* my)
33 {
34 	if ( !my )
35 	{
36 		return;
37 	}
38 
39 	my->actMagicTrapCeiling();
40 }
41 
42 
actMagicTrapCeiling()43 void Entity::actMagicTrapCeiling()
44 {
45 	spellTrapAmbience--;
46 	if ( spellTrapAmbience <= 0 )
47 	{
48 		spellTrapAmbience = TICKS_PER_SECOND * 30;
49 		playSoundEntity(this, 149, 16);
50 	}
51 
52 	if ( multiplayer == CLIENT )
53 	{
54 		return;
55 	}
56 	if ( circuit_status != CIRCUIT_ON )
57 	{
58 		spellTrapReset = 0;
59 		spellTrapCounter = spellTrapRefireRate; //shoost instantly!
60 		return;
61 	}
62 
63 	if ( !spellTrapInit )
64 	{
65 		spellTrapInit = 1;
66 		if ( spellTrapType == -1 )
67 		{
68 			switch ( rand() % 8 )
69 			{
70 				case 0:
71 					spellTrapType = SPELL_FORCEBOLT;
72 					break;
73 				case 1:
74 					spellTrapType = SPELL_MAGICMISSILE;
75 					break;
76 				case 2:
77 					spellTrapType = SPELL_COLD;
78 					break;
79 				case 3:
80 					spellTrapType = SPELL_FIREBALL;
81 					break;
82 				case 4:
83 					spellTrapType = SPELL_LIGHTNING;
84 					break;
85 				case 5:
86 					spellTrapType = SPELL_SLEEP;
87 					spellTrapRefireRate = 275; // stop getting stuck forever!
88 					break;
89 				case 6:
90 					spellTrapType = SPELL_CONFUSE;
91 					break;
92 				case 7:
93 					spellTrapType = SPELL_SLOW;
94 					break;
95 				default:
96 					spellTrapType = SPELL_MAGICMISSILE;
97 					break;
98 			}
99 		}
100 		//light = lightSphere(my->x / 16, my->y / 16, 3, 192);
101 	}
102 
103 	++spellTrapCounter;
104 
105 	node_t* node = children.first;
106 	Entity* ceilingModel = (Entity*)(node->element);
107 	int triggerSprite = 0;
108 	switch ( spellTrapType )
109 	{
110 		case SPELL_FORCEBOLT:
111 		case SPELL_MAGICMISSILE:
112 		case SPELL_CONFUSE:
113 			triggerSprite = 173;
114 			break;
115 		case SPELL_FIREBALL:
116 			triggerSprite = 168;
117 			break;
118 		case SPELL_LIGHTNING:
119 			triggerSprite = 170;
120 			break;
121 		case SPELL_COLD:
122 		case SPELL_SLEEP:
123 			triggerSprite = 172;
124 			break;
125 		case SPELL_SLOW:
126 		default:
127 			triggerSprite = 171;
128 			break;
129 	}
130 
131 	if ( spellTrapCounter > spellTrapRefireRate )
132 	{
133 		spellTrapCounter = 0; // reset timer.
134 		if ( spellTrapReset == 0 )
135 		{
136 			// once off magic particles. reset once power is cut.
137 			spawnMagicEffectParticles(x, y, z, triggerSprite);
138 			playSoundEntity(this, 252, 128);
139 			spellTrapReset = 1;
140 			/*spellTrapCounter = spellTrapRefireRate - 5; // delay?
141 			return;*/
142 		}
143 		Entity* entity = castSpell(getUID(), getSpellFromID(spellTrapType), false, true);
144 		if ( ceilingModel && entity )
145 		{
146 			entity->x = x;
147 			entity->y = y;
148 			entity->z = ceilingModel->z - 2;
149 			double missile_speed = 4 * ((double)(((spellElement_t*)(getSpellFromID(spellTrapType)->elements.first->element))->mana) / ((spellElement_t*)(getSpellFromID(spellTrapType)->elements.first->element))->overload_multiplier);
150 			entity->vel_x = 0.0;
151 			entity->vel_y = 0.0;
152 			entity->vel_z = 0.5 * (missile_speed);
153 			entity->pitch = PI / 2;
154 			entity->actmagicIsVertical = MAGIC_ISVERTICAL_Z;
155 		}
156 	}
157 }
158 
159 /*-------------------------------------------------------------------------------
160 
161 act*
162 
163 The following function describes an entity behavior. The function
164 takes a pointer to the entity that uses it as an argument.
165 
166 -------------------------------------------------------------------------------*/
167 
168 #define MAGICTRAP_INIT my->skill[0]
169 #define MAGICTRAP_SPELL my->skill[1]
170 #define MAGICTRAP_DIRECTION my->skill[3]
171 
actMagicTrap(Entity * my)172 void actMagicTrap(Entity* my)
173 {
174 	if ( !MAGICTRAP_INIT )
175 	{
176 		MAGICTRAP_INIT = 1;
177 		switch ( rand() % 8 )
178 		{
179 			case 0:
180 				MAGICTRAP_SPELL = SPELL_FORCEBOLT;
181 				break;
182 			case 1:
183 				MAGICTRAP_SPELL = SPELL_MAGICMISSILE;
184 				break;
185 			case 2:
186 				MAGICTRAP_SPELL = SPELL_COLD;
187 				break;
188 			case 3:
189 				MAGICTRAP_SPELL = SPELL_FIREBALL;
190 				break;
191 			case 4:
192 				MAGICTRAP_SPELL = SPELL_LIGHTNING;
193 				break;
194 			case 5:
195 				MAGICTRAP_SPELL = SPELL_SLEEP;
196 				break;
197 			case 6:
198 				MAGICTRAP_SPELL = SPELL_CONFUSE;
199 				break;
200 			case 7:
201 				MAGICTRAP_SPELL = SPELL_SLOW;
202 				break;
203 			default:
204 				MAGICTRAP_SPELL = SPELL_MAGICMISSILE;
205 				break;
206 		}
207 		my->light = lightSphere(my->x / 16, my->y / 16, 3, 192);
208 	}
209 
210 	// eliminate traps that have been destroyed.
211 	// check wall inside me.
212 	int checkx = static_cast<int>(my->x) >> 4;
213 	int checky = static_cast<int>(my->y) >> 4;
214 	if ( !map.tiles[OBSTACLELAYER + checky * MAPLAYERS + checkx * MAPLAYERS * map.height] )   // wall
215 	{
216 		my->removeLightField();
217 		list_RemoveNode(my->mynode);
218 		return;
219 	}
220 
221 	if ( multiplayer == CLIENT )
222 	{
223 		return;
224 	}
225 
226 	if ( my->ticks % TICKS_PER_SECOND == 0 )
227 	{
228 		int oldir = 0;
229 		int x = 0, y = 0;
230 		switch ( MAGICTRAP_DIRECTION )
231 		{
232 			case 0:
233 				x = 12;
234 				y = 0;
235 				oldir = MAGICTRAP_DIRECTION;
236 				MAGICTRAP_DIRECTION++;
237 				break;
238 			case 1:
239 				x = 0;
240 				y = 12;
241 				oldir = MAGICTRAP_DIRECTION;
242 				MAGICTRAP_DIRECTION++;
243 				break;
244 			case 2:
245 				x = -12;
246 				y = 0;
247 				oldir = MAGICTRAP_DIRECTION;
248 				MAGICTRAP_DIRECTION++;
249 				break;
250 			case 3:
251 				x = 0;
252 				y = -12;
253 				oldir = MAGICTRAP_DIRECTION;
254 				MAGICTRAP_DIRECTION = 0;
255 				break;
256 		}
257 		int u = std::min<int>(std::max<int>(0.0, (my->x + x) / 16), map.width - 1);
258 		int v = std::min<int>(std::max<int>(0.0, (my->y + y) / 16), map.height - 1);
259 		if ( !map.tiles[OBSTACLELAYER + v * MAPLAYERS + u * MAPLAYERS * map.height] )
260 		{
261 			Entity* entity = castSpell(my->getUID(), getSpellFromID(MAGICTRAP_SPELL), false, true);
262 			entity->x = my->x + x;
263 			entity->y = my->y + y;
264 			entity->z = my->z;
265 			entity->yaw = oldir * (PI / 2.f);
266 			double missile_speed = 4 * ((double)(((spellElement_t*)(getSpellFromID(MAGICTRAP_SPELL)->elements.first->element))->mana) / ((spellElement_t*)(getSpellFromID(MAGICTRAP_SPELL)->elements.first->element))->overload_multiplier);
267 			entity->vel_x = cos(entity->yaw) * (missile_speed);
268 			entity->vel_y = sin(entity->yaw) * (missile_speed);
269 		}
270 	}
271 }