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