1 #include "mattack_common.h" // IWYU pragma: associated
2 #include "monstergenerator.h" // IWYU pragma: associated
3 
4 #include <algorithm>
5 #include <cstdlib>
6 #include <limits>
7 #include <new>
8 #include <set>
9 #include <string>
10 #include <utility>
11 
12 #include "assign.h"
13 #include "bodypart.h"
14 #include "cached_options.h"
15 #include "calendar.h"
16 #include "catacharset.h"
17 #include "creature.h"
18 #include "damage.h"
19 #include "debug.h"
20 #include "enum_conversions.h"
21 #include "field_type.h"
22 #include "generic_factory.h"
23 #include "item.h"
24 #include "item_group.h"
25 #include "json.h"
26 #include "mattack_actors.h"
27 #include "monattack.h"
28 #include "mondeath.h"
29 #include "mondefense.h"
30 #include "mongroup.h"
31 #include "optional.h"
32 #include "options.h"
33 #include "pathfinding.h"
34 #include "rng.h"
35 #include "translations.h"
36 #include "units.h"
37 
38 namespace behavior
39 {
40 class node_t;
41 }  // namespace behavior
42 
43 namespace io
44 {
45 
46 template<>
enum_to_string(mon_trigger data)47 std::string enum_to_string<mon_trigger>( mon_trigger data )
48 {
49     switch( data ) {
50         // *INDENT-OFF*
51         case mon_trigger::STALK: return "STALK";
52         case mon_trigger::MEAT: return "MEAT";
53         case mon_trigger::HOSTILE_WEAK: return "PLAYER_WEAK";
54         case mon_trigger::HOSTILE_CLOSE: return "PLAYER_CLOSE";
55         case mon_trigger::HURT: return "HURT";
56         case mon_trigger::FIRE: return "FIRE";
57         case mon_trigger::FRIEND_DIED: return "FRIEND_DIED";
58         case mon_trigger::FRIEND_ATTACKED: return "FRIEND_ATTACKED";
59         case mon_trigger::SOUND: return "SOUND";
60         case mon_trigger::PLAYER_NEAR_BABY: return "PLAYER_NEAR_BABY";
61         case mon_trigger::MATING_SEASON: return "MATING_SEASON";
62         // *INDENT-ON*
63         case mon_trigger::_LAST:
64             break;
65     }
66     debugmsg( "Invalid mon_trigger" );
67     abort();
68 }
69 
70 template<>
enum_to_string(m_flag data)71 std::string enum_to_string<m_flag>( m_flag data )
72 {
73     // see mtype.h for commentary
74     switch( data ) {
75         // *INDENT-OFF*
76         case MF_SEES: return "SEES";
77         case MF_HEARS: return "HEARS";
78         case MF_GOODHEARING: return "GOODHEARING";
79         case MF_SMELLS: return "SMELLS";
80         case MF_KEENNOSE: return "KEENNOSE";
81         case MF_STUMBLES: return "STUMBLES";
82         case MF_WARM: return "WARM";
83         case MF_NOHEAD: return "NOHEAD";
84         case MF_HARDTOSHOOT: return "HARDTOSHOOT";
85         case MF_GRABS: return "GRABS";
86         case MF_BASHES: return "BASHES";
87         case MF_GROUP_BASH: return "GROUP_BASH";
88         case MF_DESTROYS: return "DESTROYS";
89         case MF_BORES: return "BORES";
90         case MF_POISON: return "POISON";
91         case MF_VENOM: return "VENOM";
92         case MF_BADVENOM: return "BADVENOM";
93         case MF_PARALYZE: return "PARALYZEVENOM";
94         case MF_WEBWALK: return "WEBWALK";
95         case MF_DIGS: return "DIGS";
96         case MF_CAN_DIG: return "CAN_DIG";
97         case MF_CAN_OPEN_DOORS: return "CAN_OPEN_DOORS";
98         case MF_FLIES: return "FLIES";
99         case MF_AQUATIC: return "AQUATIC";
100         case MF_SWIMS: return "SWIMS";
101         case MF_FISHABLE: return "FISHABLE";
102         case MF_ATTACKMON: return "ATTACKMON";
103         case MF_ANIMAL: return "ANIMAL";
104         case MF_PLASTIC: return "PLASTIC";
105         case MF_SUNDEATH: return "SUNDEATH";
106         case MF_ELECTRIC: return "ELECTRIC";
107         case MF_ACIDPROOF: return "ACIDPROOF";
108         case MF_ACIDTRAIL: return "ACIDTRAIL";
109         case MF_SHORTACIDTRAIL: return "SHORTACIDTRAIL";
110         case MF_FIREPROOF: return "FIREPROOF";
111         case MF_SLUDGEPROOF: return "SLUDGEPROOF";
112         case MF_SLUDGETRAIL: return "SLUDGETRAIL";
113         case MF_COLDPROOF: return "COLDPROOF";
114         case MF_FIREY: return "FIREY";
115         case MF_QUEEN: return "QUEEN";
116         case MF_ELECTRONIC: return "ELECTRONIC";
117         case MF_FUR: return "FUR";
118         case MF_LEATHER: return "LEATHER";
119         case MF_WOOL: return "WOOL";
120         case MF_CBM_CIV: return "CBM_CIV";
121         case MF_BONES: return "BONES";
122         case MF_FAT: return "FAT";
123         case MF_CONSOLE_DESPAWN: return "CONSOLE_DESPAWN";
124         case MF_IMMOBILE: return "IMMOBILE";
125         case MF_ID_CARD_DESPAWN: return "ID_CARD_DESPAWN";
126         case MF_RIDEABLE_MECH: return "RIDEABLE_MECH";
127         case MF_MILITARY_MECH: return "MILITARY_MECH";
128         case MF_MECH_RECON_VISION: return "MECH_RECON_VISION";
129         case MF_MECH_DEFENSIVE: return "MECH_DEFENSIVE";
130         case MF_HIT_AND_RUN: return "HIT_AND_RUN";
131         case MF_GUILT: return "GUILT";
132         case MF_PAY_BOT: return "PAY_BOT";
133         case MF_HUMAN: return "HUMAN";
134         case MF_NO_BREATHE: return "NO_BREATHE";
135         case MF_FLAMMABLE: return "FLAMMABLE";
136         case MF_REVIVES: return "REVIVES";
137         case MF_CHITIN: return "CHITIN";
138         case MF_VERMIN: return "VERMIN";
139         case MF_NOGIB: return "NOGIB";
140         case MF_ABSORBS: return "ABSORBS";
141         case MF_ABSORBS_SPLITS: return "ABSORBS_SPLITS";
142         case MF_LARVA: return "LARVA";
143         case MF_ARTHROPOD_BLOOD: return "ARTHROPOD_BLOOD";
144         case MF_ACID_BLOOD: return "ACID_BLOOD";
145         case MF_BILE_BLOOD: return "BILE_BLOOD";
146         case MF_CBM_POWER: return "CBM_POWER";
147         case MF_CBM_SCI: return "CBM_SCI";
148         case MF_CBM_OP: return "CBM_OP";
149         case MF_CBM_TECH: return "CBM_TECH";
150         case MF_CBM_SUBS: return "CBM_SUBS";
151         case MF_FILTHY: return "FILTHY";
152         case MF_SWARMS: return "SWARMS";
153         case MF_CLIMBS: return "CLIMBS";
154         case MF_GROUP_MORALE: return "GROUP_MORALE";
155         case MF_INTERIOR_AMMO: return "INTERIOR_AMMO";
156         case MF_NIGHT_INVISIBILITY: return "NIGHT_INVISIBILITY";
157         case MF_REVIVES_HEALTHY: return "REVIVES_HEALTHY";
158         case MF_NO_NECRO: return "NO_NECRO";
159         case MF_PACIFIST: return "PACIFIST";
160         case MF_PUSH_MON: return "PUSH_MON";
161         case MF_PUSH_VEH: return "PUSH_VEH";
162         case MF_AVOID_DANGER_1: return "PATH_AVOID_DANGER_1";
163         case MF_AVOID_DANGER_2: return "PATH_AVOID_DANGER_2";
164         case MF_AVOID_FALL: return "PATH_AVOID_FALL";
165         case MF_AVOID_FIRE: return "PATH_AVOID_FIRE";
166         case MF_PRIORITIZE_TARGETS: return "PRIORITIZE_TARGETS";
167         case MF_NOT_HALLU: return "NOT_HALLUCINATION";
168         case MF_CATFOOD: return "CATFOOD";
169         case MF_CANPLAY: return "CANPLAY";
170         case MF_CATTLEFODDER: return "CATTLEFODDER";
171         case MF_BIRDFOOD: return "BIRDFOOD";
172         case MF_PET_MOUNTABLE: return "PET_MOUNTABLE";
173         case MF_PET_HARNESSABLE: return "PET_HARNESSABLE";
174         case MF_DOGFOOD: return "DOGFOOD";
175         case MF_MILKABLE: return "MILKABLE";
176         case MF_SHEARABLE: return "SHEARABLE";
177         case MF_NO_BREED: return "NO_BREED";
178         case MF_PET_WONT_FOLLOW: return "PET_WONT_FOLLOW";
179         case MF_DRIPS_NAPALM: return "DRIPS_NAPALM";
180         case MF_DRIPS_GASOLINE: return "DRIPS_GASOLINE";
181         case MF_ELECTRIC_FIELD: return "ELECTRIC_FIELD";
182         case MF_STUN_IMMUNE: return "STUN_IMMUNE";
183         case MF_LOUDMOVES: return "LOUDMOVES";
184         case MF_DROPS_AMMO: return "DROPS_AMMO";
185         case MF_INSECTICIDEPROOF: return "INSECTICIDEPROOF";
186         case MF_RANGED_ATTACKER: return "RANGED_ATTACKER";
187         // *INDENT-ON*
188         case m_flag::MF_MAX:
189             break;
190     }
191     debugmsg( "Invalid m_flag" );
192     abort();
193 }
194 
195 } // namespace io
196 
197 /** @relates string_id */
198 template<>
obj() const199 const mtype &string_id<mtype>::obj() const
200 {
201     return MonsterGenerator::generator().mon_templates->obj( *this );
202 }
203 
204 /** @relates string_id */
205 template<>
is_valid() const206 bool string_id<mtype>::is_valid() const
207 {
208     return MonsterGenerator::generator().mon_templates->is_valid( *this );
209 }
210 
211 /** @relates string_id */
212 template<>
obj() const213 const species_type &string_id<species_type>::obj() const
214 {
215     return MonsterGenerator::generator().mon_species->obj( *this );
216 }
217 
218 /** @relates string_id */
219 template<>
is_valid() const220 bool string_id<species_type>::is_valid() const
221 {
222     return MonsterGenerator::generator().mon_species->is_valid( *this );
223 }
224 
get_death_function(const std::string & f) const225 cata::optional<mon_action_death> MonsterGenerator::get_death_function( const std::string &f ) const
226 {
227     const auto it = death_map.find( f );
228 
229     return it != death_map.cend()
230            ? cata::optional<mon_action_death>( it->second )
231            : cata::optional<mon_action_death>();
232 }
233 
MonsterGenerator()234 MonsterGenerator::MonsterGenerator()
235     : mon_templates( "monster type" )
236     , mon_species( "species" )
237 {
238     mon_templates->insert( mtype() );
239     mon_species->insert( species_type() );
240     init_phases();
241     init_attack();
242     init_defense();
243     init_death();
244 }
245 
246 MonsterGenerator::~MonsterGenerator() = default;
247 
reset()248 void MonsterGenerator::reset()
249 {
250     mon_templates->reset();
251     mon_templates->insert( mtype() );
252 
253     mon_species->reset();
254     mon_species->insert( species_type() );
255 
256     hallucination_monsters.clear();
257 
258     attack_map.clear();
259     // Hardcode attacks need to be re-added here
260     // TODO: Move initialization from constructor to init()
261     init_attack();
262 }
263 
calc_bash_skill(const mtype & t)264 static int calc_bash_skill( const mtype &t )
265 {
266     // IOW, the critter's max bashing damage
267     int ret = t.melee_dice * t.melee_sides;
268     // This is for stuff that goes through solid rock: minerbots, dark wyrms, etc
269     if( t.has_flag( MF_BORES ) ) {
270         ret *= 15;
271     } else if( t.has_flag( MF_DESTROYS ) ) {
272         ret *= 2.5;
273     } else if( !t.has_flag( MF_BASHES ) ) {
274         ret = 0;
275     }
276 
277     return ret;
278 }
279 
volume_to_size(const units::volume & vol)280 static creature_size volume_to_size( const units::volume &vol )
281 {
282     if( vol <= 7500_ml ) {
283         return creature_size::tiny;
284     } else if( vol <= 46250_ml ) {
285         return creature_size::small;
286     } else if( vol <= 77500_ml ) {
287         return creature_size::medium;
288     } else if( vol <= 483750_ml ) {
289         return creature_size::large;
290     }
291     return creature_size::huge;
292 }
293 
294 struct monster_adjustment {
295     species_id species;
296     std::string stat;
297     float stat_adjust = 0.0f;
298     std::string flag;
299     bool flag_val = false;
300     std::string special;
301     void apply( mtype &mon );
302 };
303 
apply(mtype & mon)304 void monster_adjustment::apply( mtype &mon )
305 {
306     if( !mon.in_species( species ) ) {
307         return;
308     }
309     if( !stat.empty() ) {
310         if( stat == "speed" ) {
311             mon.speed *= stat_adjust;
312         } else if( stat == "hp" ) {
313             mon.hp *= stat_adjust;
314         }
315     }
316     if( !flag.empty() ) {
317         mon.set_flag( io::string_to_enum<m_flag>( flag ), flag_val );
318     }
319     if( !special.empty() ) {
320         if( special == "nightvision" ) {
321             mon.vision_night = mon.vision_day;
322         }
323     }
324 }
325 
326 static std::vector<monster_adjustment> adjustments;
327 
reset_monster_adjustment()328 void reset_monster_adjustment()
329 {
330     adjustments.clear();
331 }
332 
load_monster_adjustment(const JsonObject & jsobj)333 void load_monster_adjustment( const JsonObject &jsobj )
334 {
335     monster_adjustment adj;
336     adj.species = species_id( jsobj.get_string( "species" ) );
337     if( jsobj.has_member( "stat" ) ) {
338         JsonObject stat = jsobj.get_object( "stat" );
339         stat.read( "name", adj.stat );
340         stat.read( "modifier", adj.stat_adjust );
341     }
342     if( jsobj.has_member( "flag" ) ) {
343         JsonObject flag = jsobj.get_object( "flag" );
344         flag.read( "name", adj.flag );
345         flag.read( "value", adj.flag_val );
346     }
347     if( jsobj.has_member( "special" ) ) {
348         jsobj.read( "special", adj.special );
349     }
350     adjustments.push_back( adj );
351 }
352 
build_behavior_tree(mtype & type)353 static void build_behavior_tree( mtype &type )
354 {
355     type.set_strategy();
356     if( type.has_flag( MF_ABSORBS ) || type.has_flag( MF_ABSORBS_SPLITS ) ) {
357         type.add_goal( "absorb_items" );
358     }
359     for( const std::pair<const std::string, mtype_special_attack> &attack : type.special_attacks ) {
360         if( string_id<behavior::node_t>( attack.first ).is_valid() ) {
361             type.add_goal( attack.first );
362         } /* TODO: Make this an error once all the special attacks are migrated. */
363     }
364 }
365 
finalize_mtypes()366 void MonsterGenerator::finalize_mtypes()
367 {
368     mon_templates->finalize();
369     for( const mtype &elem : mon_templates->get_all() ) {
370         mtype &mon = const_cast<mtype &>( elem );
371 
372         if( !mon.default_faction.is_valid() ) {
373             debugmsg( "Monster type '%s' has invalid default_faction: '%s'. "
374                       "Add this faction to json as MONSTER_FACTION type.",
375                       mon.id.str(), mon.default_faction.str() );
376         }
377 
378         apply_species_attributes( mon );
379         validate_species_ids( mon );
380         mon.size = volume_to_size( mon.volume );
381 
382         // adjust for worldgen difficulty parameters
383         mon.speed *= get_option<int>( "MONSTER_SPEED" )      / 100.0;
384         mon.hp    *= get_option<int>( "MONSTER_RESILIENCE" ) / 100.0;
385 
386         for( monster_adjustment adj : adjustments ) {
387             adj.apply( mon );
388         }
389 
390         if( mon.bash_skill < 0 ) {
391             mon.bash_skill = calc_bash_skill( mon );
392         }
393 
394         if( mon.armor_bash < 0 ) {
395             mon.armor_bash = 0;
396         }
397         if( mon.armor_cut < 0 ) {
398             mon.armor_cut = 0;
399         }
400         if( mon.armor_stab < 0 ) {
401             mon.armor_stab = mon.armor_cut * 0.8;
402         }
403         if( mon.armor_bullet < 0 ) {
404             mon.armor_bullet = 0;
405         }
406         if( mon.armor_acid < 0 ) {
407             mon.armor_acid = mon.armor_cut * 0.5;
408         }
409         if( mon.armor_fire < 0 ) {
410             mon.armor_fire = 0;
411         }
412 
413         // Lower bound for hp scaling
414         mon.hp = std::max( mon.hp, 1 );
415 
416         //If the result monster is blacklisted no need to have the original monster look like it can revive
417         if( !mon.zombify_into.is_empty() &&
418             MonsterGroupManager::monster_is_blacklisted( mon.zombify_into ) ) {
419             mon.zombify_into = mtype_id();
420         }
421 
422         build_behavior_tree( mon );
423         finalize_pathfinding_settings( mon );
424     }
425 
426     for( const auto &mon : mon_templates->get_all() ) {
427         if( !mon.has_flag( MF_NOT_HALLU ) ) {
428             hallucination_monsters.push_back( mon.id );
429         }
430     }
431 }
432 
apply_species_attributes(mtype & mon)433 void MonsterGenerator::apply_species_attributes( mtype &mon )
434 {
435     for( const auto &spec : mon.species ) {
436         if( !spec.is_valid() ) {
437             continue;
438         }
439         const species_type &mspec = spec.obj();
440 
441         mon.flags |= mspec.flags;
442         mon.anger |= mspec.anger;
443         mon.fear |= mspec.fear;
444         mon.placate |= mspec.placate;
445     }
446 }
447 
finalize_pathfinding_settings(mtype & mon)448 void MonsterGenerator::finalize_pathfinding_settings( mtype &mon )
449 {
450     if( mon.path_settings.max_length < 0 ) {
451         mon.path_settings.max_length = mon.path_settings.max_dist * 5;
452     }
453 
454     if( mon.path_settings.bash_strength < 0 ) {
455         mon.path_settings.bash_strength = mon.bash_skill;
456     }
457 
458     if( mon.has_flag( MF_CLIMBS ) ) {
459         mon.path_settings.climb_cost = 3;
460     }
461 }
462 
init_phases()463 void MonsterGenerator::init_phases()
464 {
465     phase_map["NULL"] = phase_id::PNULL;
466     phase_map["SOLID"] = phase_id::SOLID;
467     phase_map["LIQUID"] = phase_id::LIQUID;
468     phase_map["GAS"] = phase_id::GAS;
469     phase_map["PLASMA"] = phase_id::PLASMA;
470 }
471 
init_death()472 void MonsterGenerator::init_death()
473 {
474     // Drop a body
475     death_map["NORMAL"] = &mdeath::normal;
476     // Explodes in gibs and chunks
477     death_map["SPLATTER"] = &mdeath::splatter;
478     // Acid instead of a body
479     death_map["ACID"] = &mdeath::acid;
480     // Explodes in vomit :3
481     death_map["BOOMER"] = &mdeath::boomer;
482     // Explodes in glowing vomit :3
483     death_map["BOOMER_GLOW"] = &mdeath::boomer_glow;
484     // Kill all nearby vines
485     death_map["KILL_VINES"] = &mdeath::kill_vines;
486     // Kill adjacent vine if it's cut
487     death_map["VINE_CUT"] = &mdeath::vine_cut;
488     // Destroy all roots
489     death_map["TRIFFID_HEART"] = &mdeath::triffid_heart;
490     // Explodes in spores D:
491     death_map["FUNGUS"] = &mdeath::fungus;
492     // Falls apart
493     death_map["DISINTEGRATE"] = &mdeath::disintegrate;
494     // Spawns 2 half-worms
495     death_map["WORM"] = &mdeath::worm;
496     // Hallucination disappears
497     death_map["DISAPPEAR"] = &mdeath::disappear;
498     // Morale penalty
499     death_map["GUILT"] = &mdeath::guilt;
500     // Frees blobs, redirects to brainblob()
501     death_map["BRAINBLOB"] = &mdeath::brainblob;
502     // Creates more blobs
503     death_map["BLOBSPLIT"] = &mdeath::blobsplit;
504     // Reverts dancers
505     death_map["JACKSON"] = &mdeath::jackson;
506     // Normal death, but melts
507     death_map["MELT"] = &mdeath::melt;
508     // Removes hypnosis if last one
509     death_map["AMIGARA"] = &mdeath::amigara;
510     // Turn into a full thing
511     death_map["THING"] = &mdeath::thing;
512     // Damaging explosion
513     death_map["EXPLODE"] = &mdeath::explode;
514     // Blinding ray
515     death_map["FOCUSEDBEAM"] = &mdeath::focused_beam;
516     // Spawns a broken robot.
517     death_map["BROKEN"] = &mdeath::broken;
518     // Cure verminitis
519     death_map["RATKING"] = &mdeath::ratking;
520     // Sight returns to normal
521     death_map["DARKMAN"] = &mdeath::darkman;
522     // Explodes in toxic gas
523     death_map["GAS"] = &mdeath::gas;
524     // All breathers die
525     death_map["KILL_BREATHERS"] = &mdeath::kill_breathers;
526     // Gives a message about destroying ammo and then calls "BROKEN"
527     death_map["BROKEN_AMMO"] = &mdeath::broken_ammo;
528     // Explode like a huge smoke bomb.
529     death_map["SMOKEBURST"] = &mdeath::smokeburst;
530     // Explode with a cloud of fungal haze.
531     death_map["FUNGALBURST"] = &mdeath::fungalburst;
532     // Snicker-snack!
533     death_map["JABBERWOCKY"] = &mdeath::jabberwock;
534     // Game over!  Defense mode
535     death_map["GAMEOVER"] = &mdeath::gameover;
536     // Spawn some cockroach nymphs
537     death_map["PREG_ROACH"] = &mdeath::preg_roach;
538     // Explode in a fireball
539     death_map["FIREBALL"] = &mdeath::fireball;
540     // Explode in a huge fireball
541     death_map["CONFLAGRATION"] = &mdeath::conflagration;
542     // resurrect all zombies in the area and upgrade all zombies in the area
543     death_map["NECRO_BOOMER"] = &mdeath::necro_boomer;
544 
545     /* Currently Unimplemented */
546     // Screams loudly
547     //death_map["SHRIEK"] = &mdeath::shriek;
548     // Wolf's howling
549     //death_map["HOWL"] = &mdeath::howl;
550     // Rattles like a rattlesnake
551     //death_map["RATTLE"] = &mdeath::rattle;
552 }
553 
init_attack()554 void MonsterGenerator::init_attack()
555 {
556     add_hardcoded_attack( "NONE", mattack::none );
557     add_hardcoded_attack( "EAT_CROP", mattack::eat_crop );
558     add_hardcoded_attack( "EAT_FOOD", mattack::eat_food );
559     add_hardcoded_attack( "ANTQUEEN", mattack::antqueen );
560     add_hardcoded_attack( "CHECK_UP", mattack::nurse_check_up );
561     add_hardcoded_attack( "ASSIST", mattack::nurse_assist );
562     add_hardcoded_attack( "OPERATE", mattack::nurse_operate );
563     add_hardcoded_attack( "PAID_BOT", mattack::check_money_left );
564     add_hardcoded_attack( "SHRIEK", mattack::shriek );
565     add_hardcoded_attack( "SHRIEK_ALERT", mattack::shriek_alert );
566     add_hardcoded_attack( "SHRIEK_STUN", mattack::shriek_stun );
567     add_hardcoded_attack( "RATTLE", mattack::rattle );
568     add_hardcoded_attack( "HOWL", mattack::howl );
569     add_hardcoded_attack( "ACID", mattack::acid );
570     add_hardcoded_attack( "ACID_BARF", mattack::acid_barf );
571     add_hardcoded_attack( "ACID_ACCURATE", mattack::acid_accurate );
572     add_hardcoded_attack( "SHOCKSTORM", mattack::shockstorm );
573     add_hardcoded_attack( "SHOCKING_REVEAL", mattack::shocking_reveal );
574     add_hardcoded_attack( "PULL_METAL_WEAPON", mattack::pull_metal_weapon );
575     add_hardcoded_attack( "BOOMER", mattack::boomer );
576     add_hardcoded_attack( "BOOMER_GLOW", mattack::boomer_glow );
577     add_hardcoded_attack( "RESURRECT", mattack::resurrect );
578     add_hardcoded_attack( "SMASH", mattack::smash );
579     add_hardcoded_attack( "SCIENCE", mattack::science );
580     add_hardcoded_attack( "GROWPLANTS", mattack::growplants );
581     add_hardcoded_attack( "GROW_VINE", mattack::grow_vine );
582     add_hardcoded_attack( "VINE", mattack::vine );
583     add_hardcoded_attack( "SPIT_SAP", mattack::spit_sap );
584     add_hardcoded_attack( "TRIFFID_HEARTBEAT", mattack::triffid_heartbeat );
585     add_hardcoded_attack( "FUNGUS", mattack::fungus );
586     add_hardcoded_attack( "FUNGUS_CORPORATE", mattack::fungus_corporate );
587     add_hardcoded_attack( "FUNGUS_HAZE", mattack::fungus_haze );
588     add_hardcoded_attack( "FUNGUS_BIG_BLOSSOM", mattack::fungus_big_blossom );
589     add_hardcoded_attack( "FUNGUS_INJECT", mattack::fungus_inject );
590     add_hardcoded_attack( "FUNGUS_BRISTLE", mattack::fungus_bristle );
591     add_hardcoded_attack( "FUNGUS_GROWTH", mattack::fungus_growth );
592     add_hardcoded_attack( "FUNGUS_SPROUT", mattack::fungus_sprout );
593     add_hardcoded_attack( "FUNGUS_FORTIFY", mattack::fungus_fortify );
594     add_hardcoded_attack( "DERMATIK", mattack::dermatik );
595     add_hardcoded_attack( "DERMATIK_GROWTH", mattack::dermatik_growth );
596     add_hardcoded_attack( "FUNGAL_TRAIL", mattack::fungal_trail );
597     add_hardcoded_attack( "PLANT", mattack::plant );
598     add_hardcoded_attack( "DISAPPEAR", mattack::disappear );
599     add_hardcoded_attack( "FORMBLOB", mattack::formblob );
600     add_hardcoded_attack( "CALLBLOBS", mattack::callblobs );
601     add_hardcoded_attack( "JACKSON", mattack::jackson );
602     add_hardcoded_attack( "DANCE", mattack::dance );
603     add_hardcoded_attack( "DOGTHING", mattack::dogthing );
604     add_hardcoded_attack( "TENTACLE", mattack::tentacle );
605     add_hardcoded_attack( "GENE_STING", mattack::gene_sting );
606     add_hardcoded_attack( "PARA_STING", mattack::para_sting );
607     add_hardcoded_attack( "TRIFFID_GROWTH", mattack::triffid_growth );
608     add_hardcoded_attack( "STARE", mattack::stare );
609     add_hardcoded_attack( "FEAR_PARALYZE", mattack::fear_paralyze );
610     add_hardcoded_attack( "PHOTOGRAPH", mattack::photograph );
611     add_hardcoded_attack( "TAZER", mattack::tazer );
612     add_hardcoded_attack( "SEARCHLIGHT", mattack::searchlight );
613     add_hardcoded_attack( "SPEAKER", mattack::speaker );
614     add_hardcoded_attack( "FLAMETHROWER", mattack::flamethrower );
615     add_hardcoded_attack( "COPBOT", mattack::copbot );
616     add_hardcoded_attack( "CHICKENBOT", mattack::chickenbot );
617     add_hardcoded_attack( "MULTI_ROBOT", mattack::multi_robot );
618     add_hardcoded_attack( "RATKING", mattack::ratking );
619     add_hardcoded_attack( "GENERATOR", mattack::generator );
620     add_hardcoded_attack( "UPGRADE", mattack::upgrade );
621     add_hardcoded_attack( "BREATHE", mattack::breathe );
622     add_hardcoded_attack( "IMPALE", mattack::impale );
623     add_hardcoded_attack( "BRANDISH", mattack::brandish );
624     add_hardcoded_attack( "FLESH_GOLEM", mattack::flesh_golem );
625     add_hardcoded_attack( "ABSORB_MEAT", mattack::absorb_meat );
626     add_hardcoded_attack( "LUNGE", mattack::lunge );
627     add_hardcoded_attack( "LONGSWIPE", mattack::longswipe );
628     add_hardcoded_attack( "PARROT", mattack::parrot );
629     add_hardcoded_attack( "PARROT_AT_DANGER", mattack::parrot_at_danger );
630     add_hardcoded_attack( "DARKMAN", mattack::darkman );
631     add_hardcoded_attack( "SLIMESPRING", mattack::slimespring );
632     add_hardcoded_attack( "EVOLVE_KILL_STRIKE", mattack::evolve_kill_strike );
633     add_hardcoded_attack( "LEECH_SPAWNER", mattack::leech_spawner );
634     add_hardcoded_attack( "MON_LEECH_EVOLUTION", mattack::mon_leech_evolution );
635     add_hardcoded_attack( "TINDALOS_TELEPORT", mattack::tindalos_teleport );
636     add_hardcoded_attack( "FLESH_TENDRIL", mattack::flesh_tendril );
637     add_hardcoded_attack( "BIO_OP_BIOJUTSU", mattack::bio_op_random_biojutsu );
638     add_hardcoded_attack( "BIO_OP_TAKEDOWN", mattack::bio_op_takedown );
639     add_hardcoded_attack( "BIO_OP_IMPALE", mattack::bio_op_impale );
640     add_hardcoded_attack( "BIO_OP_DISARM", mattack::bio_op_disarm );
641     add_hardcoded_attack( "SUICIDE", mattack::suicide );
642     add_hardcoded_attack( "KAMIKAZE", mattack::kamikaze );
643     add_hardcoded_attack( "GRENADIER", mattack::grenadier );
644     add_hardcoded_attack( "GRENADIER_ELITE", mattack::grenadier_elite );
645     add_hardcoded_attack( "RIOTBOT", mattack::riotbot );
646     add_hardcoded_attack( "STRETCH_ATTACK", mattack::stretch_attack );
647     add_hardcoded_attack( "STRETCH_BITE", mattack::stretch_bite );
648     add_hardcoded_attack( "RANGED_PULL", mattack::ranged_pull );
649     add_hardcoded_attack( "GRAB", mattack::grab );
650     add_hardcoded_attack( "GRAB_DRAG", mattack::grab_drag );
651     add_hardcoded_attack( "DOOT", mattack::doot );
652     add_hardcoded_attack( "ZOMBIE_FUSE", mattack::zombie_fuse );
653 }
654 
init_defense()655 void MonsterGenerator::init_defense()
656 {
657     // No special attack-back
658     defense_map["NONE"] = &mdefense::none;
659     // Shock attacker on hit
660     defense_map["ZAPBACK"] = &mdefense::zapback;
661     // Splash acid on the attacker
662     defense_map["ACIDSPLASH"] = &mdefense::acidsplash;
663     // Blind fire on unseen attacker
664     defense_map["RETURN_FIRE"] = &mdefense::return_fire;
665 }
666 
validate_species_ids(mtype & mon)667 void MonsterGenerator::validate_species_ids( mtype &mon )
668 {
669     for( const auto &s : mon.species ) {
670         if( !s.is_valid() ) {
671             debugmsg( "Tried to assign species %s to monster %s, but no entry for the species exists",
672                       s.c_str(), mon.id.c_str() );
673         }
674     }
675 }
676 
load_monster(const JsonObject & jo,const std::string & src)677 void MonsterGenerator::load_monster( const JsonObject &jo, const std::string &src )
678 {
679     mon_templates->load( jo, src );
680 }
681 
load_mon_effect_data(const JsonObject & e)682 mon_effect_data load_mon_effect_data( const JsonObject &e )
683 {
684     return mon_effect_data( efftype_id( e.get_string( "id" ) ), e.get_int( "duration", 0 ),
685                             e.get_bool( "affect_hit_bp", false ),
686                             bodypart_str_id( e.get_string( "bp", "bp_null" ) ),
687                             e.get_bool( "permanent", false ),
688                             e.get_int( "chance", 100 ) );
689 }
690 
691 class mon_attack_effect_reader : public generic_typed_reader<mon_attack_effect_reader>
692 {
693     public:
get_next(JsonIn & jin) const694         mon_effect_data get_next( JsonIn &jin ) const {
695             JsonObject e = jin.get_object();
696             return load_mon_effect_data( e );
697         }
698         template<typename C>
erase_next(JsonIn & jin,C & container) const699         void erase_next( JsonIn &jin, C &container ) const {
700             const efftype_id id = efftype_id( jin.get_string() );
701             reader_detail::handler<C>().erase_if( container, [&id]( const mon_effect_data & e ) {
702                 return e.id == id;
703             } );
704         }
705 };
706 
load(const JsonObject & jo,const std::string & src)707 void mtype::load( const JsonObject &jo, const std::string &src )
708 {
709     bool strict = src == "dda";
710 
711     MonsterGenerator &gen = MonsterGenerator::generator();
712 
713     name.make_plural();
714     mandatory( jo, was_loaded, "name", name );
715 
716     optional( jo, was_loaded, "description", description );
717 
718     assign( jo, "ascii_picture", picture_id );
719 
720     optional( jo, was_loaded, "material", mat, auto_flags_reader<material_id> {} );
721     if( mat.empty() ) { // Assign a default "flesh" material to prevent crash (#48988)
722         mat.emplace_back( material_id( "flesh" ) );
723     }
724     optional( jo, was_loaded, "species", species, auto_flags_reader<species_id> {} );
725     optional( jo, was_loaded, "categories", categories, auto_flags_reader<> {} );
726 
727     // See monfaction.cpp
728     if( !was_loaded || jo.has_member( "default_faction" ) ) {
729         default_faction = mfaction_str_id( jo.get_string( "default_faction" ) );
730     }
731 
732     if( !was_loaded || jo.has_member( "symbol" ) ) {
733         sym = jo.get_string( "symbol" );
734         if( utf8_wrapper( sym ).display_width() != 1 ) {
735             jo.throw_error( "monster symbol should be exactly one console cell width", "symbol" );
736         }
737     }
738     if( was_loaded && jo.has_member( "copy-from" ) && looks_like.empty() ) {
739         looks_like = jo.get_string( "copy-from" );
740     }
741     jo.read( "looks_like", looks_like );
742 
743     assign( jo, "bodytype", bodytype );
744     assign( jo, "color", color );
745     assign( jo, "volume", volume, strict, 0_ml );
746     assign( jo, "weight", weight, strict, 0_gram );
747 
748     optional( jo, was_loaded, "phase", phase, make_flag_reader( gen.phase_map, "phase id" ),
749               phase_id::SOLID );
750 
751     assign( jo, "diff", difficulty_base, strict, 0 );
752     assign( jo, "hp", hp, strict, 1 );
753     assign( jo, "speed", speed, strict, 0 );
754     assign( jo, "aggression", agro, strict, -100, 100 );
755     assign( jo, "morale", morale, strict );
756 
757     assign( jo, "mountable_weight_ratio", mountable_weight_ratio, strict );
758 
759     assign( jo, "attack_cost", attack_cost, strict, 0 );
760     assign( jo, "melee_skill", melee_skill, strict, 0 );
761     assign( jo, "melee_dice", melee_dice, strict, 0 );
762     assign( jo, "melee_dice_sides", melee_sides, strict, 0 );
763 
764     assign( jo, "grab_strength", grab_strength, strict, 0 );
765 
766     assign( jo, "dodge", sk_dodge, strict, 0 );
767     assign( jo, "armor_bash", armor_bash, strict, 0 );
768     assign( jo, "armor_cut", armor_cut, strict, 0 );
769     assign( jo, "armor_bullet", armor_bullet, strict, 0 );
770     assign( jo, "armor_stab", armor_stab, strict, 0 );
771     assign( jo, "armor_acid", armor_acid, strict, 0 );
772     assign( jo, "armor_fire", armor_fire, strict, 0 );
773 
774     assign( jo, "vision_day", vision_day, strict, 0 );
775     assign( jo, "vision_night", vision_night, strict, 0 );
776 
777     optional( jo, was_loaded, "regenerates", regenerates, 0 );
778     optional( jo, was_loaded, "regenerates_in_dark", regenerates_in_dark, false );
779     optional( jo, was_loaded, "regen_morale", regen_morale, false );
780 
781     optional( jo, was_loaded, "starting_ammo", starting_ammo );
782     optional( jo, was_loaded, "luminance", luminance, 0 );
783     optional( jo, was_loaded, "revert_to_itype", revert_to_itype, itype_id() );
784     optional( jo, was_loaded, "attack_effs", atk_effs, mon_attack_effect_reader{} );
785     optional( jo, was_loaded, "mech_weapon", mech_weapon, itype_id() );
786     optional( jo, was_loaded, "mech_str_bonus", mech_str_bonus, 0 );
787     optional( jo, was_loaded, "mech_battery", mech_battery, itype_id() );
788 
789     optional( jo, was_loaded, "zombify_into", zombify_into, auto_flags_reader<mtype_id> {},
790               mtype_id() );
791 
792     // TODO: make this work with `was_loaded`
793     if( jo.has_array( "melee_damage" ) ) {
794         melee_damage = load_damage_instance( jo.get_array( "melee_damage" ) );
795     } else if( jo.has_object( "melee_damage" ) ) {
796         melee_damage = load_damage_instance( jo );
797     }
798 
799     if( jo.has_array( "scents_tracked" ) ) {
800         for( const std::string line : jo.get_array( "scents_tracked" ) ) {
801             scents_tracked.emplace( line );
802         }
803     }
804 
805     if( jo.has_array( "scents_ignored" ) ) {
806         for( const std::string line : jo.get_array( "scents_ignored" ) ) {
807             scents_ignored.emplace( line );
808         }
809     }
810 
811     int bonus_cut = 0;
812     if( jo.has_int( "melee_cut" ) ) {
813         bonus_cut = jo.get_int( "melee_cut" );
814         melee_damage.add_damage( damage_type::CUT, bonus_cut );
815     }
816 
817     if( jo.has_member( "death_drops" ) ) {
818         death_drops =
819             item_group::load_item_group( jo.get_member( "death_drops" ), "distribution",
820                                          "death_drops for mtype " + id.str() );
821     }
822 
823     assign( jo, "harvest", harvest );
824 
825     const auto death_reader = make_flag_reader( gen.death_map, "monster death function" );
826     optional( jo, was_loaded, "death_function", dies, death_reader );
827     if( dies.empty() ) {
828         // TODO: really needed? Is an empty `dies` container not allowed?
829         dies.push_back( mdeath::normal );
830     }
831 
832     if( jo.has_array( "emit_fields" ) ) {
833         JsonArray jar = jo.get_array( "emit_fields" );
834         if( jar.has_string( 0 ) ) { // TEMPORARY until 0.F
835             for( const std::string id : jar ) {
836                 emit_fields.emplace( emit_id( id ), 1_seconds );
837             }
838         } else {
839             while( jar.has_more() ) {
840                 JsonObject obj = jar.next_object();
841                 emit_fields.emplace( emit_id( obj.get_string( "emit_id" ) ),
842                                      read_from_json_string<time_duration>( *obj.get_raw( "delay" ), time_duration::units ) );
843             }
844         }
845     }
846 
847     if( jo.has_member( "special_when_hit" ) ) {
848         JsonArray jsarr = jo.get_array( "special_when_hit" );
849         const auto iter = gen.defense_map.find( jsarr.get_string( 0 ) );
850         if( iter == gen.defense_map.end() ) {
851             jsarr.throw_error( "Invalid monster defense function" );
852         }
853         sp_defense = iter->second;
854         def_chance = jsarr.get_int( 1 );
855     } else if( !was_loaded ) {
856         sp_defense = &mdefense::none;
857         def_chance = 0;
858     }
859 
860     if( !was_loaded || jo.has_member( "special_attacks" ) ) {
861         special_attacks.clear();
862         special_attacks_names.clear();
863         add_special_attacks( jo, "special_attacks", src );
864     } else {
865         // Note: special_attacks left as is, new attacks are added to it!
866         // Note: member name prefixes are compatible with those used by generic_typed_reader
867         if( jo.has_object( "extend" ) ) {
868             JsonObject tmp = jo.get_object( "extend" );
869             tmp.allow_omitted_members();
870             add_special_attacks( tmp, "special_attacks", src );
871         }
872         if( jo.has_object( "delete" ) ) {
873             JsonObject tmp = jo.get_object( "delete" );
874             tmp.allow_omitted_members();
875             remove_special_attacks( tmp, "special_attacks", src );
876         }
877     }
878 
879     // Disable upgrading when JSON contains `"upgrades": false`, but fallback to the
880     // normal behavior (including error checking) if "upgrades" is not boolean or not `false`.
881     if( jo.has_bool( "upgrades" ) && !jo.get_bool( "upgrades" ) ) {
882         upgrade_group = mongroup_id::NULL_ID();
883         upgrade_into = mtype_id::NULL_ID();
884         upgrades = false;
885     } else if( jo.has_member( "upgrades" ) ) {
886         JsonObject up = jo.get_object( "upgrades" );
887         optional( up, was_loaded, "half_life", half_life, -1 );
888         optional( up, was_loaded, "age_grow", age_grow, -1 );
889         optional( up, was_loaded, "into_group", upgrade_group, auto_flags_reader<mongroup_id> {},
890                   mongroup_id::NULL_ID() );
891         optional( up, was_loaded, "into", upgrade_into, auto_flags_reader<mtype_id> {},
892                   mtype_id::NULL_ID() );
893         upgrades = true;
894     }
895 
896     //Reproduction
897     if( jo.has_member( "reproduction" ) ) {
898         JsonObject repro = jo.get_object( "reproduction" );
899         optional( repro, was_loaded, "baby_count", baby_count, -1 );
900         if( repro.has_int( "baby_timer" ) ) {
901             baby_timer = time_duration::from_days( repro.get_int( "baby_timer" ) );
902         } else if( repro.has_string( "baby_timer" ) ) {
903             baby_timer = read_from_json_string<time_duration>( *repro.get_raw( "baby_timer" ),
904                          time_duration::units );
905         }
906         optional( repro, was_loaded, "baby_monster", baby_monster, auto_flags_reader<mtype_id> {},
907                   mtype_id::NULL_ID() );
908         optional( repro, was_loaded, "baby_egg", baby_egg, auto_flags_reader<itype_id> {},
909                   itype_id::NULL_ID() );
910         reproduces = true;
911     }
912 
913     if( jo.has_member( "baby_flags" ) ) {
914         // Because this determines mating season and some monsters have a mating season but not in-game offspring, declare this separately
915         baby_flags.clear();
916         for( const std::string line : jo.get_array( "baby_flags" ) ) {
917             baby_flags.push_back( line );
918         }
919     }
920 
921     if( jo.has_member( "biosignature" ) ) {
922         JsonObject biosig = jo.get_object( "biosignature" );
923         if( biosig.has_int( "biosig_timer" ) ) {
924             biosig_timer = time_duration::from_days( biosig.get_int( "biosig_timer" ) );
925         } else if( biosig.has_string( "biosig_timer" ) ) {
926             biosig_timer = read_from_json_string<time_duration>( *biosig.get_raw( "biosig_timer" ),
927                            time_duration::units );
928         }
929 
930         optional( biosig, was_loaded, "biosig_item", biosig_item, auto_flags_reader<itype_id> {},
931                   itype_id::NULL_ID() );
932         biosignatures = true;
933     }
934 
935     optional( jo, was_loaded, "burn_into", burn_into, auto_flags_reader<mtype_id> {},
936               mtype_id::NULL_ID() );
937 
938     const auto flag_reader = enum_flags_reader<m_flag> { "monster flag" };
939     optional( jo, was_loaded, "flags", flags, flag_reader );
940     // Can't calculate yet - we want all flags first
941     optional( jo, was_loaded, "bash_skill", bash_skill, -1 );
942 
943     const auto trigger_reader = enum_flags_reader<mon_trigger> { "monster trigger" };
944     optional( jo, was_loaded, "anger_triggers", anger, trigger_reader );
945     optional( jo, was_loaded, "placate_triggers", placate, trigger_reader );
946     optional( jo, was_loaded, "fear_triggers", fear, trigger_reader );
947 
948     if( jo.has_member( "path_settings" ) ) {
949         JsonObject jop = jo.get_object( "path_settings" );
950         // Here rather than in pathfinding.cpp because we want monster-specific defaults and was_loaded
951         optional( jop, was_loaded, "max_dist", path_settings.max_dist, 0 );
952         optional( jop, was_loaded, "max_length", path_settings.max_length, -1 );
953         optional( jop, was_loaded, "bash_strength", path_settings.bash_strength, -1 );
954         optional( jop, was_loaded, "allow_open_doors", path_settings.allow_open_doors, false );
955         optional( jop, was_loaded, "avoid_traps", path_settings.avoid_traps, false );
956         optional( jop, was_loaded, "allow_climb_stairs", path_settings.allow_climb_stairs, true );
957         optional( jop, was_loaded, "avoid_sharp", path_settings.avoid_sharp, false );
958     }
959     difficulty = ( melee_skill + 1 ) * melee_dice * ( bonus_cut + melee_sides ) * 0.04 +
960                  ( sk_dodge + 1 ) * ( 3 + armor_bash + armor_cut ) * 0.04 +
961                  ( difficulty_base + special_attacks.size() + 8 * emit_fields.size() );
962     difficulty *= ( hp + speed - attack_cost + ( morale + agro ) * 0.1 ) * 0.01 +
963                   ( vision_day + 2 * vision_night ) * 0.01;
964 }
965 
load_species(const JsonObject & jo,const std::string & src)966 void MonsterGenerator::load_species( const JsonObject &jo, const std::string &src )
967 {
968     mon_species->load( jo, src );
969 }
970 
load(const JsonObject & jo,const std::string &)971 void species_type::load( const JsonObject &jo, const std::string & )
972 {
973     optional( jo, was_loaded, "description", description );
974     optional( jo, was_loaded, "footsteps", footsteps, to_translation( "footsteps." ) );
975     const auto flag_reader = enum_flags_reader<m_flag> { "monster flag" };
976     optional( jo, was_loaded, "flags", flags, flag_reader );
977 
978     const auto trigger_reader = enum_flags_reader<mon_trigger> { "monster trigger" };
979     optional( jo, was_loaded, "anger_triggers", anger, trigger_reader );
980     optional( jo, was_loaded, "placate_triggers", placate, trigger_reader );
981     optional( jo, was_loaded, "fear_triggers", fear, trigger_reader );
982 
983     optional( jo, was_loaded, "bleeds", bleeds, auto_flags_reader<field_type_str_id> {}, fd_null );
984 }
985 
get_all_mtypes() const986 const std::vector<mtype> &MonsterGenerator::get_all_mtypes() const
987 {
988     return mon_templates->get_all();
989 }
990 
get_valid_hallucination() const991 mtype_id MonsterGenerator::get_valid_hallucination() const
992 {
993     return random_entry( hallucination_monsters );
994 }
995 
996 class mattack_hardcoded_wrapper : public mattack_actor
997 {
998     private:
999         mon_action_attack cpp_function;
1000     public:
mattack_hardcoded_wrapper(const mattack_id & id,const mon_action_attack f)1001         mattack_hardcoded_wrapper( const mattack_id &id, const mon_action_attack f )
1002             : mattack_actor( id )
1003             , cpp_function( f ) { }
1004 
1005         ~mattack_hardcoded_wrapper() override = default;
call(monster & m) const1006         bool call( monster &m ) const override {
1007             return cpp_function( &m );
1008         }
clone() const1009         std::unique_ptr<mattack_actor> clone() const override {
1010             return std::make_unique<mattack_hardcoded_wrapper>( *this );
1011         }
1012 
load_internal(const JsonObject &,const std::string &)1013         void load_internal( const JsonObject &, const std::string & ) override {}
1014 };
1015 
mtype_special_attack(const mattack_id & id,const mon_action_attack f)1016 mtype_special_attack::mtype_special_attack( const mattack_id &id, const mon_action_attack f )
1017     : mtype_special_attack( std::make_unique<mattack_hardcoded_wrapper>( id, f ) ) {}
1018 
add_hardcoded_attack(const std::string & type,const mon_action_attack f)1019 void MonsterGenerator::add_hardcoded_attack( const std::string &type, const mon_action_attack f )
1020 {
1021     add_attack( mtype_special_attack( type, f ) );
1022 }
1023 
add_attack(std::unique_ptr<mattack_actor> ptr)1024 void MonsterGenerator::add_attack( std::unique_ptr<mattack_actor> ptr )
1025 {
1026     add_attack( mtype_special_attack( std::move( ptr ) ) );
1027 }
1028 
add_attack(const mtype_special_attack & wrapper)1029 void MonsterGenerator::add_attack( const mtype_special_attack &wrapper )
1030 {
1031     if( attack_map.count( wrapper->id ) > 0 ) {
1032         if( test_mode ) {
1033             debugmsg( "Overwriting monster attack with id %s", wrapper->id.c_str() );
1034         }
1035 
1036         attack_map.erase( wrapper->id );
1037     }
1038 
1039     attack_map.emplace( wrapper->id, wrapper );
1040 }
1041 
create_actor(const JsonObject & obj,const std::string & src) const1042 mtype_special_attack MonsterGenerator::create_actor( const JsonObject &obj,
1043         const std::string &src ) const
1044 {
1045     // Legacy support: tolerate attack types being specified as the type
1046     const std::string type = obj.get_string( "type", "monster_attack" );
1047     const std::string attack_type = obj.get_string( "attack_type", type );
1048 
1049     if( type != "monster_attack" && attack_type != type ) {
1050         obj.throw_error(
1051             R"(Specifying "attack_type" is only allowed when "type" is "monster_attack" or not specified)",
1052             "type" );
1053     }
1054 
1055     std::unique_ptr<mattack_actor> new_attack;
1056     if( attack_type == "monster_attack" ) {
1057         const std::string id = obj.get_string( "id" );
1058         const auto &iter = attack_map.find( id );
1059         if( iter == attack_map.end() ) {
1060             obj.throw_error( "Monster attacks must specify type and/or id", "type" );
1061         }
1062 
1063         new_attack = iter->second->clone();
1064     } else if( attack_type == "leap" ) {
1065         new_attack = std::make_unique<leap_actor>();
1066     } else if( attack_type == "melee" ) {
1067         new_attack = std::make_unique<melee_actor>();
1068     } else if( attack_type == "bite" ) {
1069         new_attack = std::make_unique<bite_actor>();
1070     } else if( attack_type == "gun" ) {
1071         new_attack = std::make_unique<gun_actor>();
1072     } else if( attack_type == "spell" ) {
1073         new_attack = std::make_unique<mon_spellcasting_actor>();
1074     } else {
1075         obj.throw_error( "unknown monster attack", "attack_type" );
1076     }
1077 
1078     new_attack->load( obj, src );
1079     return mtype_special_attack( std::move( new_attack ) );
1080 }
1081 
load(const JsonObject & jo,const std::string & src)1082 void mattack_actor::load( const JsonObject &jo, const std::string &src )
1083 {
1084     bool strict = src == "dda";
1085 
1086     // Legacy support
1087     if( !jo.has_string( "id" ) ) {
1088         id = jo.get_string( "type" );
1089     } else {
1090         // Loading ids can't be strict at the moment, since it has to match the stored version
1091         assign( jo, "id", id, false );
1092     }
1093 
1094     assign( jo, "cooldown", cooldown, strict );
1095 
1096     load_internal( jo, src );
1097     // Set was_loaded manually because we don't have generic_factory to do it for us
1098     was_loaded = true;
1099 }
1100 
load_monster_attack(const JsonObject & jo,const std::string & src)1101 void MonsterGenerator::load_monster_attack( const JsonObject &jo, const std::string &src )
1102 {
1103     add_attack( create_actor( jo, src ) );
1104 }
1105 
add_special_attack(const JsonObject & obj,const std::string & src)1106 void mtype::add_special_attack( const JsonObject &obj, const std::string &src )
1107 {
1108     mtype_special_attack new_attack = MonsterGenerator::generator().create_actor( obj, src );
1109 
1110     if( special_attacks.count( new_attack->id ) > 0 ) {
1111         special_attacks.erase( new_attack->id );
1112         const auto iter = std::find( special_attacks_names.begin(), special_attacks_names.end(),
1113                                      new_attack->id );
1114         if( iter != special_attacks_names.end() ) {
1115             special_attacks_names.erase( iter );
1116         }
1117         if( test_mode ) {
1118             debugmsg( "%s specifies more than one attack of (sub)type %s, ignoring all but the last",
1119                       id.c_str(), new_attack->id.c_str() );
1120         }
1121     }
1122 
1123     special_attacks.emplace( new_attack->id, new_attack );
1124     special_attacks_names.push_back( new_attack->id );
1125 }
1126 
add_special_attack(JsonArray inner,const std::string &)1127 void mtype::add_special_attack( JsonArray inner, const std::string & )
1128 {
1129     MonsterGenerator &gen = MonsterGenerator::generator();
1130     const std::string name = inner.get_string( 0 );
1131     const auto iter = gen.attack_map.find( name );
1132     if( iter == gen.attack_map.end() ) {
1133         inner.throw_error( "Invalid special_attacks" );
1134     }
1135 
1136     if( special_attacks.count( name ) > 0 ) {
1137         special_attacks.erase( name );
1138         const auto iter = std::find( special_attacks_names.begin(), special_attacks_names.end(), name );
1139         if( iter != special_attacks_names.end() ) {
1140             special_attacks_names.erase( iter );
1141         }
1142         if( test_mode ) {
1143             debugmsg( "%s specifies more than one attack of (sub)type %s, ignoring all but the last",
1144                       id.c_str(), name );
1145         }
1146     }
1147     mtype_special_attack new_attack = mtype_special_attack( iter->second );
1148     new_attack.actor->cooldown = inner.get_int( 1 );
1149     special_attacks.emplace( name, new_attack );
1150     special_attacks_names.push_back( name );
1151 }
1152 
add_special_attacks(const JsonObject & jo,const std::string & member,const std::string & src)1153 void mtype::add_special_attacks( const JsonObject &jo, const std::string &member,
1154                                  const std::string &src )
1155 {
1156 
1157     if( !jo.has_array( member ) ) {
1158         return;
1159     }
1160 
1161     for( const JsonValue entry : jo.get_array( member ) ) {
1162         if( entry.test_array() ) {
1163             add_special_attack( entry.get_array(), src );
1164         } else if( entry.test_object() ) {
1165             add_special_attack( entry.get_object(), src );
1166         } else {
1167             entry.throw_error( "array element is neither array nor object." );
1168         }
1169     }
1170 }
1171 
remove_special_attacks(const JsonObject & jo,const std::string & member_name,const std::string &)1172 void mtype::remove_special_attacks( const JsonObject &jo, const std::string &member_name,
1173                                     const std::string & )
1174 {
1175     for( const std::string &name : jo.get_tags( member_name ) ) {
1176         special_attacks.erase( name );
1177         const auto iter = std::find( special_attacks_names.begin(), special_attacks_names.end(), name );
1178         if( iter != special_attacks_names.end() ) {
1179             special_attacks_names.erase( iter );
1180         }
1181     }
1182 }
1183 
check_monster_definitions() const1184 void MonsterGenerator::check_monster_definitions() const
1185 {
1186     for( const auto &mon : mon_templates->get_all() ) {
1187         if( mon.harvest.is_null() && !mon.has_flag( MF_ELECTRONIC ) && !mon.id.is_null() ) {
1188             debugmsg( "monster %s has no harvest entry", mon.id.c_str(), mon.harvest.c_str() );
1189         }
1190         if( mon.has_flag( MF_MILKABLE ) && mon.starting_ammo.empty() ) {
1191             debugmsg( "monster %s is flagged milkable, but has no starting ammo", mon.id.c_str() );
1192         }
1193         if( mon.has_flag( MF_MILKABLE ) && !mon.starting_ammo.empty() &&
1194             !item( mon.starting_ammo.begin()->first ).made_of( phase_id::LIQUID ) ) {
1195             debugmsg( "monster % is flagged milkable, but starting ammo %s is not a liquid type",
1196                       mon.id.c_str(), mon.starting_ammo.begin()->first.str() );
1197         }
1198         if( mon.has_flag( MF_MILKABLE ) && mon.starting_ammo.size() > 1 ) {
1199             debugmsg( "monster % is flagged milkable, but has multiple starting_ammo defined", mon.id.c_str() );
1200         }
1201         for( const species_id &spec : mon.species ) {
1202             if( !spec.is_valid() ) {
1203                 debugmsg( "monster %s has invalid species %s", mon.id.c_str(), spec.c_str() );
1204             }
1205         }
1206         if( !mon.death_drops.is_empty() && !item_group::group_is_defined( mon.death_drops ) ) {
1207             debugmsg( "monster %s has unknown death drop item group: %s", mon.id.c_str(),
1208                       mon.death_drops.c_str() );
1209         }
1210         for( const material_id &m : mon.mat ) {
1211             if( m.str() == "null" || !m.is_valid() ) {
1212                 debugmsg( "monster %s has unknown material: %s", mon.id.c_str(), m.c_str() );
1213             }
1214         }
1215         if( !mon.revert_to_itype.is_empty() && !item::type_is_defined( mon.revert_to_itype ) ) {
1216             debugmsg( "monster %s has unknown revert_to_itype: %s", mon.id.c_str(),
1217                       mon.revert_to_itype.c_str() );
1218         }
1219         if( !mon.zombify_into.is_empty() && !mon.zombify_into.is_valid() ) {
1220             debugmsg( "monster %s has unknown zombify_into: %s", mon.id.c_str(),
1221                       mon.zombify_into.c_str() );
1222         }
1223         if( !mon.picture_id.is_empty() && !mon.picture_id.is_valid() ) {
1224             debugmsg( "monster %s has unknown ascii_picture: %s", mon.id.c_str(),
1225                       mon.picture_id.c_str() );
1226         }
1227         if( !mon.mech_weapon.is_empty() && !item::type_is_defined( mon.mech_weapon ) ) {
1228             debugmsg( "monster %s has unknown mech_weapon: %s", mon.id.c_str(),
1229                       mon.mech_weapon.c_str() );
1230         }
1231         if( !mon.mech_battery.is_empty() && !item::type_is_defined( mon.mech_battery ) ) {
1232             debugmsg( "monster %s has unknown mech_battery: %s", mon.id.c_str(),
1233                       mon.mech_battery.c_str() );
1234         }
1235         if( !mon.harvest.is_valid() ) {
1236             debugmsg( "monster %s has invalid harvest_entry: %s", mon.id.c_str(), mon.harvest.c_str() );
1237         }
1238         for( const scenttype_id &s_id : mon.scents_tracked ) {
1239             if( !s_id.is_empty() && !s_id.is_valid() ) {
1240                 debugmsg( "monster %s has unknown scents_tracked %s", mon.id.c_str(), s_id.c_str() );
1241             }
1242         }
1243         for( const scenttype_id &s_id : mon.scents_ignored ) {
1244             if( !s_id.is_empty() && !s_id.is_valid() ) {
1245                 debugmsg( "monster %s has unknown scents_ignored %s", mon.id.c_str(), s_id.c_str() );
1246             }
1247         }
1248         for( const std::pair<const itype_id, int> &s : mon.starting_ammo ) {
1249             if( !item::type_is_defined( s.first ) ) {
1250                 debugmsg( "starting ammo %s of monster %s is unknown", s.first.c_str(), mon.id.c_str() );
1251             }
1252         }
1253         for( const mon_effect_data &e : mon.atk_effs ) {
1254             if( !e.id.is_valid() ) {
1255                 debugmsg( "attack effect %s of monster %s is unknown", e.id.c_str(), mon.id.c_str() );
1256             }
1257         }
1258 
1259         for( const std::pair<const emit_id, time_duration> &e : mon.emit_fields ) {
1260             const emit_id emid = e.first;
1261             if( !emid.is_valid() ) {
1262                 debugmsg( "monster %s has invalid emit source %s", mon.id.c_str(), emid.c_str() );
1263             }
1264         }
1265 
1266         if( mon.upgrades ) {
1267             if( mon.half_life < 0 && mon.age_grow < 0 ) {
1268                 debugmsg( "half_life %d and age_grow %d (<0) of monster %s is invalid",
1269                           mon.half_life, mon.age_grow, mon.id.c_str() );
1270             }
1271             if( !mon.upgrade_into && !mon.upgrade_group ) {
1272                 debugmsg( "no into nor into_group defined for monster %s", mon.id.c_str() );
1273             }
1274             if( mon.upgrade_into && mon.upgrade_group ) {
1275                 debugmsg( "both into and into_group defined for monster %s", mon.id.c_str() );
1276             }
1277             if( !mon.upgrade_into.is_valid() ) {
1278                 debugmsg( "upgrade_into %s of monster %s is not a valid monster id",
1279                           mon.upgrade_into.c_str(), mon.id.c_str() );
1280             }
1281             if( !mon.upgrade_group.is_valid() ) {
1282                 debugmsg( "upgrade_group %s of monster %s is not a valid monster group id",
1283                           mon.upgrade_group.c_str(), mon.id.c_str() );
1284             }
1285         }
1286 
1287         if( mon.reproduces ) {
1288             if( !mon.baby_timer || *mon.baby_timer <= 0_seconds ) {
1289                 debugmsg( "Time between reproductions (%d) is invalid for %s",
1290                           mon.baby_timer ? to_turns<int>( *mon.baby_timer ) : -1, mon.id.c_str() );
1291             }
1292             if( mon.baby_count < 1 ) {
1293                 debugmsg( "Number of children (%d) is invalid for %s",
1294                           mon.baby_count, mon.id.c_str() );
1295             }
1296             if( !mon.baby_monster && mon.baby_egg.is_null() ) {
1297                 debugmsg( "No baby or egg defined for monster %s", mon.id.c_str() );
1298             }
1299             if( mon.baby_monster && !mon.baby_egg.is_null() ) {
1300                 debugmsg( "Both an egg and a live birth baby are defined for %s", mon.id.c_str() );
1301             }
1302             if( !mon.baby_monster.is_valid() ) {
1303                 debugmsg( "baby_monster %s of monster %s is not a valid monster id",
1304                           mon.baby_monster.c_str(), mon.id.c_str() );
1305             }
1306             if( !item::type_is_defined( mon.baby_egg ) ) {
1307                 debugmsg( "item_id %s of monster %s is not a valid item id",
1308                           mon.baby_egg.c_str(), mon.id.c_str() );
1309             }
1310         }
1311 
1312         if( mon.biosignatures ) {
1313             if( !mon.biosig_timer || *mon.biosig_timer <= 0_seconds ) {
1314                 debugmsg( "Time between biosignature drops (%d) is invalid for %s",
1315                           mon.biosig_timer ? to_turns<int>( *mon.biosig_timer ) : -1, mon.id.c_str() );
1316             }
1317             if( mon.biosig_item.is_null() ) {
1318                 debugmsg( "No biosignature drop defined for monster %s", mon.id.c_str() );
1319             }
1320             if( !item::type_is_defined( mon.biosig_item ) ) {
1321                 debugmsg( "item_id %s of monster %s is not a valid item id",
1322                           mon.biosig_item.c_str(), mon.id.c_str() );
1323             }
1324         }
1325     }
1326 }
1327