JNR
aiMobState.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: aiMobState.cpp
32 //
33 // Basic monster AI
34 //
35 // Copyright (C) 2007-2013 Atanas Laskov, <latanas@gmail.com>
36 //
37 #include "stdafx.h"
38 #include "ai.h"
39 
40 aiMobState::aiMobState()
41 {
42  _pTouchSound = NULL;
43  _pProximitySound = NULL;
44 
45  _bIsSelected = M_FALSE;
46 }
47 
48 void aiMobState::load(laFileParser *fp)
49 {
50  // Load sounds
51  //
52  _pTouchSound = laSystemIntegrator::getSound()->soundCreate("sound\\mon_die(rattlesnake).mp3");
53  _pProximitySound = laSystemIntegrator::getSound()->soundCreate("sound\\mon_proximity(rattlesnake).mp3");
54 }
55 
56 // Call the specific percept handlers
57 //
58 void aiMobState::perceive(unsigned state, M_BOOL global, unsigned id, aiPerceptData data)
59 {
60  //No special handling for global percepts
61  if(global) return;
62 
63  //No handling for dead monsters
64  if( !( ((laFightingCreature*)self())->isAlive() ) ) return;
65 
66  //Recognize local percepts
67  switch(id)
68  {
69  case P__PLAYER_DISTANCE:
70  if( (state==PERCEPT_SET) || (state==PERCEPT_HOLD) )
71  {
72  this->perceive_Distance( data.dData );
73  _dPlayerDistance = data.dData;
74  }
75  break;
76 
77  case P__PLAYER_IN_TERRITORY:
78  this->perceive_InTerritory(state);
79  break;
80 
81  case P__PLAYER_IN_RANGE:
82  this->perceive_InRange(state);
83  break;
84 
85  case P__PLAYER_TOUCHED:
86  this->perceive_Touched(state);
87  break;
88 
89  case P__PLAYER_ATTACKS:
90  this->perceive_UnderAttack(state);
91  break;
92  }
93 }
94 
95 // The player touched me
96 //
97 void aiMobState::perceive_Touched(unsigned state)
98 {
99  laMonster* pMonster = (laMonster*) self();
100  laPlayer* pPlayer = (laPlayer*) player();
101 
102  if(! pMonster->isAlive() ) return;
103 
104  // Hit him
105  //
106  // NOTE: it's improtant to reflect() first and hit() second;
107  // The hit() method enables immunity and when imunity is enabled reflect() doesn't do anything.
108  //
109  if(state == PERCEPT_SET)
110  {
111  pPlayer->reflect( pMonster->boundingRect() );
112  pMonster->attack(M_MATTACK_TOUCH, pPlayer);
113 
114  //Play tocuh sound
115  if(_pTouchSound) _pTouchSound->play();
116  }
117 }
118 
119 // The player is attacking
120 //
121 void aiMobState::perceive_UnderAttack(unsigned state)
122 {
123  laMonster* pMonster = (laMonster*) self();
124  laPlayer* pPlayer = (laPlayer*) player();
125 
126  if( ! pMonster->isAlive() ) return;
127 
128  if(state == PERCEPT_SET)
129  {
130  // Hit me
131  //
132  if( pMonster->isAlive() )
133  {
134  if(pPlayer->attackIsQuick())
135  pPlayer->attack(M_PLAYER_ATTACK_QUICK, pMonster);
136  else
137  pPlayer->attack(M_PLAYER_ATTACK_BASIC, pMonster);
138  }
139 
140  // Am I dead?
141  //
142  if( ! pMonster->isAlive() )
143  {
144  laElement* ptso = pMonster->getObject();
145  laPoint3 bmin = ptso->getModel(M_STATE_DIE)->boundaryMin();
146  laPoint3 bmax = ptso->getModel(M_STATE_DIE)->boundaryMax();
147  double deadH = bmax.y() - bmin.y();
148 
149  _spawn_crystal( pMonster->getPosition() + laPoint3(0,-deadH/2,0) );
150  }
151  }
152 }
153 
154 void aiMobState::_spawn_crystal( laPoint3 pos )
155 {
156  laMonster* pMonster = (laMonster*) self();
157 
158  laLevel* pLevel = pMonster->getLevelObject();
159  laTileset* pTS = pMonster->getTS();
160  laElement* pTSObject = pMonster->getObject();
161 
162  // Spawn a crystal
163  //
164  laCollectable *pBraveryCrystal = new laCollectable();
165  unsigned nElementIndex = pTS->getElementIndex("loot crystal");
166 
167  pBraveryCrystal->setObject(nElementIndex, (laElement*)pTS->getElement(nElementIndex));
168  pBraveryCrystal->setTS(pTS);
169  pBraveryCrystal->setLevel(pLevel);
170  pBraveryCrystal->create( pos );
171 
172  pMonster->nestedAdd( pBraveryCrystal );
173  //pMonster->setNestedObject(pBraveryCrystal);
174 }
175 
176 void aiMobState::_select_creature(M_BOOL on)
177 {
178  laMonster* pMonster = (laMonster*) self();
179 
180  if(! pMonster->isAlive() ) return;
181 
182  if(_bIsSelected != on)
183  {
184  _bIsSelected = on;
185 
186  if( on )
187  {
188  pMonster->setOutline( laOutline(M_TRUE, laColor(255,200,200), 1.5) );
189  if(_pProximitySound) _pProximitySound->play();
190  }
191  else
192  pMonster->setOutline( laOutline(M_TRUE, laColor(), 1) );
193  }
194 }
195 
196 M_BOOL aiMobState::_within_left_range()
197 {
198  laMonster* pMonster = (laMonster*) self();
199 
200  if( (pMonster->getOriginalPos().x() - pMonster->getPosition().x() ) > pMonster->getLeftRange() )
201  return M_FALSE;
202  return M_TRUE;
203 }
204 
205 M_BOOL aiMobState::_within_right_range()
206 {
207  laMonster* pMonster = (laMonster*) self();
208 
209  if( (pMonster->getPosition().x() - pMonster->getOriginalPos().x() ) > pMonster->getRightRange() )
210  return M_FALSE;
211  return M_TRUE;
212 }
Playable Character.
Definition: laPlayer.h:46
Base Class for Tileset Elements.
Definition: laElement.h:48
: JR Level
Definition: laLevel.h:48
Object outline properties.
Definition: laRenderer.h:66
Adds capabilities and percepts specific to monster creatures.
Definition: laMonster.h:45
Tileset Class.
Definition: laTileset.h:46
File Parser.
Definition: laFileParser.h:41
Collectable Level Object.
Definition: laCollectable.h:43