- Timestamp:
- Apr 18, 2009, 6:14:52 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/weapons/src/orxonox/objects/weaponSystem/Munition.cc
r2912 r2918 20 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 21 * 22 * Author :22 * Authors: 23 23 * Martin Polak 24 * Fabian 'x3n' Landau 24 25 * Co-authors: 25 26 * ... … … 40 41 RegisterObject(Munition); 41 42 43 this->maxMunitionPerMagazine_ = 10; 44 this->maxMagazines_ = 10; 45 this->magazines_ = 10; 46 47 this->bUseSeparateMagazines_ = false; 48 this->bStackMunition_ = true; 49 this->bAllowMunitionRefilling_ = true; 50 this->bAllowMultiMunitionRemovementUnderflow_ = true; 51 52 this->reloadTime_ = 0; 53 42 54 COUT(0) << "+Munition" << std::endl; 43 55 } … … 45 57 Munition::~Munition() 46 58 { 59 for (std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.begin(); it != this->currentMagazines_.end(); ++it) 60 delete it->second; 61 47 62 COUT(0) << "~Munition" << std::endl; 48 63 } 49 64 50 unsigned int Munition::bullets() 51 { 52 if (this->bullets_ > 0) 53 return bullets_; 65 Munition::Magazine* Munition::getMagazine(WeaponMode* user) const 66 { 67 if (this->bUseSeparateMagazines_) 68 { 69 // For separated magazines we definitively need a given user 70 if (!user) 71 return 0; 72 73 // Use the map to get the magazine assigned to the given user 74 std::map<WeaponMode*, Magazine*>::const_iterator it = this->currentMagazines_.find(user); 75 if (it != this->currentMagazines_.end()) 76 return it->second; 77 } 78 else 79 { 80 // We don't use separate magazines for each user, so just take the first magazine 81 if (this->currentMagazines_.size() > 0) 82 return this->currentMagazines_.begin()->second; 83 } 84 85 return 0; 86 } 87 88 unsigned int Munition::getNumMunition(WeaponMode* user) const 89 { 90 Magazine* magazine = this->getMagazine(user); 91 if (magazine) 92 { 93 if (this->bStackMunition_) 94 // With stacked munition every magazine contributes to the total amount 95 return this->maxMunitionPerMagazine_ * this->magazines_ + magazine->munition_; 96 else 97 // Wihtout stacked munition we just consider the current magazine 98 return magazine->munition_; 99 } 100 return 0; 101 } 102 103 unsigned int Munition::getNumMunitionInCurrentMagazine(WeaponMode* user) const 104 { 105 // In contrast to getNumMunition() we really just consider the current magazine, even if we're stacking munition 106 Magazine* magazine = this->getMagazine(user); 107 if (magazine) 108 return magazine->munition_; 54 109 else 55 110 return 0; 56 111 } 57 112 58 unsigned int Munition::magazines() 59 { 60 if (this->magazines_ > 0) 61 return magazines_; 62 else 63 return 0; 64 } 65 66 void Munition::setMaxBullets(unsigned int amount) 67 { this->maxBullets_ = amount; } 68 69 void Munition::setMaxMagazines(unsigned int amount) 70 { this->maxMagazines_ = amount; } 71 72 void Munition::removeBullets(unsigned int amount) 73 { 74 if ( this->bullets_ != 0 ) 75 this->bullets_ = this->bullets_ - amount; 76 } 77 78 void Munition::removeMagazines(unsigned int amount) 79 { 80 if ( this->magazines_ != 0 ) 81 this->magazines_ = this->magazines_ - amount; 82 } 83 84 void Munition::addBullets(unsigned int amount) 85 { 86 if ( this->bullets_ == this->maxBullets_ ) 87 { 88 //cannot add bullets to actual magazine 89 } 90 else 91 this->bullets_ = this->bullets_ + amount; 92 } 93 94 void Munition::addMagazines(unsigned int amount) 95 { 96 if ( this->magazines_ == this->maxMagazines_ ) 97 { 98 //no more capacity for another magazine 99 } 100 else 101 this->magazines_ = this->magazines_ + amount; 102 } 103 104 105 void Munition::fillBullets() 106 { 107 this->bullets_ = this->maxBullets_; 108 } 109 110 void Munition::fillMagazines() 111 { 112 this->magazines_ = this->maxMagazines_; 113 unsigned int Munition::getNumMagazines() const 114 { 115 if (this->bStackMunition_) 116 { 117 // If we stack munition and the current magazine is still full, it counts too 118 Magazine* magazine = this->getMagazine(0); 119 if (magazine && magazine->munition_ == this->maxMunitionPerMagazine_) 120 return this->magazines_ + 1; 121 } 122 123 return this->magazines_; 124 } 125 126 unsigned int Munition::getMaxMunition() const 127 { 128 if (this->bStackMunition_) 129 return this->maxMunitionPerMagazine_ * this->maxMagazines_; 130 else 131 return this->maxMunitionPerMagazine_; 132 } 133 134 bool Munition::canTakeMunition(unsigned int amount, WeaponMode* user) const 135 { 136 Magazine* magazine = this->getMagazine(user); 137 if (magazine && magazine->bLoaded_) 138 { 139 unsigned int munition = magazine->munition_; 140 141 // If we stack munition, we con't care about the current magazine - we just need enough munition in total 142 if (this->bStackMunition_) 143 munition += this->maxMunitionPerMagazine_ * this->magazines_; 144 145 if (munition == 0) 146 // Absolutely no munition - no chance to take munition 147 return false; 148 else if (this->bAllowMultiMunitionRemovementUnderflow_) 149 // We're not empty AND we allow underflow, so this will always work 150 return true; 151 else 152 // We don't allow underflow, so we have to check the amount 153 return (munition >= amount); 154 } 155 return false; 156 } 157 158 bool Munition::takeMunition(unsigned int amount, WeaponMode* user) 159 { 160 if (!this->canTakeMunition(amount, user)) 161 return false; 162 163 Magazine* magazine = this->getMagazine(user); 164 if (magazine && magazine->bLoaded_) 165 { 166 if (magazine->munition_ >= amount) 167 { 168 // Enough munition 169 magazine->munition_ -= amount; 170 return true; 171 } 172 else 173 { 174 // Not enough munition 175 if (this->bStackMunition_) 176 { 177 // We stack munition, so just take what we can and then load the next magazine 178 amount -= magazine->munition_; 179 magazine->munition_ = 0; 180 181 if (this->reload(0)) 182 // Successfully reloaded, continue recursively 183 return this->takeMunition(amount, 0); 184 else 185 // We don't have more magazines, so let's just hope we allow underflow 186 return this->bAllowMultiMunitionRemovementUnderflow_; 187 } 188 else 189 { 190 // We don't stack, so we can only take munition if this is allowed 191 if (magazine->munition_ > 0 && this->bAllowMultiMunitionRemovementUnderflow_) 192 { 193 magazine->munition_ -= 0; 194 return true; 195 } 196 } 197 } 198 } 199 return false; 200 } 201 202 bool Munition::canReload() const 203 { 204 // As long as we have enough magazines (and don't stack munition) we can reload 205 return (this->magazines_ > 0 && !this->bStackMunition_); 206 } 207 208 bool Munition::needReload(WeaponMode* user) const 209 { 210 Magazine* magazine = this->getMagazine(user); 211 if (magazine) 212 { 213 if (this->bStackMunition_) 214 // With stacked munition, we never have to reload 215 return false; 216 else 217 // We need to reload if an already loaded magazine is empty 218 return (magazine->bLoaded_ && magazine->munition_ == 0); 219 } 220 else 221 // No magazine - we definitively need to reload 222 return true; 223 } 224 225 bool Munition::reload(WeaponMode* user, bool bUseReloadTime) 226 { 227 // Don't reload if we're already reloading 228 Magazine* magazine = this->getMagazine(user); 229 if (magazine && !magazine->bLoaded_) 230 return false; 231 232 // Check if we actually can reload 233 if (this->magazines_ == 0) 234 return false; 235 236 // If we use separate magazines for each user, we definitively need a user given 237 if (this->bUseSeparateMagazines_ && !user) 238 return false; 239 240 // If we don't use separate magazines, set user to 0 241 if (!this->bUseSeparateMagazines_) 242 user = 0; 243 244 // Remove the current magazine for the given user 245 std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.find(user); 246 if (it != this->currentMagazines_.end()) 247 { 248 delete it->second; 249 this->currentMagazines_.erase(it); 250 } 251 252 // Load a new magazine 253 this->currentMagazines_[user] = new Magazine(this, bUseReloadTime); 254 this->magazines_--; 255 256 return true; 257 } 258 259 bool Munition::canAddMunition(unsigned int amount) const 260 { 261 if (!this->bAllowMunitionRefilling_) 262 return false; 263 264 if (this->bStackMunition_) 265 { 266 // If we stack munition, we can always add munition until we reach the limit 267 return (this->getNumMunition(0) < this->getMaxMunition()); 268 } 269 else 270 { 271 // Return true if any of the current magazines is not full (loading counts as full although it returns 0 munition) 272 for (std::map<WeaponMode*, Magazine*>::const_iterator it = this->currentMagazines_.begin(); it != this->currentMagazines_.end(); ++it) 273 if (it->second->munition_ < this->maxMunitionPerMagazine_ && it->second->bLoaded_) 274 return true; 275 } 276 277 return false; 278 } 279 280 bool Munition::addMunition(unsigned int amount) 281 { 282 if (!this->canAddMunition(amount)) 283 return false; 284 285 if (this->bStackMunition_) 286 { 287 // Stacking munition means, if a magazine gets full, the munition adds to a new magazine 288 Magazine* magazine = this->getMagazine(0); 289 if (magazine) 290 { 291 // Add the whole amount 292 magazine->munition_ += amount; 293 294 // Add new magazines if the current magazine is overfull 295 while (magazine->munition_ > this->maxMunitionPerMagazine_) 296 { 297 magazine->munition_ -= this->maxMunitionPerMagazine_; 298 this->magazines_++; 299 } 300 301 // If we reached the limit, reduze both magazines and munition to the maximum 302 if (this->magazines_ >= this->maxMagazines_) 303 { 304 this->magazines_ = this->maxMagazines_ - 1; 305 magazine->munition_ = this->maxMunitionPerMagazine_; 306 } 307 308 return true; 309 } 310 311 // Something went wrong 312 return false; 313 } 314 else 315 { 316 // Share the munition equally to the current magazines 317 while (amount > 0) 318 { 319 bool change = false; 320 for (std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.begin(); it != this->currentMagazines_.end(); ++it) 321 { 322 // Add munition if the magazine isn't full (but only to loaded magazines) 323 if (amount > 0 && it->second->munition_ < this->maxMunitionPerMagazine_ && it->second->bLoaded_) 324 { 325 it->second->munition_++; 326 amount--; 327 change = true; 328 } 329 } 330 331 // If there was no change in a loop, all magazines are full (or locked due to loading) 332 if (!change) 333 break; 334 } 335 336 return true; 337 } 338 } 339 340 bool Munition::canAddMagazines(unsigned int amount) const 341 { 342 if (this->bStackMunition_) 343 // If we stack munition, we can always add new magazines because they contribute directly to the munition 344 return (this->getNumMunition(0) < this->getMaxMunition()); 345 else 346 // If we don't stack munition, we're more limited 347 return ((this->currentMagazines_.size() + this->magazines_) < this->maxMagazines_); 348 } 349 350 bool Munition::addMagazines(unsigned int amount) 351 { 352 if (!this->canAddMagazines(amount)) 353 return false; 354 355 // Calculate how many magazines are needed 356 int needed_magazines = this->maxMagazines_ - this->magazines_ - this->currentMagazines_.size(); 357 358 // If zero or less magazines are needed, we definitively don't need more magazines (unless we stack munition - then a magazine contributes directly to the munition) 359 if (needed_magazines <= 0 && !this->bStackMunition_) 360 return false; 361 362 if (amount <= needed_magazines) 363 { 364 // We need more magazines than we get, so just add them 365 this->magazines_ += amount; 366 } 367 else 368 { 369 // We get more magazines than we need, so just add the needed amount 370 this->magazines_ += needed_magazines; 371 if (this->bStackMunition_) 372 { 373 // We stack munition, so the additional amount contributes directly to the munition of the current magazine 374 Magazine* magazine = this->getMagazine(0); 375 if (magazine) 376 magazine->munition_ = this->maxMunitionPerMagazine_; 377 } 378 } 379 380 return true; 381 } 382 383 bool Munition::canRemoveMagazines(unsigned int amount) const 384 { 385 if (this->bStackMunition_) 386 { 387 if (this->magazines_ >= amount) 388 { 389 // We have enough magazines 390 return true; 391 } 392 else if (this->magazines_ == amount - 1) 393 { 394 // We lack one magazine, check if the current magazine is still full, if yes we're fine 395 Magazine* magazine = this->getMagazine(0); 396 if (magazine && magazine->munition_ == this->maxMunitionPerMagazine_) 397 return true; 398 } 399 else 400 { 401 // We don't have enough magazines 402 return false; 403 } 404 } 405 else 406 { 407 // In case we're not stacking munition, just check the number of magazines 408 return (this->magazines_ >= amount); 409 } 410 } 411 412 bool Munition::removeMagazines(unsigned int amount) 413 { 414 if (!this->canRemoveMagazines(amount)) 415 return false; 416 417 if (this->magazines_ >= amount) 418 { 419 // We have enough magazines, just remove the amount 420 this->magazines_ -= amount; 421 } 422 else if (this->bStackMunition_) 423 { 424 // We don't have enough magazines, but we're stacking munition, so additionally remove the bullets from the current magazine 425 this->magazines_ = 0; 426 Magazine* magazine = this->getMagazine(0); 427 if (magazine) 428 magazine->munition_ = 0; 429 } 430 431 return true; 432 } 433 434 bool Munition::dropMagazine(WeaponMode* user) 435 { 436 // If we use separate magazines, we need a user 437 if (this->bUseSeparateMagazines_ && !user) 438 return false; 439 440 // If we don't use separate magazines, set user to 0 441 if (!this->bUseSeparateMagazines_) 442 user = 0; 443 444 // Remove the current magazine for the given user 445 std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.find(user); 446 if (it != this->currentMagazines_.end()) 447 { 448 delete it->second; 449 this->currentMagazines_.erase(it); 450 return true; 451 } 452 453 return false; 454 } 455 456 457 ///////////////////// 458 // Magazine struct // 459 ///////////////////// 460 Munition::Magazine::Magazine(Munition* munition, bool bUseReloadTime) 461 { 462 this->munition_ = 0; 463 this->bLoaded_ = false; 464 465 if (bUseReloadTime && (munition->reloadTime_ > 0 || munition->bStackMunition_)) 466 { 467 ExecutorMember<Magazine>* executor = createExecutor(createFunctor(&Magazine::loaded)); 468 executor->setDefaultValues(munition); 469 470 this->loadTimer_.setTimer(munition->reloadTime_, false, this, executor); 471 } 472 else 473 this->loaded(munition); 474 } 475 476 void Munition::Magazine::loaded(Munition* munition) 477 { 478 this->bLoaded_ = true; 479 this->munition_ = munition->maxMunitionPerMagazine_; 113 480 } 114 481 }
Note: See TracChangeset
for help on using the changeset viewer.