JNR
laFightingCreature.cpp
1 /*
2 
3 Jump'n'Run Engine
4 http://www.atanaslaskov.com/jnr/
5 
6 BSD LICENSE
7 Copyright (c) 2007-2013, Atanas Laskov
8 All rights reserved.
9 
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are met:
12 1. Redistributions of source code must retain the above copyright notice,
13 this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright notice,
15 this list of conditions and the following disclaimer in the documentation
16 and/or other materials provided with the distribution.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL ATANAS LASKOV BE LIABLE FOR ANY
21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 */
29 
30 //
31 // FILE: laFightingCreature.cpp
32 //
33 // Copyright (C) 2007-2013 Atanas Laskov, <latanas@gmail.com>
34 //
35 #include "stdafx.h"
36 #include "Core-Level-JR.h"
37 
38 // Constructor
39 //
40 laFightingCreature::laFightingCreature(rpgSheet* pSheet):
41  laMovingCreature( pSheet ? pSheet : new rpgSheet_Fighter() )
42 {
43  // Initial state
44  //
45  _bAttack = _bAttack_Quick = M_FALSE;
46  _nSelectedAttack = 0;
47 
48  _ttDeath.parameters(M_DEATHFX_DURATION); // time to play the death anim
49  _ttDeath.reset();
50  _ttDeath.enable(M_FALSE);
51 
52  _ttHitImmunity.parameters(0.5); // imunity after an attack is initated
53  _ttHitImmunity.enable();
54  _ttHitImmunity.force();
55 
56  // No sounds by defaults
57  //
58  _pAttackSound = NULL;
59  _pSufferSound = NULL;
60  _pDieSound = NULL;
61 
62  // Load blood fx
63  //
64  laFileParser fxp;
65  char strFilePath[128]=M_DIR_FX;
66  fxParticleSystem_params param;
67 
68  sprintf(strFilePath, "%s%s", M_DIR_FX, "creature_blood.fx");
69  fxp.fileOpen(strFilePath);
70  fxp.readObj(&param, M_FALSE);
71  fxp.fileClose();
72 
73  _fxBlood.create(param);
74  _fxBlood.enable(M_TRUE);
75  _fxBlood.enableGeneration(M_TRUE);
76  _fxBlood.ctlRewind();
77 
78 }
79 
80 laFightingCreature::~laFightingCreature(void)
81 {
82 }
83 
84 
85 // This method is part of the laLoadableObj interface
86 //
87 void laFightingCreature::load(class laFileParser *fp)
88 {
89  ERRORLEVEL_BEGIN;
90 
91  //Do the laStateObject loading
92  laMovingCreature::load(fp);
93 
94  //Misc
95  getObject()->getModel(M_STATE_DIE)->cycle(M_FALSE);
96 
97  //_ttAttackCharge.parameters( ((rpgSheet_Fighter*)_pSheet)->modAttack(0).dChargeTime );
98  _ttAttackCharge.enable(M_FALSE);
99 
100  _ttAttack.parameters( getObject()->getModel(M_STATE_ATTACK)->duration() );
101  _ttAttack.enable(M_FALSE);
102 
103  ERRORLEVEL_END;
104 }
105 
106 // Respawn
107 //
108 void laFightingCreature::respawn()
109 {
110  laMovingCreature::respawn();
111 
112  //Reset attack state
113  //
114  _bAttack = _bAttack_Quick = M_FALSE;
115 
116  _ttDeath.reset();
117  _ttDeath.enable(M_FALSE);
118 
119  _color[3]= _outline.color[3]= 255;
120 }
121 
122 void laFightingCreature::attackInitiate(M_BOOL bQuick)
123 {
124  if(!isControlEnabled()) return;
125  if(attackIsCharged()) return;
126 
127  if( (!_ttAttackCharge.isEnabled()) /*&& (_ptPivot.bOnGround) /*&& (!_bJumping)*/ )
128  {
129  //_nSelectedAttack = nAttack;
130  _bAttack_Quick = bQuick;
131 
132  //MSG("%lf", selectedAttack().dChargeTime );
133  _ttAttackCharge.parameters( selectedAttack().dChargeTime );
134  _ttAttackCharge.enable();
135  _ttAttackCharge.reset();
136 
137  if(bQuick)
138  if(!_bAttack_Quick) fxMessages.add(0.8, laColor(255,255,0), "Haste!");
139 
140  //Play sound
141  //
142  if(_pAttackSound) _pAttackSound->play();
143  }
144 }
145 
146 // Stop attack (e.g. in the case of a jump)
147 //
148 void laFightingCreature::attackStop()
149 {
150  //if(_ttAttackCharge.isEnabled() || _ttAttack.isEnabled())
151  {
152  _bAttack = _bAttack_Quick = M_FALSE;
153 
154  _ttAttackCharge.reset();
155  _ttAttackCharge.enable(M_FALSE);
156 
157  _ttAttack.reset();
158  _ttAttack.enable(M_FALSE);
159  }
160 }
161 
162 // Hit another creature
163 //
164 void laFightingCreature::attack( unsigned nAttackIndex, laFightingCreature* pTarget ) {
165  ASSERT(pTarget, "Nil target object");
166  ASSERT(nAttackIndex < ((rpgSheet_Fighter*)_pSheet)->properties()->vAttacks.size(), "Attack %d not registered", nAttackIndex);
167 
168  pTarget->hit( ((rpgSheet_Fighter*)_pSheet)->modAttack( nAttackIndex ) );
169 }
170 
171 // Another creature, or trap, hits me
172 //
173 // NOTE: This method disregards the AP modifier of the attacker,
174 // and therefore it is more suitable for attacks performed by traps
175 // or other object that don't have modifiers.
176 //
177 // Attacking monsters should use the attack() methods instead of the hit() method;
178 //
179 void laFightingCreature::hit(rpgAttack attack)
180 {
181  //Check conditions
182  //
183  if( (!isAlive()) || isImmune() || getLevelObject()->isCompleted() ) return;
184 
185  // Hit
186  //
187  unsigned nDamage = ((rpgSheet_Fighter*)_pSheet)->hit( attack );
188 
189  // Perform actions after the hit
190  //
191  _hit_actions(nDamage);
192 }
193 
194 // Actions to be performed when the creature is hit
195 //
196 void laFightingCreature::_hit_actions(unsigned nDamage)
197 {
198  if( nDamage <=0 )
199  {
200  fxMessages.add(0.8, laColor(255,255,0), "Resist");
201  //TODO: play miss sound
202  return;
203  }
204 
205  if( ! ((rpgSheet_Fighter*)_pSheet)->isAlive() )
206  {
207  //fxMessages.add(1.5, laColor(255,0,0), "x_x");
208 
209  if(_pDieSound) _pDieSound->play();
210  //_pObject->getModel(M_CREATURE_MDIE)->frameIndex(0);
211  }
212  else if(_pSufferSound) _pSufferSound->play();
213 
214  //Activate blood FX
215  _fxBlood.reset();
216 
217  //Display HP change message
218  fxMessages.add(1, laColor(255,0,0), "-%d", (int)nDamage);
219 
220  //Enable Hit Immunity
221  _ttHitImmunity.reset();
222  //_ttHitImmunity.enable(M_TRUE);
223  //_bHitImmunity = M_TRUE;
224 }
225 
226 // Animate
227 //
228 void laFightingCreature::animate(laTimer &t)
229 {
230  ERRORLEVEL_BEGIN;
231 
232  _ttAttackCharge.animate(t);
233  _ttAttack.animate(t);
234 
235  _ttHitImmunity.animate(t);
236  _ttDeath.animate(t);
237 
238  // Animate attacks
239  _animate_attacks();
240 
241  //Animate blood FX
242  //
243  //_fxBlood.position( _ptPivot );
244  _fxBlood.animate(t);
245 
246  // Default animation
247  //
248  laMovingCreature::animate(t);
249  ERRORLEVEL_END;
250 }
251 
252 void laFightingCreature::_animate_attacks()
253 {
254  // Hit immunity trigger
255  //
256  //if(_ttHitImmunity.isElapsed()) _bHitImmunity = M_FALSE;
257 
258  //Reset attacks
259  //
260  if( _ttAttackCharge.isElapsed() && (!_bAttack) )
261  {
262  _bAttack = M_TRUE;
263  _ttAttack.enable();
264  _ttAttack.reset();
265 
266  if(_bAttack_Quick)
267  {
268  getObject()->getModel(M_STATE_QATTACK)->frameIndex(0);
269  getObject()->getModel(M_STATE_QATTACK)->toggleTraceFx(M_TRUE);
270  }
271  else
272  getObject()->getModel(M_STATE_ATTACK)->frameIndex(0);
273  }
274 
275  if( _ttAttack.isElapsed() )
276  {
277  attackStop();
278  }
279 }
280 
281 unsigned laFightingCreature::_next_state( unsigned nCurrentState )
282 {
283  // Death state
284  //
285  if( (!isAlive()) && (!_ttDeath.isEnabled()) )
286  {
287  _ttDeath.enable(M_TRUE);
288  _ttDeath.reset();
289 
290  setBlendTime(0.2);
291  return M_STATE_DIE;
292  }
293 
294  // Attack state
295  //
296  else if(_bAttack)
297  {
298  setBlendTime(0.15);
299  if(_bAttack_Quick) return M_STATE_QATTACK;
300  else return M_STATE_ATTACK;
301  }
302 
303  /*if( ((getOldState()==M_STATE_ATTACK) || (getOldState()==M_STATE_QATTACK))
304  && (getState()!=M_STATE_ATTACK) && (getState()!=M_STATE_QATTACK) )
305  {
306  setBlendTime(0.2);
307  }*/
308 
309  return laMovingCreature::_next_state( nCurrentState );
310 }
311 
312 
313 // Draw geometry
314 //
315 void laFightingCreature::_draw_positioned_rotated(laRenderer *r)
316 {
317  // Death effect
318  //
319  if(_ttDeath.isEnabled())
320  {
321  r->transPush();
322  _trans_deathfx(r);
323  laStateObject::_draw_positioned_rotated(r);
324  r->transPop();
325  }
326  else laMovingCreature::_draw_positioned_rotated(r);
327 }
328 
329 // Apply death Fx rotation and offset, and style changes
330 //
331 void laFightingCreature::_trans_deathfx(laRenderer *r)
332 {
333  _color[3]= _outline.color[3]= _ttDeath.reminder() * 250;
334  r->styleSet(_color);
335  r->modeOutline(_outline);
336 
337  if(_ptPivot.bOnGround) r->transTranslate(laPoint3(0, -1*_ttDeath.progress()*M_DEATHFX_OFFSET, 0));
338  r->transRotate(_ttDeath.progress()*M_DEATHFX_ROTATION, laPoint3(0,1,0));
339 }
340 
341 // Draw specific FX
342 //
343 void laFightingCreature::_drawFx_positioned(laRenderer *r)
344 {
345  _fxBlood.draw(r);
346 
347  if(_ttDeath.isEnabled())
348  _ptPivot.dShadowY = _ptPivot.y() + _ttDeath.progress()*M_DEATHFX_OFFSET;
349 
350  if(_ptPivot.y() < M_UNIT * (M_SEGH - 1))
351  laMovingCreature::_drawFx_positioned(r);
352 }
353 
354 /*void laFightingCreature::heal(unsigned hp)
355 {
356  if ( ((rpgSheet_Fighter*)_pSheet)->heal(hp) )
357  {
358  fxMessages.add(1, laColor(255,0,0), "+%d", (int)hp);
359  }
360 }*/
Moving Creature.
#define M_UNIT
Unit of 1 meter.
laColor color
Outline color.
Definition: laRenderer.h:71
Animated Text Effect.
Definition: fxMessages.h:64
#define M_DIR_FX
Visual effects directory.
Abstract RPG Properties Sheet.
Definition: rpgSheet.h:107
virtual void modeOutline(const laOutline &outline)
Set outline parameters.
Definition: laRenderer.h:174
Virtual interface for the Engine graphics renderer.
Definition: laRenderer.h:98
Attack RPG Properties.
Definition: rpgAttack.h:55
File Parser.
Definition: laFileParser.h:41