JNR
laCollectable.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: laCollectable.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 laCollectable::laCollectable(void)
39 {
40  _nHP = _nXP = 0;
41  _bWeapon = /*_bPotion =*/ M_FALSE;
42  _pPotion = NULL;
43 
44  pItem = NULL;
45 
46  _bTaken = M_FALSE;
47 
48  _dRotAngle = 0;
49  _nWaveIndex = rand()%M_SEGW;
50 
51  _ptPivot.bSimulateCollision = _ptPivot.bSimulateGravitation = M_FALSE;
52 }
53 
54 laCollectable::~laCollectable(void)
55 {
56  if(pItem) delete pItem;
57  if(_pPotion && _bOwnPotionObject) delete _pPotion;
58 }
59 
60 void laCollectable::respawn()
61 {
62  laObject::respawn();
63 
64  _bTaken = M_FALSE;
65  _dRotAngle = 0;
66 }
67 
68 // Load collectable from the TS file
69 //
70 void laCollectable::load(class laFileParser *fp)
71 {
72  ERRORLEVEL_BEGIN;
73  laObject::load(fp);
74 
75  // Load Fx to be palyed on collect
76  _load_collect_fx();
77 
78  // Pivot tweak
79  _ptPivot.size = laPoint3(M_UNIT/2, M_UNIT/2);
80 
81  // HP value
82  //
83  try{
84  _nHP = getObject()->getInt("value-hp");
85  }
86  catch(laError_PropertyNotDefined&){ _nHP = 0; }
87 
88  // XP value
89  //
90  try{
91  _nXP = getObject()->getInt("value-xp");
92  }
93  catch(laError_PropertyNotDefined&){ _nXP=0; }
94 
95  // Weapon value
96  //
97  try{
98  laElement* pe = (laElement*) (getObject()->getChild("weapon"));
99  _bWeapon = M_TRUE;
100 
101  pItem = new rpgWeapon();
102  pItem->load( pe );
103  }
104  catch(laError_PropertyNotDefined&){ _bWeapon = M_FALSE; }
105 
106  // Potion value
107  //
108  try{
109  laElement* pe = (laElement*) (getObject()->getChild("potion"));
110 
111  _pPotion = new rpgPotion();
112  _bOwnPotionObject = M_TRUE;
113 
114  _pPotion->load( pe );
115 
116  //Initialise a effect duration trigger
117  _ttDuration.parameters( _pPotion->dDuration );
118  _ttDuration.enable(M_FALSE);
119 
120  } catch(laError_PropertyNotDefined&){ _pPotion = NULL; }
121 
122  _fxCollect.position( laPoint3(0, -_ptPivot.size.y()/2) );
123 
124  ERRORLEVEL_END;
125 }
126 
127 // Create dynamically
128 //
129 void laCollectable::create(laPoint3 pos, rpgPotion* pPot)
130 {
131  ERRORLEVEL_BEGIN;
132  laObject::create(pos);
133 
134  // Load Fx to be palyed on collect
135  _load_collect_fx();
136 
137  // Pivot tweak
138  _ptPivot.y( _ptPivot.y() - M_UNIT/2.1);
139 
140  _ptPivot.size.x( M_ABS( getObject()->getModel(0)->boundaryMax().x() - getObject()->getModel(0)->boundaryMin().x())*0.8 );
141  _ptPivot.size.y( M_ABS( getObject()->getModel(0)->boundaryMax().y() - getObject()->getModel(0)->boundaryMin().y())*0.8 );
142 
143  _color = getObject()->getColor("color");
144 
145  // Potion value
146  //
147  if(pPot)
148  {
149  _pPotion = pPot;
150  _bOwnPotionObject = M_FALSE;
151 
152  //Initialise a effect duration trigger
153  _ttDuration.parameters( _pPotion->dDuration );
154  _ttDuration.enable(M_FALSE);
155  }
156 
157  _fxCollect.position( laPoint3(0, -_ptPivot.size.y()/2) );
158 
159  ERRORLEVEL_END;
160 }
161 
162 void laCollectable::_load_collect_fx()
163 {
164  // Load Fx to be palyed on collect
165  //
166  laFileParser fxp;
167  char strFilePath[128]=M_DIR_FX;
168  fxParticleSystem_params param;
169 
170  strcat(strFilePath, "creature_collect.fx");
171  fxp.fileOpen(strFilePath);
172  fxp.readObj(&param, M_FALSE);
173  fxp.fileClose();
174 
175  _fxCollect.create(param);
176  _fxCollect.enable(M_TRUE);
177  _fxCollect.enableGeneration(M_TRUE);
178  _fxCollect.ctlRewind();
179 
180  _fxCollect.parameters.p_rgb = getObject()->getColor("color");
181  if( getObject()->getFxCnt()>=1 )
182  {
183  getObject()->getFx(0)->parameters.p_rgb[0]= _fxCollect.parameters.p_rgb.r();
184  getObject()->getFx(0)->parameters.p_rgb[1]= _fxCollect.parameters.p_rgb.g();
185  getObject()->getFx(0)->parameters.p_rgb[2]= _fxCollect.parameters.p_rgb.b();
186  }
187 }
188 
189 // Actions to be performed when the item is collected
190 //
191 M_BOOL laCollectable::_collect_actions()
192 {
193  laPlayer *pPlayer = getLevelObject()->getPlayer();
194  M_BOOL bAnimateResponsiblity = M_FALSE; // same type of ptotion is collected N times; only 1 obj animates
195 
196  _bTaken = M_TRUE;
197 
198  // HP value
199  if(_nHP)
200  pPlayer->heal( _nHP );
201 
202  // XP value
203  if(_nXP)
204  pPlayer->collect( _nXP );
205 
206  // Weapon value
207  if(_bWeapon)
208  pPlayer->collect( pItem );
209 
210  // Potion value
211  //
212  if(_pPotion)
213  {
214  bAnimateResponsiblity = pPlayer->collect( _pPotion );
215  _pPotion->pAnimatorObj = this;
216 
217  _ttDuration.enable();
218  _ttDuration.reset();
219  }
220 
221  // Play collect Fx
222  _fxCollect.reset();
223  return bAnimateResponsiblity;
224 }
225 
226 // Animate collectable item
227 //
228 void laCollectable::animate(laTimer &t)
229 {
230  ERRORLEVEL_BEGIN;
231 
232  // Default animate()
233  //
234  laObject::animate(t);
235  _fxCollect.animate(t);
236 
237  // Potion effect
238  //
239  if(_pPotion /*&& _bAnimateResponsiblity*/) _potion_mechanic();
240 
241  // Collect mechanic
242  //
243  if( !_bTaken ) {
244  _collect_mechanic();
245 
246  // Rotate
247  _ptPivot.angleY += 100*t.delta();
248 
249  // Wiggle a bit
250  ASSERT(getSegmentObject(), "Nil segment object");
251  _ptPivot.y( _ptPivot.y() + getSegmentObject()->getWave(_nWaveIndex) * M_UNIT * 0.1 * t.delta() );
252  }
253 
254  ERRORLEVEL_END;
255 }
256 
257 // Collect mechanic
258 //
259 void laCollectable::_collect_mechanic()
260 {
261  laPlayer *pPlayer = (laPlayer*)getLevelObject()->getPlayer();
262 
263  laLine2 ln(pPlayer->getPosition(), _ptPivot);
264  _dPlayerDistance = ln.lenght();
265 
266  if( pPlayer->boundingRect().intersecting(boundingRect()) )
267  {
268  this->_collect_actions();
269  }
270 }
271 
272 // Potion effect mechanic
273 //
274 void laCollectable::_potion_mechanic()
275 {
276  laTimer *pt = laSystemIntegrator::getEnvironment()->getTimer();
277  laPlayer *pPlayer = (laPlayer*)getLevelObject()->getPlayer();
278  rpgSheet_PlayableChar* ps = ( (rpgSheet_PlayableChar*)(pPlayer->getSheet()) );
279  unsigned n = ps->properties()->potions.findByName( _pPotion->strName );
280 
281  if( n < ps->properties()->potions.size() )
282  {
283  laObject *pAnimator = ((rpgPotion*)(ps->properties()->potions[n]))->pAnimatorObj;
284  if( pAnimator != this )
285  return; // somebody else takes care for this potion;
286  }
287  //else return;
288 
289  _ttDuration.animate(*pt);
290 
291  // Reset the potion effect?
292  //
293  if( _pPotion->bResetTime ) resetPotion();
294  else _pPotion->dDurationReminder = _ttDuration.reminder() * _pPotion->dDuration;
295 
296  // don't mess up with expired potions
297  // important to ignore them in case there are several laCollectables
298  // of the same potion type
299  if(!_ttDuration.isEnabled() ) return;
300 
301  // Time to remove potion effect?
302  //
303  if( _ttDuration.isElapsed())
304  {
305  rpgSheet_PlayableChar* ps = ( (rpgSheet_PlayableChar*)(pPlayer->getSheet()) );
306  unsigned nIndex = ps->properties()->potions.findByName( _pPotion->strName );
307 
308  if( nIndex < ps->properties()->potions.size())
309  ps->properties()->potions.remove( nIndex );
310 
311  _ttDuration.enable(M_FALSE);
312  }
313  else if( _pPotion->dDurationReminder < 1 )
314  {
315  _disable_potion_icon();
316 
317  // Trigger removal animation
318  //
319  /*rpgSheet_PlayableChar* ps = ( (rpgSheet_PlayableChar*)(pPlayer->getSheet()) );
320  unsigned n = ps->properties()->potions.findByName( _pPotion->strName );
321 
322  if( n < ps->properties()->potions.size() )
323  {
324  uiIcon3D* pIcon =pPlayer->getPotionsGUI()->getIcon(n);
325  if( (!pIcon->isDiscarding()) ) pIcon->discardingIcon();
326  }*/
327  }
328 }
329 
330 void laCollectable::resetPotion()
331 {
332  ERRORLEVEL_BEGIN;
333 
334  _ttDuration.enable();
335  _ttDuration.reset();
336  _pPotion->reset();
337 
338  //MSG("reset");
339 
340  // Disable any removal animation, possibly present
341  //
342  /*rpgSheet_PlayableChar* ps = ( (rpgSheet_PlayableChar*)(pPlayer->getSheet()) );
343  unsigned n = ps->properties()->potions.findByName( _pPotion->strName );
344 
345  //MSG("%d %d", n, ps->properties()->potions.size());
346  if( n < ps->properties()->potions.size() )
347  {
348  uiIcon3D* pIcon =pPlayer->getPotionsGUI()->getIcon(n);
349  pIcon->discardingIcon(M_FALSE);
350  }*/
351 
352  if( !_reset_potion_icon() )
353  {
354  // Expired; collect anew
355  _collect_actions();
356  //pPlayer->collect( _pPotion );
357  _reset_potion_icon();
358  //MSG("drink");
359 
360  //ps->properties()->potions.add( _pPotion );
361 
362  /*rpgSheet_PlayableChar* ps = ( (rpgSheet_PlayableChar*)(pPlayer->getSheet()) );
363  unsigned n = ps->properties()->potions.findByName( _pPotion->strName );
364 
365  uiIcon3D* pIcon =pPlayer->getPotionsGUI()->getIcon(n);
366  pIcon->discardingIcon(M_FALSE);*/
367  }
368 
369  ERRORLEVEL_END;
370 }
371 
372 M_BOOL laCollectable::_reset_potion_icon()
373 {
374  ASSERT(_pPotion, "Nil potion");
375  laPlayer *pPlayer = (laPlayer*)getLevelObject()->getPlayer();
376  rpgSheet_PlayableChar* ps = ( (rpgSheet_PlayableChar*)(pPlayer->getSheet()) );
377  unsigned n = ps->properties()->potions.findByName( _pPotion->strName );
378 
379  if( n < ps->properties()->potions.size() )
380  {
381  uiIcon3D* pIcon = pPlayer->getPotionsGUI()->getIcon(n);
382  pIcon->discardingIcon(M_FALSE);
383 
384  return M_TRUE;
385  }
386 
387  return M_FALSE;
388 }
389 
390 void laCollectable::_disable_potion_icon()
391 {
392  ASSERT(_pPotion, "Nil potion");
393  laPlayer *pPlayer = (laPlayer*)getLevelObject()->getPlayer();
394  rpgSheet_PlayableChar* ps = ( (rpgSheet_PlayableChar*)(pPlayer->getSheet()) );
395  unsigned n = ps->properties()->potions.findByName( _pPotion->strName );
396 
397  if( n < ps->properties()->potions.size() )
398  {
399  uiIcon3D* pIcon =pPlayer->getPotionsGUI()->getIcon(n);
400  if( !pIcon->isDiscarding() ) pIcon->discardingIcon();
401  }
402 }
403 
404 void laCollectable::drawGeometry(laRenderer *r, laPoint3 ptBasePos)
405 {
406  ERRORLEVEL_BEGIN;
407 
408  // Draw the prop
409  //
410  if(!_bTaken)
411  laObject::drawGeometry(r, ptBasePos);
412  else
413  {
414  // Draw only the nested objects
415  _nested_draw(r, ptBasePos);
416  }
417 
418  ERRORLEVEL_END;
419 }
420 
421 void laCollectable::_drawFx_positioned(laRenderer *r) {
422  r->transPush();
423  r->transTranslate( laPoint3(0,0, +M_UNIT/2.0) );
424  _fxCollect.draw(r);
425  r->transPop();
426 
427  if(!_bTaken) laObject::_drawFx_positioned(r);
428 }
laTimer * getTimer()
Get inegrated timer.
Definition: laEnvironment.h:85
Playable Character.
Definition: laPlayer.h:46
#define M_UNIT
Unit of 1 meter.
Base Class for Tileset Elements.
Definition: laElement.h:48
2D line segment
Definition: laLine2.h:40
#define M_DIR_FX
Visual effects directory.
Potion RPG Properties.
Definition: rpgPotion.h:44
Player RPG Properties.
#define M_ABS(a)
Return abs(a)
Virtual interface for the Engine graphics renderer.
Definition: laRenderer.h:98
GUI icon object that can siplay 3D models as icons.
Definition: uiIcon3D.h:52
Base Class for Level Objects.
Definition: laObject.h:43
File Parser.
Definition: laFileParser.h:41