1 /***************************************************************************
2 StateBehavior.cpp - description
3 -------------------
4 begin : Thu Jan 25 2001
5 copyright : (C) 2001 by Henrik Enqvist
6 email : henqvist@excite.com
7
8
9 ========================= Modifications =========================
10
11 Apr. 4, 2017:
12 Clear the keyboard on game reset. (c30zD)
13
14 ***************************************************************************/
15
16 #include "Private.h"
17 #include "StateBehavior.h"
18 #include "Pinball.h"
19 #include "Group.h"
20 #include "Light.h"
21 #include "Shape3D.h"
22 #include "Polygon.h"
23 #include "SoundUtil.h"
24 #include "BallGroup.h"
25 #include "Loader.h"
26 #include "Keyboard.h"
27
StateItem()28 StateItem::StateItem() {
29 m_iActSig = -1;
30 m_iCollSig = -1;
31 m_iSigDelay = 0;
32 m_bLight = false;
33 m_iUserProperty = PBL_NULL;
34 m_iShapeProperty = 0;
35 m_iSound = -1;
36 m_iMusic = -1;
37 m_iDelay = -1;
38 m_iDelayState = -1;
39 m_iCollState = -1;
40 m_iMoveSteps = 0;
41 m_iTick = 0;
42 m_vtxTr.x = 0;
43 m_vtxTr.y = 0;
44 m_vtxTr.z = 0;
45 m_vtxRot.x = 0;
46 m_vtxRot.y = 0;
47 m_vtxRot.z = 0;
48 }
49
~StateItem()50 StateItem::~StateItem() {
51 }
52
setTr(float x,float y,float z)53 void StateItem::setTr(float x, float y, float z) {
54 m_vtxTr.x = x;
55 m_vtxTr.y = y;
56 m_vtxTr.z = z;
57 //m_fTrSpeed = EM_ABS(speed);
58 }
59
setRot(float x,float y,float z)60 void StateItem::setRot(float x, float y, float z) {
61 m_vtxRot.x = x;
62 m_vtxRot.y = y;
63 m_vtxRot.z = z;
64 //m_fRotSpeed = EM_ABS(speed);
65 }
66
addTexCoord(float u,float v)67 void StateItem::addTexCoord(float u, float v) {
68 TexCoord tex;
69 tex.u = u;
70 tex.v = v;
71 m_vTexCoord.push_back(tex);
72 }
73
addShapeEnable(int i,bool e)74 void StateItem::addShapeEnable(int i, bool e) {
75 if (i < 0) return;
76 // expand vector
77 while (i+1 > (signed)m_vShapeEnable.size()) {
78 m_vShapeEnable.push_back(false);
79 }
80 m_vShapeEnable[i] = e;
81 }
82
getShapeEnable(int i)83 bool StateItem::getShapeEnable(int i) {
84 if (i < 0 || i >= (signed)m_vShapeEnable.size()) return false;
85 return m_vShapeEnable[i];
86 }
87
StateBehavior()88 StateBehavior::StateBehavior() : Behavior() {
89 m_iOwnerBall = -1;
90 m_iTick = 0;
91 m_iCollisionSafe = 0;
92 m_bTexCoord = false;
93 m_bMove = false;
94 m_bShape = false;
95 p_CurrentStateItem = NULL;
96 m_vtxTr.x = 0;
97 m_vtxTr.y = 0;
98 m_vtxTr.z = 0;
99 m_vtxRot.x = 0;
100 m_vtxRot.y = 0;
101 m_vtxRot.z = 0;
102 this->setType(PBL_TYPE_STATEBEH);
103 }
104
~StateBehavior()105 StateBehavior::~StateBehavior(){
106 }
107
addStateItem(StateItem * stateitem)108 void StateBehavior::addStateItem(StateItem* stateitem) {
109 if (stateitem == NULL) return;
110 // insert state
111 m_vStateItem.push_back(stateitem);
112 if (m_vStateItem.size() == 1) {
113 p_CurrentStateItem = stateitem;
114 }
115 }
116
removeStateItem(StateItem * stateitem)117 void StateBehavior::removeStateItem(StateItem* stateitem) {
118 if (stateitem == NULL) return;
119 if (p_CurrentStateItem == stateitem) {
120 p_CurrentStateItem = NULL;
121 }
122
123 vector<StateItem*>::iterator iter = m_vStateItem.begin();
124 vector<StateItem*>::iterator end = m_vStateItem.end();
125 for (; iter != end; iter++) {
126 if ((*iter) == stateitem) {
127 m_vStateItem.erase(iter);
128 return;
129 }
130 }
131
132 if (m_vStateItem.size() >= 1) {
133 p_CurrentStateItem = m_vStateItem[0];
134 }
135 }
136
getStateItem(int i)137 StateItem * StateBehavior::getStateItem(int i) {
138 if (i < 0 || m_vStateItem.size() <= (unsigned) i ) return NULL;
139 return m_vStateItem[i];
140 }
141
onTick()142 void StateBehavior::onTick() {
143 EmAssert(this->getParent() != NULL, "Parent NULL");
144 if (p_CurrentStateItem == NULL) return;
145
146 // initialize origo
147 if (m_iTick == 0) {
148 this->getParent()->getTranslation(m_vtxTr.x, m_vtxTr.y, m_vtxTr.z);
149 this->getParent()->getRotation(m_vtxRot.x, m_vtxRot.y, m_vtxRot.z);
150 }
151
152 m_iTick++;
153 p_CurrentStateItem->m_iTick++;
154
155 if (p_CurrentStateItem->m_iDelay >= 0 &&
156 p_CurrentStateItem->m_iTick >= p_CurrentStateItem->m_iDelay &&
157 p_CurrentStateItem->m_iDelayState >= 0) {
158 this->setState(this->getStateItem(p_CurrentStateItem->m_iDelayState));
159 }
160 // the ball recently collided with this object is in a safe distance
161 if (m_iTick > m_iCollisionSafe) {
162 m_iOwnerBall = -1;
163 }
164 // move the object to towards the next spot
165 // TODO smother move
166 if (m_bMove) {
167 int steps = p_CurrentStateItem->m_iMoveSteps - p_CurrentStateItem->m_iTick;
168
169 if (steps <= 0) {
170 this->getParent()->setTransform(m_vtxTr.x + p_CurrentStateItem->m_vtxTr.x,
171 m_vtxTr.y + p_CurrentStateItem->m_vtxTr.y,
172 m_vtxTr.z + p_CurrentStateItem->m_vtxTr.z,
173 m_vtxRot.x + p_CurrentStateItem->m_vtxRot.x,
174 m_vtxRot.y + p_CurrentStateItem->m_vtxRot.y,
175 m_vtxRot.z + p_CurrentStateItem->m_vtxRot.z);
176 } else {
177 float dtx, dty, dtz, drx, dry, drz;
178 float tx, ty, tz, rx, ry, rz;
179 this->getParent()->getTranslation(tx, ty, tz);
180 this->getParent()->getRotation(rx, ry, rz);
181
182 dtx = p_CurrentStateItem->m_vtxTr.x + m_vtxTr.x - tx;
183 dty = p_CurrentStateItem->m_vtxTr.y + m_vtxTr.y - ty;
184 dtz = p_CurrentStateItem->m_vtxTr.z + m_vtxTr.z - tz;
185 drx = p_CurrentStateItem->m_vtxRot.x + m_vtxRot.x - rx;
186 dry = p_CurrentStateItem->m_vtxRot.y + m_vtxRot.y - ry;
187 drz = p_CurrentStateItem->m_vtxRot.z + m_vtxRot.z - rz;
188
189 dtx /= steps; dty /= steps; dtz /= steps;
190 drx /= steps; dry /= steps; drz /= steps;
191 this->getParent()->addTransform(dtx, dty, dtz, drx, dry, drz);
192 }
193 }
194 }
195
setState(StateItem * stateitem)196 void StateBehavior::setState(StateItem* stateitem) {
197 EmAssert(p_CurrentStateItem != NULL, "Current state item NULL");
198 if (stateitem == NULL) return;
199 StateItem* previtem = p_CurrentStateItem;
200 p_CurrentStateItem = stateitem;
201
202 // set properties
203 this->getParent()->unsetUserProperty(previtem->m_iUserProperty);
204 this->getParent()->setUserProperty(p_CurrentStateItem->m_iUserProperty);
205 // defaults to shape 0
206 int sindex = 0;
207 Shape3D* shape = this->getParent()->getShape3D(sindex);
208 while (shape != NULL) {
209 shape->unsetProperty(previtem->m_iShapeProperty);
210 shape->setProperty(p_CurrentStateItem->m_iShapeProperty);
211 ++sindex;
212 shape = this->getParent()->getShape3D(sindex);
213 }
214 // apply texcoords
215 if (m_bTexCoord) {
216 // default to shape 0 TODO remove this thing, we can use shapes instead
217 Shape3D* shape = this->getParent()->getShape3D(0);
218 if (shape != NULL) {
219 // only apply to fisrst polygon TODO
220 Polygon3D* poly = shape->getPolygon(0);
221 if (poly != NULL) {
222 vector<TexCoord>::iterator iter1 = p_CurrentStateItem->m_vTexCoord.begin();
223 vector<TexCoord>::iterator end1 = p_CurrentStateItem->m_vTexCoord.end();
224 vector<TexCoord>::iterator iter2 = shape->m_vTexCoord.begin();
225 vector<TexCoord>::iterator end2 = shape->m_vTexCoord.end();
226 for (; iter1 != end1 && iter2 != end2; ++iter1, ++iter2) {
227 (*iter2) = (*iter1);
228 }
229 }
230 }
231 }
232 // look out shapes conflicts with shape properties
233 if (m_bShape) {
234 vector<bool>::iterator iter = p_CurrentStateItem->m_vShapeEnable.begin();
235 vector<bool>::iterator end = p_CurrentStateItem->m_vShapeEnable.end();
236 int index = 0;
237 Shape3D* shape = this->getParent()->getShape3D(index);
238 while (shape != NULL && iter != end) {
239 if (*iter) {
240 shape->unsetProperty(EM_SHAPE3D_HIDDEN);
241 } else {
242 shape->setProperty(EM_SHAPE3D_HIDDEN);
243 }
244 ++index;
245 ++iter;
246 shape = this->getParent()->getShape3D(index);
247 }
248 }
249 // start music
250 if (p_CurrentStateItem->m_iMusic >= 0) {
251 SoundUtil::getInstance()->playMusic(p_CurrentStateItem->m_iMusic, true);
252 }
253 // play sound
254 if (p_CurrentStateItem->m_iSound >= 0) {
255 SoundUtil::getInstance()->playSample(p_CurrentStateItem->m_iSound, false);
256 }
257 // apply light
258 SetLightOn(p_CurrentStateItem->m_bLight);
259 // zero counter
260 p_CurrentStateItem->m_iTick = 0;
261 }
262
StdOnSignal()263 void StateBehavior::StdOnSignal() {
264 EmAssert(this->getParent() != NULL, "Parent NULL");
265 if (p_CurrentStateItem == NULL && m_vStateItem.size() == 0) return;
266
267 // initialize origo, this is a ugle hack
268 if (m_iTick == 0) {
269 this->getParent()->getTranslation(m_vtxTr.x, m_vtxTr.y, m_vtxTr.z);
270 this->getParent()->getRotation(m_vtxRot.x, m_vtxRot.y, m_vtxRot.z);
271 }
272
273 #if EM_DEBUG
274 if (Loader::getInstance()->getSignal(GetSignal()) != NULL) {
275 EM_COUT("Got signal " << Loader::getInstance()->getSignal(GetSignal()), 0);
276 }
277 #endif
278
279 OnSignal( PBL_SIG_RESET_ALL) {
280 this->setState(m_vStateItem[0]);
281 // do a fast move
282 if (m_bMove) {
283 this->getParent()->setTransform(m_vtxTr.x + p_CurrentStateItem->m_vtxTr.x,
284 m_vtxTr.y + p_CurrentStateItem->m_vtxTr.y,
285 m_vtxTr.z + p_CurrentStateItem->m_vtxTr.z,
286 m_vtxRot.x + p_CurrentStateItem->m_vtxRot.x,
287 m_vtxRot.y + p_CurrentStateItem->m_vtxRot.y,
288 m_vtxRot.z + p_CurrentStateItem->m_vtxRot.z);
289
290 }
291 Keyboard::clear();
292 } else {
293 vector<StateItem*>::iterator iter = m_vStateItem.begin();
294 vector<StateItem*>::iterator end = m_vStateItem.end();
295 for (; iter != end; iter++) {
296 OnSignal((*iter)->m_iActSig) {
297 this->setState(*iter);
298 break;
299 }
300 }
301 }
302 }
303
StdOnCollision()304 void StateBehavior::StdOnCollision() {
305 if (p_CurrentStateItem == NULL && m_vStateItem.size() == 0) return;
306
307 OnCallerProperty( PBL_BALL ) {
308 // this is to avaid one collision to generate more than one signal
309 if (m_iTick <= m_iCollisionSafe) {
310 m_iCollisionSafe = m_iTick + 5;
311 return;
312 }
313
314 m_iOwnerBall = ((BallGroup*)em_group)->getBall();;
315 m_iCollisionSafe = m_iTick + 5;
316
317 // if (p_CurrentStateItem->m_iSound >= 0) {
318 // SoundUtil::getInstance()->playSample(p_CurrentStateItem->m_iSound, false);
319 // }
320 if (p_CurrentStateItem->m_iCollSig >= 0) {
321 SendSignal(p_CurrentStateItem->m_iCollSig, p_CurrentStateItem->m_iSigDelay,
322 this->getParent(), NULL);
323 }
324 if (p_CurrentStateItem->m_iCollState >= 0) {
325 this->setState(this->getStateItem(p_CurrentStateItem->m_iCollState));
326 }
327 EM_COUT("StateBehavior::StdOnCollision ball", 0);
328 }
329 }
330