1 /************************************************************************ 2 * * 3 * FreeSynd - a remake of the classic Bullfrog game "Syndicate". * 4 * * 5 * Copyright (C) 2005 Stuart Binge <skbinge@gmail.com> * 6 * Copyright (C) 2005 Joost Peters <joostp@users.sourceforge.net> * 7 * Copyright (C) 2006 Trent Waddington <qg@biodome.org> * 8 * Copyright (C) 2006 Tarjei Knapstad <tarjei.knapstad@gmail.com> * 9 * Copyright (C) 2010 Bohdan Stelmakh <chamel@users.sourceforge.net> * 10 * Copyright (C) 2011 Mark <mentor66@users.sourceforge.net> * 11 * * 12 * This program is free software; you can redistribute it and / or * 13 * modify it under the terms of the GNU General Public License as * 14 * published by the Free Software Foundation; either version 2 of the * 15 * License, or (at your option) any later version. * 16 * * 17 * This program is distributed in the hope that it will be useful, * 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 20 * General Public License for more details. * 21 * * 22 * You can view the GNU General Public License, online, at the GNU * 23 * project's web site; see <http://www.gnu.org/licenses/gpl.html>. * 24 * The full text of the license is also included in the file COPYING. * 25 * * 26 ************************************************************************/ 27 28 #ifndef WEAPON_H 29 #define WEAPON_H 30 31 #include <string> 32 #include <vector> 33 #include "mapobject.h" 34 #include "sound/sound.h" 35 #include "utils/configfile.h" 36 #include "utils/timer.h" 37 38 class FlamerShot; 39 class PedInstance; 40 41 /*! 42 * Weapon class. 43 */ 44 class Weapon { 45 public: 46 enum WeaponType { 47 Unknown = 0, 48 Pistol = 1, 49 GaussGun = 2, 50 Shotgun = 3, 51 Uzi = 4, 52 Minigun = 5, 53 Laser = 6, 54 Flamer = 7, 55 LongRange = 8, 56 Scanner = 9, 57 MediKit = 10, 58 TimeBomb = 11, 59 AccessCard = 12, 60 EnergyShield = 13, 61 Persuadatron = 14 62 }; 63 64 typedef enum { 65 Unarmed_Anim, 66 Pistol_Anim, 67 Minigun_Anim, 68 Flamer_Anim, 69 LongRange_Anim, 70 EnergyShield_Anim, 71 Uzi_Anim, 72 Laser_Anim, 73 Gauss_Anim, 74 Shotgun_Anim 75 } WeaponAnimIndex; 76 77 /*! 78 * This structure holds animation ids of impacts for a weapon. 79 */ 80 struct ImpactAnims { 81 //! Animation played when impact is on the ground. 82 SFXObject::SfxTypeEnum groundHit; 83 //! Animation played when impact is on a living object. 84 SFXObject::SfxTypeEnum objectHit; 85 SFXObject::SfxTypeEnum trace_anim; 86 /*! if weapon can do range damage this is used for range definition 87 * with animation.*/ 88 int rd_anim; 89 }; 90 91 Weapon(WeaponType w_type, ConfigFile &conf); 92 getName()93 const char *getName() { return name_.c_str(); } 94 cost()95 int cost() { return cost_; } ammo()96 int ammo() { return ammo_; } range()97 int range() { return range_; } damagePerShot()98 int damagePerShot() { return dmg_per_shot_; } rank()99 int rank() { return rank_; } anim()100 int anim() { return anim_; } weight()101 int weight() {return weight_; } getSound()102 snd::InGameSample getSound() { return sample_; } getSmallIconId()103 int getSmallIconId() { return small_icon_; } getBigIconId()104 int getBigIconId() { return big_icon_; } 105 selector()106 int selector() { 107 return small_icon_ == 28 ? 1618 : small_icon_ - 14 + 1602; 108 } 109 index()110 WeaponAnimIndex index() { return idx_; } getWeaponType()111 WeaponType getWeaponType() { return type_; } dmgType()112 MapObject::DamageType dmgType() { return dmg_type_; } 113 114 bool operator==(Weapon weapon) { return this->type_ == weapon.getWeaponType(); } 115 ammoPerShot()116 int ammoPerShot() { return ammo_per_shot_; } timeForShot()117 int timeForShot() { return time_for_shot_; } timeReload()118 int timeReload() { return time_reload_; } 119 wasSubmittedToSearch()120 bool wasSubmittedToSearch() { return submittedToSearch_; } submitToSearch()121 void submitToSearch() { submittedToSearch_ = true; } resetSubmittedToSearch()122 void resetSubmittedToSearch() { submittedToSearch_ = false; } 123 canShoot()124 bool canShoot() { 125 return (shot_property_ & Weapon::spe_CanShoot) != 0; 126 } 127 doesPhysicalDmg()128 bool doesPhysicalDmg() { 129 return (dmg_type_ & MapObject::dmg_Physical) != 0; 130 } 131 132 typedef enum { 133 spe_None = 0x0, 134 // can target only owner 135 spe_Owner = 0x0001, 136 137 spe_PointToPoint = 0x0002, 138 spe_PointToManyPoints = 0x0004, 139 140 spe_TargetReachInstant = 0x0008, 141 142 spe_TargetReachNeedTime = 0x0010, 143 spe_CreatesProjectile = 0x0010, 144 145 spe_RangeDamageOnReach = 0x0020, 146 // ignore accuracy 147 spe_ShootsWhileNoTarget = 0x0040, 148 spe_UsesAmmo = 0x0080, 149 spe_ChangeAttribute = 0x0100, 150 spe_SelfDestruction = 0x0200, 151 spe_TargetPedOnly = 0x0400, 152 spe_CanShoot = 0x0800, 153 //! Automatic weapon can shot continuously 154 spe_Automatic = 0X1000 155 } ShotPropertyEnum; 156 157 typedef enum { 158 wspt_None = spe_None, 159 wspt_Persuadatron = spe_None, 160 wspt_Pistol = 161 (spe_PointToPoint | spe_TargetReachInstant | spe_UsesAmmo 162 | spe_CanShoot), 163 wspt_GaussGun = 164 (spe_PointToPoint | spe_TargetReachNeedTime | spe_UsesAmmo 165 | spe_RangeDamageOnReach | spe_CanShoot), 166 wspt_Shotgun = 167 (spe_PointToManyPoints | spe_TargetReachInstant | spe_UsesAmmo 168 | spe_CanShoot), 169 wspt_Uzi = (spe_PointToPoint | spe_TargetReachInstant 170 | spe_UsesAmmo | spe_CanShoot | spe_Automatic), 171 wspt_Minigun = 172 (spe_PointToManyPoints | spe_TargetReachInstant | spe_UsesAmmo 173 | spe_CanShoot | spe_Automatic), 174 wspt_Laser = 175 (spe_PointToPoint | spe_TargetReachInstant 176 | spe_RangeDamageOnReach | spe_UsesAmmo | spe_CanShoot), 177 wspt_Flamer = 178 (spe_PointToPoint | spe_TargetReachNeedTime | spe_UsesAmmo 179 | spe_CanShoot | spe_Automatic), 180 wspt_LongRange = 181 (spe_PointToPoint | spe_TargetReachInstant | spe_UsesAmmo 182 | spe_CanShoot), 183 wspt_Scanner = (spe_Owner | spe_ChangeAttribute), 184 wspt_MediKit = (spe_Owner | spe_UsesAmmo), 185 wspt_TimeBomb = (spe_ShootsWhileNoTarget | spe_TargetReachInstant 186 | spe_RangeDamageOnReach | spe_SelfDestruction), 187 wspt_AccessCard = (spe_Owner | spe_ChangeAttribute), 188 wspt_EnergyShield = 189 (spe_Owner | spe_ChangeAttribute | spe_UsesAmmo), 190 } WeaponShotPropertyType; 191 192 enum SearchTargetMask { 193 stm_AllObjects = MapObject::kNaturePed | MapObject::kNatureVehicle 194 | MapObject::kNatureStatic | MapObject::kNatureWeapon 195 }; 196 197 // (WeaponShotPropertyType) shotProperty()198 unsigned int shotProperty() { return shot_property_; } 199 impactAnims()200 ImpactAnims * impactAnims() { return &impactAnims_; } rangeDmg()201 int rangeDmg() { return range_dmg_; } shotAngle()202 double shotAngle() { return shot_angle_; } shotAcurracy()203 double shotAcurracy() { return shot_accuracy_; } ammoCost()204 int ammoCost() { return ammo_cost_; } shotSpeed()205 int shotSpeed() { return shot_speed_; } shotsPerAmmo()206 int shotsPerAmmo() { return shots_per_ammo_; } 207 //! Returns the fire rate expressed in time between two shots fireRate()208 int fireRate() { return fireRate_; } usesAmmo()209 bool usesAmmo() { 210 return (shotProperty() & Weapon::spe_UsesAmmo) != 0; 211 } 212 /*! 213 * Return true if weapon is automatic. 214 * With automatic weapon, player can keep mouse clicked 215 * to shoot continuously. 216 */ isAutomatic()217 bool isAutomatic() { 218 return (shotProperty() & Weapon::spe_Automatic) != 0; 219 } 220 221 protected: 222 //! Init weapon from given config file 223 void initFromConfig(WeaponType w_type, ConfigFile &conf); 224 225 protected: 226 std::string name_; 227 int small_icon_, big_icon_; 228 /*! The price of this weapon.*/ 229 int cost_; 230 /*! The price to reload the weapon.*/ 231 int ammo_cost_; 232 int ammo_, range_, dmg_per_shot_; 233 int rank_; //!> weapon rank 234 WeaponType type_; 235 MapObject::DamageType dmg_type_; 236 int ammo_per_shot_; 237 //! time weapon uses to do a single shot 238 int time_for_shot_; 239 //! time required to make weapon ready to shoot 240 int time_reload_; 241 /*! True when weapon was found and submit to search manager.*/ 242 bool submittedToSearch_; 243 //WeaponShotPropertyType 244 uint32 shot_property_; 245 int range_dmg_; 246 //! some weapons have wider shot 247 double shot_angle_; 248 //! agent accuracy will be applied to this, later to shot_angle_ 249 double shot_accuracy_; 250 //! only projectiles have this set (gauss, flamer) 251 int shot_speed_; 252 //! shotgun only for now 253 int shots_per_ammo_; 254 //! The weight of a weapon influences the agent's speed 255 int weight_; 256 //! The fire rate expressed by time between two shots. Only for automatic weapons 257 int fireRate_; 258 //! 259 WeaponAnimIndex idx_; 260 int anim_; 261 //! Set of ids of impacts animation 262 ImpactAnims impactAnims_; 263 //! Sound of weapon 264 snd::InGameSample sample_; 265 }; 266 267 /*! 268 * Weapon instance class. 269 */ 270 class WeaponInstance : public ShootableMapObject { 271 public: 272 //! Creates a instance for the given weapon class 273 static WeaponInstance *createInstance(Weapon *pWeaponClass); 274 275 WeaponInstance(Weapon *w, uint16 id); 276 277 /*! Sets the owner of the weapon. */ setOwner(PedInstance * pOwner)278 void setOwner(PedInstance *pOwner) { pOwner_ = pOwner; } 279 /*! Return the owner of the weapon.*/ owner()280 PedInstance *owner() { return pOwner_; } 281 /*! Return true if the weapon has an owner.*/ hasOwner()282 bool hasOwner() { return pOwner_ != NULL; } 283 ammoRemaining()284 int ammoRemaining() { return ammo_remaining_; } setAmmoRemaining(int n)285 void setAmmoRemaining(int n) { ammo_remaining_ = n; } 286 287 bool animate(int elapsed); 288 void draw(int x, int y); 289 getWeaponClass()290 Weapon *getWeaponClass() { return pWeaponClass_; } 291 range()292 int range() { return pWeaponClass_->range(); } ammo()293 int ammo() { return pWeaponClass_->ammo(); } rank()294 int rank() { return pWeaponClass_->rank(); } shotProperty()295 uint32 shotProperty() { return pWeaponClass_->shotProperty(); } name()296 const char * name() { return pWeaponClass_->getName(); } 297 index()298 Weapon::WeaponAnimIndex index() { return pWeaponClass_->index(); } getWeaponType()299 Weapon::WeaponType getWeaponType() { return pWeaponClass_->getWeaponType(); } 300 301 bool operator==(WeaponInstance wi) { 302 return getWeaponType() == wi.getWeaponType(); 303 } 304 305 //! Plays the weapon's sound. 306 void playSound(); 307 resetWeaponUsedTime()308 void resetWeaponUsedTime() { weapon_used_time_ = 0; } 309 310 int getShots(int *elapsed = NULL, uint32 make_shots = 0); 311 312 void activate(); 313 void deactivate(); 314 315 void handleHit(ShootableMapObject::DamageInflictType & d); 316 canShoot()317 bool canShoot() { 318 return pWeaponClass_->canShoot(); 319 } 320 doesPhysicalDmg()321 bool doesPhysicalDmg() { 322 return pWeaponClass_->doesPhysicalDmg(); 323 } 324 needsReloading()325 bool needsReloading() { 326 return pWeaponClass_->ammo() > ammo_remaining_; 327 } 328 usesAmmo()329 bool usesAmmo() { 330 return (shotProperty() & Weapon::spe_UsesAmmo) != 0; 331 } 332 doesDmgStrict(uint32 dmg_type)333 bool doesDmgStrict(uint32 dmg_type) { 334 return pWeaponClass_->dmgType() == dmg_type; 335 } doesDmgNonStrict(uint32 dmg_type)336 bool doesDmgNonStrict(uint32 dmg_type) { 337 return (pWeaponClass_->dmgType() & dmg_type) != 0; 338 } dmgType()339 MapObject::DamageType dmgType() { 340 return pWeaponClass_->dmgType(); 341 } getWeight()342 int getWeight() { return pWeaponClass_->weight(); } 343 void updtWeaponUsedTime(int elapsed); 344 345 //! Use weapon 346 void fire(Mission *pMission, ShootableMapObject::DamageInflictType &dmg, int elapsed); 347 348 protected: 349 static uint16 weaponIdCnt; 350 Weapon *pWeaponClass_; 351 /*! Owner of the weapon.*/ 352 PedInstance *pOwner_; 353 int ammo_remaining_; 354 /*! if this value is smaller time_for_shot_ shot cannot be done 355 * if is greater then time_for_shot_ reload is in execution 356 * if is greater then time_for_shot_ + time_reload_ then full shot is done 357 * */ 358 int weapon_used_time_; 359 // used for timebomb sound effect 360 fs_utils::Timer bombSoundTimer; 361 /*! Timer used for bomb explosion.*/ 362 fs_utils::Timer bombExplosionTimer; 363 /*! Timer used for rotating flamer direction.*/ 364 fs_utils::Timer flamerTimer_; 365 bool activated_; 366 /*! used to avoid double consuming of same elapsed time, 367 * if ped shoots, time is consumed and should not be reused by weapon, 368 * NOTE: ped animate executed before weapon animate 369 */ 370 bool time_consumed_; 371 FlamerShot *pFlamerShot_; 372 }; 373 374 #endif 375