1 /* 2 * Copyright (C) 2004 Ivo Danihelka (ivo@danihelka.net) 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 #include "Controls.h" 10 11 #include "Unit.h" 12 #include "PhaseLocker.h" 13 14 #include "KeyStroke.h" 15 #include "MouseStroke.h" 16 17 //----------------------------------------------------------------- 18 /** 19 * Create list of drivers. 20 * @param locker shared locker for anim 21 */ Controls(PhaseLocker * locker)22Controls::Controls(PhaseLocker *locker) 23 : m_units(), m_moves() 24 { 25 m_locker = locker; 26 m_active = m_units.begin(); 27 m_speedup = 0; 28 m_switch = true; 29 m_strokeSymbol = ControlSym::SYM_NONE; 30 } 31 //----------------------------------------------------------------- 32 /** 33 * Delete drivers. 34 */ ~Controls()35Controls::~Controls() 36 { 37 t_units::iterator end = m_units.end(); 38 for (t_units::iterator i = m_units.begin(); i != end; ++i) { 39 delete (*i); 40 } 41 } 42 //----------------------------------------------------------------- 43 /** 44 * Add unit under our control. 45 * @return model index 46 */ 47 void addUnit(Unit * unit)48Controls::addUnit(Unit *unit) 49 { 50 m_units.push_back(unit); 51 //NOTE: insertion invalidates m_active 52 t_units::iterator end = m_units.end(); 53 for (t_units::iterator i = m_units.begin(); i != end; ++i) { 54 if ((*i)->startActive()) { 55 setActive(i); 56 return; 57 } 58 } 59 setActive(m_units.begin()); 60 } 61 //----------------------------------------------------------------- 62 /** 63 * Returns active unit or NULL. 64 */ 65 const Unit * getActive()66Controls::getActive() 67 { 68 Unit *result = NULL; 69 if (m_active != m_units.end()) { 70 result = *m_active; 71 } 72 return result; 73 } 74 //----------------------------------------------------------------- 75 /** 76 * Let drivers to drive. 77 * Only one driver can drive at the same time. 78 * @param input wrapped input 79 * @return true when a fish has moved (switch does not count) 80 */ 81 bool driving(const InputProvider * input)82Controls::driving(const InputProvider *input) 83 { 84 bool moved = false; 85 if (!useSwitch()) { 86 if (!useStroke()) { 87 moved = driveUnit(input); 88 } 89 else { 90 moved = true; 91 } 92 } 93 return moved; 94 } 95 //----------------------------------------------------------------- 96 /** 97 * Returns true when a switch was done. 98 */ 99 bool useSwitch()100Controls::useSwitch() 101 { 102 bool result = false; 103 if (m_active != m_units.end()) { 104 if (!(*m_active)->willMove()) { 105 checkActive(); 106 } 107 108 if (m_switch && m_active != m_units.end()) { 109 m_locker->ensurePhases(3); 110 (*m_active)->activate(); 111 result = true; 112 } 113 } 114 m_switch = false; 115 return result; 116 } 117 //----------------------------------------------------------------- 118 /** 119 * Use gathered stroke. 120 * NOTE: returns true even for bad move (not used) 121 * @return true for used stroke 122 */ 123 bool useStroke()124Controls::useStroke() 125 { 126 bool result = false; 127 if (m_strokeSymbol != ControlSym::SYM_NONE) { 128 makeMove(m_strokeSymbol); 129 m_strokeSymbol = ControlSym::SYM_NONE; 130 result = true; 131 } 132 return result; 133 } 134 //----------------------------------------------------------------- 135 bool driveUnit(const InputProvider * input)136Controls::driveUnit(const InputProvider *input) 137 { 138 char moved = ControlSym::SYM_NONE; 139 if (m_active != m_units.end()) { 140 moved = (*m_active)->driveBorrowed(input, m_arrows); 141 } 142 143 if (ControlSym::SYM_NONE == moved) { 144 t_units::iterator end = m_units.end(); 145 for (t_units::iterator i = m_units.begin(); i != end; ++i) { 146 moved = (*i)->drive(input); 147 if (moved != ControlSym::SYM_NONE) { 148 setActive(i); 149 break; 150 } 151 } 152 } 153 154 if (moved != ControlSym::SYM_NONE) { 155 m_moves.append(1, moved); 156 } 157 return (moved != ControlSym::SYM_NONE); 158 } 159 //----------------------------------------------------------------- 160 void lockPhases()161Controls::lockPhases() 162 { 163 if (m_active != m_units.end() && (*m_active)->isMoving()) { 164 if ((*m_active)->isPushing()) { 165 m_speedup = 0; 166 } 167 else if (!(*m_active)->isTurning()) { 168 m_speedup++; 169 } 170 171 m_locker->ensurePhases(getNeededPhases(m_speedup)); 172 } 173 else { 174 m_speedup = 0; 175 } 176 } 177 //----------------------------------------------------------------- 178 int getNeededPhases(int speedup) const179Controls::getNeededPhases(int speedup) const 180 { 181 static const int SPEED_WARP1 = 6; 182 static const int SPEED_WARP2 = 10; 183 184 int phases = 3; 185 if (m_active != m_units.end()) { 186 if ((*m_active)->isTurning()) { 187 phases = (*m_active)->countAnimPhases("turn"); 188 } 189 else if (speedup > SPEED_WARP2) { 190 phases = (*m_active)->countAnimPhases("swam") / 6; 191 } 192 else if (speedup > SPEED_WARP1) { 193 phases = (*m_active)->countAnimPhases("swam") / 3; 194 } 195 else { 196 phases = (*m_active)->countAnimPhases("swam") / 2; 197 } 198 } 199 return phases; 200 } 201 //----------------------------------------------------------------- 202 /** 203 * Check whether active unit can still drive, 204 * otherwise make switch. 205 */ 206 void checkActive()207Controls::checkActive() 208 { 209 if (m_active == m_units.end() || !(*m_active)->canDrive()) { 210 switchActive(); 211 } 212 } 213 //----------------------------------------------------------------- 214 /** 215 * Switch active unit. 216 * Activate next driveable unit. 217 */ 218 void switchActive()219Controls::switchActive() 220 { 221 if (!m_units.empty()) { 222 t_units::iterator start = m_active; 223 224 do { 225 if (m_active == m_units.end() || m_active + 1 == m_units.end()) { 226 m_active = m_units.begin(); 227 } 228 else { 229 ++m_active; 230 } 231 } while (m_active != start && !(*m_active)->canDrive()); 232 233 if (start != m_active) { 234 m_speedup = 0; 235 m_switch = true; 236 } 237 } 238 } 239 //----------------------------------------------------------------- 240 /** 241 * Obtain first control symbol from keyboard events. 242 */ 243 void controlEvent(const KeyStroke & stroke)244Controls::controlEvent(const KeyStroke &stroke) 245 { 246 SDLKey key = stroke.getKey(); 247 248 if (m_strokeSymbol == ControlSym::SYM_NONE) { 249 if (m_active != m_units.end()) { 250 m_strokeSymbol = (*m_active)->mySymbolBorrowed(key, m_arrows); 251 } 252 253 if (m_strokeSymbol == ControlSym::SYM_NONE) { 254 t_units::iterator end = m_units.end(); 255 for (t_units::iterator i = m_units.begin(); i != end; ++i) { 256 m_strokeSymbol = (*i)->mySymbol(key); 257 if (m_strokeSymbol != ControlSym::SYM_NONE) { 258 return; 259 } 260 } 261 } 262 } 263 } 264 //----------------------------------------------------------------- 265 /** 266 * Activate fish under cursor. 267 * @param occupant model to activate 268 * @return true when fish was selected 269 */ 270 bool activateSelected(const Cube * occupant)271Controls::activateSelected(const Cube *occupant) 272 { 273 t_units::iterator end = m_units.end(); 274 for (t_units::iterator i = m_units.begin(); i != end; ++i) { 275 if ((*i)->equalsModel(occupant)) { 276 m_active = i; 277 m_switch = true; 278 return true; 279 } 280 } 281 return false; 282 } 283 //----------------------------------------------------------------- 284 void setMoves(const std::string & moves)285Controls::setMoves(const std::string &moves) 286 { 287 m_moves = moves; 288 if (!m_moves.empty()) { 289 activateDriven(m_moves[m_moves.size() - 1]); 290 } 291 } 292 //----------------------------------------------------------------- 293 /** 294 * Activate fish driven by given symbol. 295 * @param symbol one of fish symbols 296 * @return true when fish was selected 297 */ 298 bool activateDriven(char symbol)299Controls::activateDriven(char symbol) 300 { 301 t_units::iterator end = m_units.end(); 302 for (t_units::iterator i = m_units.begin(); i != end; ++i) { 303 if ((*i)->isDrivenBy(symbol)) { 304 m_active = i; 305 m_switch = true; 306 return true; 307 } 308 } 309 return false; 310 } 311 //----------------------------------------------------------------- 312 /** 313 * Change active unit. 314 * NOTE: change is without switch animation 315 */ 316 void setActive(t_units::iterator active)317Controls::setActive(t_units::iterator active) 318 { 319 if (m_active != active) { 320 m_speedup = 0; 321 m_active = active; 322 } 323 } 324 //----------------------------------------------------------------- 325 /** 326 * Make this move. 327 * @return false for bad move 328 */ 329 bool makeMove(char move)330Controls::makeMove(char move) 331 { 332 t_units::iterator end = m_units.end(); 333 for (t_units::iterator i = m_units.begin(); i != end; ++i) { 334 if ((*i)->driveOrder(move) == move) { 335 setActive(i); 336 m_moves.append(1, move); 337 return true; 338 } 339 } 340 return false; 341 } 342 //----------------------------------------------------------------- 343 /** 344 * Returns true when there is no unit which will be able to move. 345 */ 346 bool cannotMove() const347Controls::cannotMove() const 348 { 349 t_units::const_iterator end = m_units.end(); 350 for (t_units::const_iterator i = m_units.begin(); i != end; ++i) { 351 if ((*i)->willMove()) { 352 return false; 353 } 354 } 355 return true; 356 } 357 //----------------------------------------------------------------- 358 /** 359 * Returns true when active fish is powerful. 360 */ 361 bool isPowerful() const362Controls::isPowerful() const 363 { 364 bool result = false; 365 if (m_active != m_units.end()) { 366 result = (*m_active)->isPowerful(); 367 } 368 return result; 369 } 370 //----------------------------------------------------------------- 371 /** 372 * Returns true when the active fish is doing a dangerous move. 373 */ 374 bool isDangerousMove() const375Controls::isDangerousMove() const 376 { 377 bool result = false; 378 if (m_active != m_units.end()) { 379 result = (*m_active)->isPushing(); 380 } 381 return result; 382 } 383 384 385