1 /*-------------------------------------------------------------------------------
2
3 BARONY
4 File: actpowercrystal.cpp
5 Desc: behavior function for power crystals
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 "monster.hpp"
17 #include "sound.hpp"
18 #include "items.hpp"
19 #include "net.hpp"
20 #include "collision.hpp"
21 #include "player.hpp"
22
23 /*-------------------------------------------------------------------------------
24
25 act*
26
27 The following function describes an entity behavior. The function
28 takes a pointer to the entity that uses it as an argument.
29
30 -------------------------------------------------------------------------------*/
31
actPowerCrystalBase(Entity * my)32 void actPowerCrystalBase(Entity* my)
33 {
34 if ( my->flags[PASSABLE] ) // stop the compiler optimising into a different entity.
35 {
36 my->flags[PASSABLE] = false;
37 }
38
39 return;
40 }
41
actPowerCrystal(Entity * my)42 void actPowerCrystal(Entity* my)
43 {
44 if ( !my )
45 {
46 return;
47 }
48
49 my->actPowerCrystal();
50 }
51
actPowerCrystal()52 void Entity::actPowerCrystal()
53 {
54 //Entity* entity;
55 real_t upper_z = this->crystalStartZ - 0.4;
56 real_t lower_z = crystalStartZ + 0.4;
57 int i = 0;
58
59 real_t acceleration = 0.95;
60
61 //this->light = lightSphereShadow(this->x / 16, this->y / 16, 3, 64);
62 //messagePlayer(0, "vel z: %f", this->vel_z);
63
64 if ( !crystalInitialised && !crystalSpellToActivate )
65 {
66 if ( this->z > crystalStartZ )
67 {
68 this->z -= this->vel_z * (1 / acceleration); // start levitating upwards.
69 }
70 else
71 {
72 this->z = crystalStartZ;
73 this->powerCrystalCreateElectricityNodes();
74 crystalInitialised = 1;
75 }
76 }
77
78 if ( crystalInitialised )
79 {
80 if ( crystalHoverDirection == CRYSTAL_HOVER_UP ) //rise state
81 {
82 this->z -= this->vel_z;
83
84 if ( this->z < upper_z )
85 {
86 this->z = upper_z;
87 crystalHoverDirection = CRYSTAL_HOVER_UP_WAIT;
88 }
89
90 if ( this->z < crystalStartZ ) //higher than mid point
91 {
92 this->vel_z = std::max(this->vel_z * acceleration, crystalMinZVelocity);
93 }
94 else if ( this->z > crystalStartZ ) //lower than midpoint
95 {
96 this->vel_z = std::min(this->vel_z * (1 / acceleration), crystalMaxZVelocity);
97 }
98 }
99 else if ( crystalHoverDirection == CRYSTAL_HOVER_UP_WAIT ) // wait state
100 {
101 crystalHoverWaitTimer++;
102 if ( crystalHoverWaitTimer >= 1 )
103 {
104 crystalHoverDirection = CRYSTAL_HOVER_DOWN; // advance state
105 crystalHoverWaitTimer = 0; // reset timer
106 }
107 }
108 else if ( crystalHoverDirection == CRYSTAL_HOVER_DOWN ) //fall state
109 {
110 this->z += this->vel_z;
111
112 if ( this->z > lower_z )
113 {
114 this->z = lower_z;
115 crystalHoverDirection = CRYSTAL_HOVER_DOWN_WAIT;
116 }
117
118 if ( this->z < crystalStartZ ) //higher than mid point, start accelerating
119 {
120 this->vel_z = std::min(this->vel_z * (1 / acceleration), crystalMaxZVelocity);
121 }
122 else if ( this->z > crystalStartZ ) //lower than midpoint, start decelerating
123 {
124 this->vel_z = std::max(this->vel_z * acceleration, crystalMinZVelocity);
125 }
126 }
127 else if ( crystalHoverDirection == CRYSTAL_HOVER_DOWN_WAIT ) // wait state
128 {
129 crystalHoverWaitTimer++;
130 if ( crystalHoverWaitTimer >= 1 )
131 {
132 crystalHoverDirection = CRYSTAL_HOVER_UP; // advance state
133 crystalHoverWaitTimer = 0; // reset timer
134 }
135 }
136
137
138 if ( this->z <= crystalStartZ + crystalMaxZVelocity && this->z >= crystalStartZ - crystalMaxZVelocity )
139 {
140 this->vel_z = this->fskill[1]; // reset velocity at the mid point of animation
141 }
142
143 spawnAmbientParticles(80, 579, 10 + rand() % 40, 1.0, false);
144
145 if ( crystalTurning == 1 )
146 {
147 if ( !crystalTurnReverse )
148 {
149 this->yaw += crystalTurnVelocity; // reverse velocity if turnReverse is 1
150
151 if ( (this->yaw >= (crystalTurnStartDir * (PI / 2)) + (PI / 2)) )
152 {
153 this->yaw = crystalTurnStartDir * (PI / 2) + (PI / 2);
154 crystalTurning = 0;
155
156 if ( this->yaw >= 2 * PI )
157 {
158 this->yaw = 0;
159 }
160 this->powerCrystalCreateElectricityNodes();
161 }
162 }
163 else
164 {
165 this->yaw -= crystalTurnVelocity;// reverse velocity if turnReverse is 1
166
167 if ( (this->yaw <= (crystalTurnStartDir * (PI / 2)) - (PI / 2)) )
168 {
169 this->yaw = crystalTurnStartDir * (PI / 2) - (PI / 2);
170 crystalTurning = 0;
171
172 if ( this->yaw < 0 )
173 {
174 this->yaw += 2 * PI;
175 }
176 this->powerCrystalCreateElectricityNodes();
177 }
178 }
179 }
180 }
181
182 if ( multiplayer == CLIENT )
183 {
184 return;
185 }
186
187 // handle player turning the crystal
188
189 for ( i = 0; i < MAXPLAYERS; i++ )
190 {
191 if ( ((i == 0 && selectedEntity == this) || (client_selected[i] == this)) && crystalTurning == 0 )
192 {
193 if ( inrange[i] )
194 {
195 if ( players[i] && players[i]->entity && crystalInitialised )
196 {
197 playSoundEntity(this, 151, 128);
198 crystalTurning = 1;
199 crystalTurnStartDir = static_cast<Sint32>(this->yaw / (PI / 2));
200 serverUpdateEntitySkill(this, 3);
201 serverUpdateEntitySkill(this, 4);
202 messagePlayer(i, language[2356]);
203 }
204 else if ( !crystalInitialised )
205 {
206 messagePlayer(i, language[2357]);
207 }
208 }
209 }
210 }
211
212 return;
213 }
214
215 // ambient particle effects.
actPowerCrystalParticleIdle(Entity * my)216 void actPowerCrystalParticleIdle(Entity* my)
217 {
218 if ( !my )
219 {
220 return;
221 }
222
223 if ( my->skill[0] < 0 )
224 {
225 list_RemoveNode(my->mynode);
226 return;
227 }
228 else
229 {
230 --my->skill[0];
231 my->z += my->vel_z;
232 //my->z -= 0.01;
233 }
234 return;
235 }
236
powerCrystalCreateElectricityNodes()237 void Entity::powerCrystalCreateElectricityNodes()
238 {
239 Entity* entity = nullptr;
240 node_t* node = nullptr;
241 node_t* nextnode = nullptr;
242 real_t xtest = 0;
243 real_t ytest = 0;
244
245 int i = 0;
246
247 if ( crystalGeneratedElectricityNodes )
248 {
249 this->mechanismPowerOff(); // turn off my signal
250 this->updateCircuitNeighbors(); // update the old wires to depower
251
252 if ( multiplayer != CLIENT )
253 {
254 for ( node = this->children.first; node != nullptr; node = nextnode )
255 {
256 nextnode = node->next;
257 if ( node->element != nullptr )
258 {
259 entity = (Entity*)node->element;
260 if ( entity->light != nullptr )
261 {
262 list_RemoveNode(entity->light->node);
263 }
264 entity->light = nullptr;
265 list_RemoveNode(entity->mynode);
266 }
267 list_RemoveNode(node); // delete all previously generated electricity nodes.
268 }
269 }
270 }
271
272 for ( i = 1; i <= crystalNumElectricityNodes; i++ )
273 {
274 entity = newEntity(-1, 0, map.entities, nullptr); // electricity node
275 xtest = this->x + i * 16 * ((this->yaw == 0) - (this->yaw == PI)); // add/subtract x depending on direction.
276 ytest = this->y + i * 16 * ((this->yaw == PI / 2) - (this->yaw == 3 * PI / 2)); // add/subtract y depending on direction.
277
278 if ( (static_cast<int>(xtest) >> 4) < 0 || (static_cast<int>(xtest) >> 4) >= map.width ||
279 (static_cast<int>(ytest) >> 4) < 0 || (static_cast<int>(ytest) >> 4) >= map.height )
280 {
281 //messagePlayer(0, "stopped at index %d, x: %d, y: %d", i, (static_cast<int>(xtest) >> 4), (static_cast<int>(ytest) >> 4));
282 break; // stop generating more nodes as we are out of bounds
283 }
284
285 //messagePlayer(0, "gen at index %d", i);
286 entity->x = xtest;
287 entity->y = ytest;
288 entity->z = 5;
289 entity->behavior = &actCircuit;
290 entity->flags[PASSABLE] = true;
291 entity->flags[INVISIBLE] = true;
292 entity->flags[NOUPDATE] = true;
293 entity->circuit_status = CIRCUIT_OFF; //It's a depowered powerable.
294
295 node = list_AddNodeLast(&this->children);
296 node->element = entity; // add the node to the children list.
297 node->deconstructor = &emptyDeconstructor;
298 node->size = sizeof(Entity*);
299
300 TileEntityList.addEntity(*entity); // make sure new nodes are added to the tile list to properly update neighbors.
301
302 this->crystalGeneratedElectricityNodes = 1;
303 }
304
305 this->mechanismPowerOn();
306 this->updateCircuitNeighbors();
307
308 return;
309 }
310