-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
itype.h
1596 lines (1281 loc) · 48.9 KB
/
itype.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#pragma once
#ifndef CATA_SRC_ITYPE_H
#define CATA_SRC_ITYPE_H
#include <array>
#include <cstddef>
#include <iosfwd>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
#include "bodypart.h"
#include "calendar.h"
#include "color.h" // nc_color
#include "damage.h"
#include "enums.h" // point
#include "explosion.h"
#include "game_constants.h"
#include "item_pocket.h"
#include "iuse.h" // use_function
#include "mapdata.h"
#include "proficiency.h"
#include "relic.h"
#include "stomach.h"
#include "translations.h"
#include "type_id.h"
#include "units.h"
#include "value_ptr.h"
class Item_factory;
class JsonObject;
class item;
struct tripoint;
template <typename E> struct enum_traits;
enum art_effect_active : int;
enum art_charge : int;
enum art_charge_req : int;
enum art_effect_passive : int;
class gun_modifier_data
{
private:
translation name_;
int qty_;
std::set<std::string> flags_;
public:
gun_modifier_data( const translation &n, const int q, const std::set<std::string> &f ) : name_( n ),
qty_( q ), flags_( f ) { }
const translation &name() const {
return name_;
}
/// @returns The translated name of the gun mode.
std::string tname() const {
return name_.translated();
}
int qty() const {
return qty_;
}
const std::set<std::string> &flags() const {
return flags_;
}
};
class gunmod_location
{
private:
std::string _id;
public:
gunmod_location() = default;
explicit gunmod_location( const std::string &id ) : _id( id ) { }
/// Returns the translated name.
std::string name() const;
/// Returns the location id.
std::string str() const {
return _id;
}
bool operator==( const gunmod_location &rhs ) const {
return _id == rhs._id;
}
bool operator<( const gunmod_location &rhs ) const {
return _id < rhs._id;
}
void deserialize( std::string &&id ) {
_id = std::move( id );
}
};
struct islot_tool {
std::set<ammotype> ammo_id;
translation revert_msg;
itype_id subtype;
int max_charges = 0;
int def_charges = 0;
int charge_factor = 1;
int charges_per_use = 0;
int turns_per_charge = 0;
units::power power_draw = 0_W;
float fuel_efficiency = -1.0f;
std::vector<int> rand_charges;
};
constexpr float base_metabolic_rate =
2500.0f; // kcal / day, standard average for human male, but game does not differentiate genders here.
struct islot_comestible {
public:
friend Item_factory;
friend item;
/** subtype, e.g. FOOD, DRINK, MED */
std::string comesttype;
/** tool needed to consume (e.g. lighter for cigarettes) */
itype_id tool = itype_id::NULL_ID();
/** Defaults # of charges (drugs, loaf of bread? etc) */
int def_charges = 0;
/** effect on character thirst (may be negative) */
int quench = 0;
/** Time until becomes rotten at standard temperature, or zero if never spoils */
time_duration spoils = 0_turns;
/** list of addictions and their potential */
std::map<addiction_id, int> addictions;
/** stimulant effect */
int stim = 0;
/**sleepiness altering effect*/
int sleepiness_mod = 0;
/** Reference to other item that replaces this one as a component in recipe results */
itype_id cooks_like;
/** Reference to item that will be received after smoking current item */
itype_id smoking_result;
/*
* For the few rare cases where default nutrition needs to be accessible. Prefer using
* default_character_compute_effective_nutrients unless absolutely necessary.
*/
nutrients default_nutrition_read_only() const {
return default_nutrition;
}
/** For the one case where default nutrition needs to be overridden. */
void set_default_nutrition( nutrients new_nutrition ) {
default_nutrition = std::move( new_nutrition );
};
/** TODO: add documentation */
int healthy = 0;
/** chance (odds) of becoming parasitised when eating (zero if never occurs) */
int parasites = 0;
/** freezing point in degrees celsius, below this temperature item can freeze */
float freeze_point = 0;
/** pet food category */
std::set<std::string> petfood;
/**effect on conditions to apply on consumption*/
std::vector<effect_on_condition_id> consumption_eocs;
/**List of diseases carried by this comestible and their associated probability*/
std::map<diseasetype_id, float> contamination;
// Materials to generate the below
std::map<material_id, int> materials;
//** specific heats in J/(g K) and latent heat in J/g */
float specific_heat_liquid = 4.186f;
float specific_heat_solid = 2.108f;
float latent_heat = 333.0f;
/** A penalty applied to fun for every time this food has been eaten in the last 48 hours */
int monotony_penalty = -1;
/** 1 nutr ~= 8.7kcal (1 nutr/5min = 288 nutr/day at 2500kcal/day) */
static constexpr float kcal_per_nutr = base_metabolic_rate / ( 12 * 24 );
bool has_calories() const {
return default_nutrition.calories > 0;
}
int get_default_nutr() const {
return default_nutrition.kcal() / kcal_per_nutr;
}
/** The monster that is drawn from when the item rots away */
mtype_id rot_spawn_monster = mtype_id::NULL_ID();
mongroup_id rot_spawn_group = mongroup_id::NULL_ID();
/** Chance the above monster spawns*/
int rot_spawn_chance = 10;
std::pair<int, int> rot_spawn_monster_amount = {1, 1};
private:
/** Nutrition values to use for this type when they aren't calculated from
* components */
nutrients default_nutrition;
/** effect on morale when consuming */
int fun = 0;
/** addiction potential to use when an addiction was given without one */
int default_addict_potential = 0;
};
struct islot_brewable {
/** What are the results of fermenting this item? */
std::map<itype_id, int> results;
/** How long for this brew to ferment. */
time_duration time = 0_turns;
bool was_loaded = false;
void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );
};
struct islot_compostable {
/** What are the results of fermenting this item? */
std::map<itype_id, int> results;
/** How long for this compost to ferment. */
time_duration time = 0_turns;
bool was_loaded = false;
void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );
};
/** Material data for individual armor body parts */
struct part_material {
material_id id; //material type
int cover; //portion coverage % of this material
float thickness; //portion thickness of this material
bool ignore_sheet_thickness = false; //if the def should ignore thickness of materials sheets
bool operator ==( const part_material &comp ) const {
return id == comp.id && cover == comp.cover && thickness == comp.thickness;
}
part_material() : id( material_id::NULL_ID() ), cover( 100 ), thickness( 0.0f ) {}
part_material( material_id id, int cover, float thickness ) :
id( id ), cover( cover ), thickness( thickness ) {}
part_material( const std::string &id, int cover, float thickness ) :
id( material_id( id ) ), cover( cover ), thickness( thickness ) {}
void deserialize( const JsonObject &jo );
};
// values for attributes related to encumbrance
enum class encumbrance_modifier : int {
IMBALANCED = 0,
RESTRICTS_NECK,
WELL_SUPPORTED,
NONE,
last
};
template<>
struct enum_traits<encumbrance_modifier> {
static constexpr encumbrance_modifier last = encumbrance_modifier::last;
};
// if it is a multiplier or flat modifier
enum class encumbrance_modifier_type : int {
MULT = 0,
FLAT,
last
};
struct armor_portion_data {
// The base volume for an item
static constexpr units::volume volume_per_encumbrance = 250_ml; // NOLINT(cata-serialize)
// descriptors used to infer encumbrance
std::vector<encumbrance_modifier> encumber_modifiers;
// How much this piece encumbers the player.
int encumber = 0;
// When storage is full, how much it encumbers the player.
int max_encumber = -1;
// how much an item can hold comfortably compared to an average item
float volume_encumber_modifier = 1;
// Percentage of the body part that this item covers.
// This determines how likely it is to hit the item instead of the player.
int coverage = 0;
int cover_melee = 0;
int cover_ranged = 0;
int cover_vitals = 0;
/**
* Average material thickness for all materials from
* this armor portion
*/
float avg_thickness = 0.0f;
/**
* Resistance to environmental effects.
*/
int env_resist = 0;
/**
* Environmental protection of a gas mask with installed filter.
*/
int env_resist_w_filter = 0;
/**
* What materials this portion is made of, for armor purposes.
* Includes material portion and thickness.
*/
std::vector<part_material> materials;
// Where does this cover if any
std::optional<body_part_set> covers;
std::set<sub_bodypart_str_id> sub_coverage;
// What layer does it cover if any
std::set<layer_level> layers;
// these are pre-calc values to save us time later
// the chance that every material applies to an attack
// this is primarily used as a cached value for UI
int best_protection_chance = 100; // NOLINT(cata-serialize)
// the chance that the smallest number of materials possible applies to an attack
// this is primarily used as a cached value for UI
int worst_protection_chance = 0; // NOLINT(cata-serialize)
// this is to test if the armor has unique layering information
bool has_unique_layering = false; // NOLINT(cata-serialize)
// how breathable this part of the armor is
// cached from the material data
// only tracked for amalgamized body parts entries
// if left the default -1 the value will be recalculated,
int breathability = -1; // NOLINT(cata-serialize)
// if this item is rigid, can't be worn with other rigid items
bool rigid = false; // NOLINT(cata-serialize)
// if this item only conflicts with rigid items that share a direct layer with it
bool rigid_layer_only = false;
// if this item is comfortable to wear without other items bellow it
bool comfortable = false; // NOLINT(cata-serialize)
/**
* Returns the amount all sublocations this item covers could possibly
* cover the specific body part.
* This is used for converting from sub location coverage values
* to body part coverage values. EX: shin guards cover the whole shin 100%
* coverage. However only cover 35% of the overall leg.
*/
int max_coverage( bodypart_str_id bp ) const;
// checks if two entries are similar enough to be consolidated
static bool should_consolidate( const armor_portion_data &l, const armor_portion_data &r );
// helper function to return encumbrance value by descriptor and weight
int calc_encumbrance( units::mass weight, bodypart_id bp ) const;
// converts a specific encumbrance modifier to an actual encumbrance value
static std::tuple<encumbrance_modifier_type, int> convert_descriptor_to_val(
encumbrance_modifier em );
void deserialize( const JsonObject &jo );
};
struct islot_armor {
public:
// thresholds for an item to count as hard / comfortable to wear
static const int test_threshold = 40;
/**
* Whether this item can be worn on either side of the body
*/
bool sided = false;
/**
* The Non-Functional variant of this item. Currently only applies to ablative plates
*/
itype_id non_functional;
/**
* The verb for what happens when the item transforms to non-functional
*/
translation damage_verb;
/**
* How much warmth this item provides.
*/
int warmth = 0;
/**
* The max health of an energy shield type armor. Value is completely ignored if the
* ENERGY_SHIELD flag is not set. This value and "energy_shield_hp" are then stored
* through item variables so that they might be manipulated with EOCS and magic.
*/
int max_energy_shield_hp = 0;
/**
* Whether this is a power armor item.
*/
bool power_armor = false;
/**
* Whether this item has ablative pockets
*/
bool ablative = false;
/**
* Whether this item has pockets that generate additional encumbrance
*/
bool additional_pocket_enc = false;
/**
* Whether this item has pockets that can be ripped off
*/
bool ripoff_chance = false;
/**
* If the entire item is rigid
*/
bool rigid = false;
/**
* If the entire item is comfortable
*/
bool comfortable = true;
/**
* Whether this item has pockets that are noisy
*/
bool noisy = false;
/**
* Whitelisted clothing mods.
* Restricted clothing mods must be listed here by id to be compatible.
*/
std::vector<std::string> valid_mods;
/**
* If the item in question has any sub coverage when testing for encumbrance
*/
bool has_sub_coverage = false;
// Layer, encumbrance and coverage information for each body part.
// This isn't directly loaded in but is instead generated from the loaded in
// sub_data vector
std::vector<armor_portion_data> data;
// Layer, encumbrance and coverage information for each sub body part.
// This vector can have duplicates for body parts themselves.
std::vector<armor_portion_data> sub_data;
// all of the layers this item is involved in
std::vector<layer_level> all_layers;
bool was_loaded = false;
int avg_env_resist() const;
int avg_env_resist_w_filter() const;
float avg_thickness() const;
void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );
private:
// Base material thickness, used to derive thickness in sub_data
std::optional<float> _material_thickness = 0.0f;
std::optional<int> _env_resist = 0;
std::optional<int> _env_resist_w_filter = 0;
};
struct islot_pet_armor {
/**
* TODO: document me.
*/
float thickness = 0;
/**
* Resistance to environmental effects.
*/
int env_resist = 0;
/**
* Environmental protection of a gas mask with installed filter.
*/
int env_resist_w_filter = 0;
/**
* The maximum volume a pet can be and wear this armor
*/
units::volume max_vol = 0_ml;
/**
* The minimum volume a pet can be and wear this armor
*/
units::volume min_vol = 0_ml;
/**
* What animal bodytype can wear this armor
*/
std::string bodytype = "none";
/**
* Whether this is a power armor item.
*/
bool power_armor = false;
bool was_loaded = false;
void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );
};
struct islot_book {
/**
* Which skill it upgrades, if any. Can be @ref skill_id::NULL_ID.
*/
skill_id skill = skill_id::NULL_ID();
/**
* Which martial art it teaches. Can be @ref matype_id::NULL_ID.
*/
matype_id martial_art = matype_id::NULL_ID();
/**
* The skill level the book provides.
*/
int level = 0;
/**
* The skill level required to understand it.
*/
int req = 0;
/**
* How fun reading this is, can be negative.
*/
int fun = 0;
/**
* Intelligence required to read it.
*/
int intel = 0;
/**
* How long it takes to read.
* "To read" means getting 1 skill point, not all of them.
*/
time_duration time = 0_turns;
/**
* Fun books have chapters; after all are read, the book is less fun.
*/
int chapters = 0;
/**
* What recipes can be learned from this book.
*/
struct recipe_with_description_t {
/**
* The recipe that can be learned (never null).
*/
const class recipe *recipe;
/**
* The skill level required to learn the recipe.
*/
int skill_level;
/**
* The name for the recipe as it appears in the book.
*/
std::optional<translation> optional_name;
/**
* Hidden means it does not show up in the description of the book.
*/
bool hidden;
bool operator<( const recipe_with_description_t &rhs ) const {
return recipe < rhs.recipe;
}
bool is_hidden() const {
return hidden;
}
std::string name() const;
};
using recipe_list_t = std::set<recipe_with_description_t>;
recipe_list_t recipes;
std::vector<book_proficiency_bonus> proficiencies;
bool was_loaded = false;
bool is_scannable = false;
void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );
};
struct islot_mod {
/** If non-empty restrict mod to items with those base (before modifiers) ammo types */
std::set<ammotype> acceptable_ammo;
/** If set modifies parent ammo to this type */
std::set<ammotype> ammo_modifier;
/** If non-empty replaces the compatible magazines for the parent item */
std::map< ammotype, std::set<itype_id> > magazine_adaptor;
/**
* Pockets the mod will add to the item.
* Any MAGAZINE_WELL or MAGAZINE type pockets will be overwritten,
* and CONTAINER pockets will be added.
*/
std::vector<pocket_data> add_pockets;
/** Proportional adjustment of parent item ammo capacity */
float capacity_multiplier = 1.0f;
};
/**
* Common data for ranged things: guns, gunmods and ammo.
* The values of the gun itself, its mods and its current ammo (optional) are usually summed
* up in the item class and the sum is used.
*/
struct common_ranged_data {
/**
* Damage, armor piercing and multipliers for each.
* If multipliers are set on both gun and ammo, values will be normalized
* as in @ref damage_instance::add_damage
*/
damage_instance damage;
/**
* Range bonus from gun.
*/
int range = 0;
/**
* Range multiplier from gunmods or ammo.
*/
float range_multiplier = 1.0;
/**
* Dispersion "bonus" from gun.
*/
int dispersion = 0;
};
struct islot_engine {
friend Item_factory;
friend item;
public:
/** for combustion engines the displacement (cc) */
int displacement = 0;
bool was_loaded = false;
void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );
};
struct islot_wheel {
public:
/** diameter of wheel (inches) */
int diameter = 0;
/** width of wheel (inches) */
int width = 0;
bool was_loaded = false;
void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );
};
enum class itype_variant_kind : int {
gun,
generic,
drug,
last
};
template<>
struct enum_traits<itype_variant_kind> {
static constexpr itype_variant_kind last = itype_variant_kind::last;
};
struct itype_variant_data {
std::string id;
translation alt_name;
translation alt_description;
ascii_art_id art;
std::optional<std::string> alt_sym;
std::optional<nc_color> alt_color = std::nullopt;
bool append = false; // if the description should be appended to the base description.
// Expand the description when generated and save it on the item
bool expand_snippets = false;
int weight = 1;
void deserialize( const JsonObject &jo );
void load( const JsonObject &jo );
};
// TODO: this shares a lot with the ammo item type, merge into a separate slot type?
struct islot_gun : common_ranged_data {
/**
* What skill this gun uses.
*/
skill_id skill_used = skill_id::NULL_ID();
/**
* What type of ammo this gun uses.
*/
std::set<ammotype> ammo;
/**
* Gun durability, affects gun being damaged during shooting.
*/
int durability = 0;
/**
* For guns with an integral magazine what is the capacity?
*/
int clip = 0;
/**
* Reload time, in moves.
*/
int reload_time = 100;
/**
* Noise displayed when reloading the weapon.
*/
translation reload_noise = to_translation( "click." );
/**
* Volume of the noise made when reloading this weapon.
*/
int reload_noise_volume = 0;
/** Maximum aim achievable using base weapon sights */
int sight_dispersion = 30;
/** Modifies base loudness as provided by the currently loaded ammo */
int loudness = 0;
/**
* If this uses electric energy, how much (per shot).
*/
units::energy energy_drain = 0_kJ;
/**
* One in X chance for gun to require major cleanup after firing blackpowder shot.
*/
int blackpowder_tolerance = 8;
/**
* Minimum ammo recoil for gun to be able to fire more than once per attack.
*/
int min_cycle_recoil = 0;
/**
* Length of gun barrel, if positive allows sawing down of the barrel
*/
units::volume barrel_volume = 0_ml;
units::length barrel_length = 0_mm;
/**
* Effects that are applied to the ammo when fired.
*/
std::set<ammo_effect_str_id> ammo_effects;
/**
* Location for gun mods.
* Key is the location (untranslated!), value is the number of mods
* that the location can have. The value should be > 0.
*/
std::map<gunmod_location, int> valid_mod_locations;
/**
*Built in mods. string is id of mod. These mods will get the IRREMOVABLE flag set.
*/
std::set<itype_id> built_in_mods;
/**
*Default mods, string is id of mod. These mods are removable but are default on the weapon.
*/
std::set<itype_id> default_mods;
/** Firing modes are supported by the gun. Always contains at least DEFAULT mode */
std::map<gun_mode_id, gun_modifier_data> modes;
/** How easy is control of recoil? If unset value automatically derived from weapon type */
int handling = -1;
/**
* Additional recoil applied per shot before effects of handling are considered
* @note useful for adding recoil effect to guns which otherwise consume no ammo
*/
int recoil = 0;
int ammo_to_fire = 1;
/**
* The amount by which the item's overheat value is reduced every turn. Used in
* overheat-based guns.
*/
double cooling_value = 100.0;
/**
* Used only in overheat-based guns. No melting LMG barrels yet.
*/
double heat_per_shot = 0.0;
/**
* Used in overheat-based guns.
* Heat value at which critical overheat faults might occur.
* A value beneath 0.0 means that the gun cannot overheat.
*/
double overheat_threshold = -1.0;
/**
* Multiplier of the chance for the gun to jam.
*/
double gun_jam_mult = 1;
std::map<ammotype, std::set<itype_id>> cached_ammos;
/**
* Used for the skullgun cbm. Hurts the bodypart by that much when fired
*/
std::map<bodypart_str_id, int> hurt_part_when_fired;
};
/// The type of gun. The second "_type" suffix is only to distinguish it from `item::gun_type`.
class gun_type_type
{
private:
std::string name_;
public:
/// @param name The untranslated name of the gun type. Must have been extracted
/// for translation with the context "gun_type_type".
explicit gun_type_type( const std::string &name ) : name_( name ) {}
/// Translated name.
std::string name() const;
friend bool operator==( const gun_type_type &l, const gun_type_type &r ) {
return l.name_ == r.name_;
}
friend struct std::hash<gun_type_type>;
};
namespace std
{
template<>
struct hash<gun_type_type> {
size_t operator()( const gun_type_type &t ) const noexcept {
return hash<std::string>()( t.name_ );
}
};
} // namespace std
struct islot_gunmod : common_ranged_data {
/** Where is this gunmod installed (e.g. "stock", "rail")? */
gunmod_location location;
/** What kind of weapons can this gunmod be used with (e.g. "rifle", "crossbow")? */
std::unordered_set<gun_type_type> usable;
/** If this value is set (non-negative), this gunmod functions as a sight. A sight is only usable to aim by a character whose current @ref Character::recoil is at or below this value. */
int sight_dispersion = -1;
/**
* If the target has not appeared in the scope, the aiming speed is relatively low.
* When the target appears in the scope, the aiming speed will be greatly accelerated.
* FoV uses a more realistic method to reflect the aiming speed of the sight to insteadthe original abstract aim_speed
*/
int field_of_view = -1;
/**
* Its position has been replaced by FoV.
* But it is still retained due to compatibility considerations.
*/
int aim_speed = -1;
/**
* This value is used to reflect other factors affecting aiming speed except Fov
*/
double aim_speed_modifier = 0;
/** Modifies base loudness as provided by the currently loaded ammo */
int loudness = 0;
/** Multiplies base loudness as provided by the currently loaded ammo */
float loudness_multiplier = 1;
/** How many moves does this gunmod take to install? */
int install_time = -1;
/** Increases base gun energy consumption by this many times per shot */
float energy_drain_multiplier = 1.0f;
/** Increases base gun energy consumption by this value per shot */
units::energy energy_drain_modifier = 0_kJ;
/** Increases base gun ammo to fire by this many times per shot */
float ammo_to_fire_multiplier = 1.0f;
/** Increases base gun ammo to fire by this value per shot */
int ammo_to_fire_modifier = 0;
/** Increases gun weight by this many times */
float weight_multiplier = 1.0f;
/** Firing modes added to or replacing those of the base gun */
std::map<gun_mode_id, gun_modifier_data> mode_modifier;
std::set<std::string> ammo_effects;
/** Relative adjustment to base gun handling */
int handling = 0;
/** Percentage value change to the gun's loading time. Higher is slower */
int reload_modifier = 0;
/** Percentage value change to the gun's loading time. Higher is less likely */
int consume_chance = 10000;
/** Divsor to scale back gunmod consumption damage. lower is more damaging. Affected by ammo loudness and recoil, see ranged.cpp for how much. */
int consume_divisor = 1;
/** Enlarge or reduce shot spread */
float shot_spread_multiplier_modifier = 0.0f;
/** Modifies base strength required */
int min_str_required_mod = 0;
/** Additional gunmod slots to add to the gun */
std::map<gunmod_location, int> add_mod;
// wheter the item is supposed to work as a bayonet when attached
bool is_bayonet = false;
/** Not compatible on weapons that have this mod slot */
std::set<gunmod_location> blacklist_slot;
/** Not compatible on weapons that have these mods */
std::set<itype_id> blacklist_mod;
// hard coded barrel length from this mod
units::length barrel_length = 0_mm;
// minimum recoil to cycle while this is installed
int overwrite_min_cycle_recoil = -1;
//Manipulate overheat thresholds with fixed values and percentages
double overheat_threshold_modifier = 0;
float overheat_threshold_multiplier = 1.0f;
//Manipulate cooling capacity with fixed values and percentages
double cooling_value_modifier = 0;
float cooling_value_multiplier = 1.0f;
//Manipulation of generated heat by fixed values and percentages
double heat_per_shot_modifier = 0;
float heat_per_shot_multiplier = 1.0f;
};
struct islot_magazine {
/** What type of ammo this magazine can be loaded with */
std::set<ammotype> type;
/** Capacity of magazine (in equivalent units to ammo charges) */
int capacity = 0;
/** Default amount of ammo contained by a magazine (often set for ammo belts) */
int count = 0;
/** Default type of ammo contained by a magazine (often set for ammo belts) */
itype_id default_ammo = itype_id::NULL_ID();
/** How long it takes to load each unit of ammo into the magazine */
int reload_time = 100;
/** Multiplier for the gun jamming from physical damage */
double mag_jam_mult = 1 ;
/** For ammo belts one linkage (of given type) is dropped for each unit of ammo consumed */
std::optional<itype_id> linkage;
std::map<ammotype, std::set<itype_id>> cached_ammos;
/** Map of [magazine type id] -> [set of gun itype_ids that accept the mag type ] */
static std::map<itype_id, std::set<itype_id>> compatible_guns;
};
struct islot_battery {
/** Maximum energy the battery can store */
units::energy max_capacity;
bool was_loaded = false;
void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );
};
struct islot_ammo : common_ranged_data {
/**