bool monster::make_fungus() { char polypick = 0; std::string tid = type->id; if (tid == "mon_ant" || tid == "mon_ant_soldier" || tid == "mon_ant_queen" || tid == "mon_fly" || tid == "mon_bee" || tid == "mon_dermatik") { polypick = 1; }else if (tid == "mon_zombie" || tid == "mon_zombie_shrieker" || tid == "mon_zombie_electric" || tid == "mon_zombie_spitter" || tid == "mon_zombie_dog" || tid == "mon_zombie_brute" || tid == "mon_zombie_hulk"){ polypick = 2; }else if (tid == "mon_boomer" || tid == "mon_zombie_gasbag"){ polypick = 3; }else if (tid == "mon_triffid" || tid == "mon_triffid_young" || tid == "mon_triffid_queen"){ polypick = 4; } switch (polypick) { case 1: // bugs, why do they all turn into fungal ants? poly(GetMType("mon_ant_fungus")); return true; case 2: // zombies, non-boomer poly(GetMType("mon_zombie_fungus")); return true; case 3: poly(GetMType("mon_boomer_fungus")); return true; case 4: poly(GetMType("mon_fungaloid")); return true; default: return true; } }
virtual void select(int entnum, uimenu *menu) { if ( ! started ) { started = true; setup(menu); } if (entnum != lastent) { lastent = entnum; tmp = monster(GetMType(entnum)); if (friendly) { tmp.friendly = -1; } } werase(w_info); tmp.print_info(g, w_info); std::string header = string_format("#%d: %s", entnum, GetMType(entnum)->name.c_str() ); mvwprintz(w_info, 1, ( getmaxx(w_info) - header.size() ) / 2, c_cyan, "%s", header.c_str() ); mvwprintz(w_info, getmaxy(w_info) - 3, 0, c_green, "%s", msg.c_str()); msg = padding; mvwprintw(w_info, getmaxy(w_info) - 2, 0, "[/] find, [f] friendly, [q]uit"); //wrefresh(w_info); // for some reason this makes everything disappear on first run? Not needed, at any rate. }
virtual void select(int entnum, uimenu *menu) override { if ( ! started ) { started = true; setup(menu); } if (entnum != lastent) { lastent = entnum; tmp = monster(GetMType(entnum)); if (friendly) { tmp.friendly = -1; } } werase(w_info); tmp.print_info( w_info, 6, 5, 1 ); std::string header = string_format("#%d: %s", entnum, GetMType(entnum)->nname().c_str()); mvwprintz(w_info, 1, ( getmaxx(w_info) - header.size() ) / 2, c_cyan, "%s", header.c_str()); if( hallucination ) { wprintw( w_info, _( " (hallucination)" ) ); } mvwprintz(w_info, getmaxy(w_info) - 3, 0, c_green, "%s", msg.c_str()); msg = padding; mvwprintw(w_info, getmaxy(w_info) - 2, 0, _("[/] find, [f]riendly, [h]allucination [i]ncrease group, [d]ecrease group, [q]uit")); }
bool monster::make_fungus() { if( is_hallucination() ) { return true; } char polypick = 0; std::string tid = type->id; if (type->in_species("FUNGUS")) { // No friendly-fungalizing ;-) return true; } if (tid == "mon_ant" || tid == "mon_ant_soldier" || tid == "mon_ant_queen" || tid == "mon_fly" || tid == "mon_bee" || tid == "mon_dermatik") { polypick = 1; } else if (tid == "mon_zombie" || tid == "mon_zombie_shrieker" || tid == "mon_zombie_electric" || tid == "mon_zombie_spitter" || tid == "mon_zombie_dog" || tid == "mon_zombie_brute" || tid == "mon_zombie_hulk" || tid == "mon_zombie_soldier" || tid == "mon_zombie_tough" || tid == "mon_zombie_scientist" || tid == "mon_zombie_hunter" || tid == "mon_zombie_child"|| tid == "mon_zombie_bio_op" || tid == "mon_zombie_survivor" || tid == "mon_zombie_fireman" || tid == "mon_zombie_cop" || tid == "mon_zombie_fat" || tid == "mon_zombie_rot" || tid == "mon_zombie_swimmer" || tid == "mon_zombie_grabber" || tid == "mon_zombie_technician" || tid == "mon_zombie_brute_shocker") { polypick = 2; // Necro and Master have enough Goo to resist conversion. // Firefighter, hazmat, and scarred/beekeeper have the PPG on. } else if (tid == "mon_zombie_necro" || tid == "mon_zombie_master" || tid == "mon_zombie_fireman" || tid == "mon_zombie_hazmat" || tid == "mon_beekeeper") { return true; } else if (tid == "mon_boomer" || tid == "mon_zombie_gasbag" || tid == "mon_zombie_smoker") { polypick = 3; } else if (tid == "mon_triffid" || tid == "mon_triffid_young" || tid == "mon_triffid_queen") { polypick = 4; } switch (polypick) { case 1: // bugs, why do they all turn into fungal ants? poly(GetMType("mon_ant_fungus")); return true; case 2: // zombies, non-boomer poly(GetMType("mon_zombie_fungus")); return true; case 3: poly(GetMType("mon_boomer_fungus")); return true; case 4: poly(GetMType("mon_fungaloid")); return true; default: return false; } }
item Single_item_creator::create_single(int birthday, RecursionList &rec) const { item tmp; if (type == S_ITEM) { if (id == "corpse") { tmp.make_corpse("corpse", GetMType("mon_null"), birthday); } else { tmp = item(id, birthday); } } else if (type == S_ITEM_GROUP) { if (std::find(rec.begin(), rec.end(), id) != rec.end()) { debugmsg("recursion in item spawn list %s", id.c_str()); return item(null_item_id, birthday); } rec.push_back(id); Item_spawn_data *isd = item_controller->get_group(id); if (isd == NULL) { debugmsg("unknown item spawn list %s", id.c_str()); return item(null_item_id, birthday); } tmp = isd->create_single(birthday, rec); } else if (type == S_NONE) { return item(null_item_id, birthday); } if (modifier.get() != NULL) { modifier->modify(tmp); } // TODO: change the spawn lists to contain proper references to containers tmp = tmp.in_its_container(); return tmp; }
void trapfunc::shadow(int x, int y) { g->u.add_memorial_log(pgettext("memorial_male", "Triggered a shadow trap."), pgettext("memorial_female", "Triggered a shadow trap.")); monster spawned(GetMType("mon_shadow")); int tries = 0, monx, mony, junk; do { if (one_in(2)) { monx = rng(g->u.posx - 5, g->u.posx + 5); mony = (one_in(2) ? g->u.posy - 5 : g->u.posy + 5); } else { monx = (one_in(2) ? g->u.posx - 5 : g->u.posx + 5); mony = rng(g->u.posy - 5, g->u.posy + 5); } } while (tries < 5 && !g->is_empty(monx, mony) && !g->m.sees(monx, mony, g->u.posx, g->u.posy, 10, junk)); if (tries < 5) { g->add_msg(_("A shadow forms nearby.")); spawned.sp_timeout = rng(2, 10); spawned.spawn(monx, mony); g->add_zombie(spawned); g->m.remove_trap(x, y); } }
void trapfunc::snake(int x, int y) { g->u.add_memorial_log(_("Triggered a shadow snake trap.")); if (one_in(3)) { monster spawned(GetMType("mon_shadow_snake")); int tries = 0, monx, mony, junk; do { if (one_in(2)) { monx = rng(g->u.posx - 5, g->u.posx + 5); mony = (one_in(2) ? g->u.posy - 5 : g->u.posy + 5); } else { monx = (one_in(2) ? g->u.posx - 5 : g->u.posx + 5); mony = rng(g->u.posy - 5, g->u.posy + 5); } } while (tries < 5 && !g->is_empty(monx, mony) && !g->m.sees(monx, mony, g->u.posx, g->u.posy, 10, junk)); if (tries < 5) { g->add_msg(_("A shadowy snake forms nearby.")); spawned.spawn(monx, mony); g->add_zombie(spawned); g->m.remove_trap(x, y); return; } } //~ the sound a snake makes g->sound(x, y, 10, _("ssssssss")); if (one_in(6)) g->m.remove_trap(x, y); }
void mdeath::worm(monster *z) { if (g->u_see(z)) g->add_msg(_("The %s splits in two!"), z->name().c_str()); std::vector <point> wormspots; int wormx, wormy; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { wormx = z->posx() + i; wormy = z->posy() + j; if (g->m.has_flag("DIGGABLE", wormx, wormy) && !(g->u.posx == wormx && g->u.posy == wormy)) { wormspots.push_back(point(wormx, wormy)); } } } int worms = 0; while(worms < 2 && wormspots.size() > 0) { monster worm(GetMType("mon_halfworm")); int rn = rng(0, wormspots.size() - 1); if(-1 == g->mon_at(wormspots[rn])) { worm.spawn(wormspots[rn].x, wormspots[rn].y); g->add_zombie(worm); worms++; } wormspots.erase(wormspots.begin() + rn); } }
void mdeath::ratking(monster *z) { g->u.rem_disease("rat"); if (g->u_see(z)) { add_msg(m_warning, _("Rats suddenly swarm into view.")); } std::vector <point> ratspots; int ratx, raty; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { ratx = z->posx() + i; raty = z->posy() + i; if (g->m.move_cost(ratx, raty) > 0 && g->mon_at(ratx, raty) == -1 && !(g->u.posx == ratx && g->u.posy == raty)) { ratspots.push_back(point(ratx, raty)); } } } int rn; monster rat(GetMType("mon_sewer_rat")); for (int rats = 0; rats < 7 && !ratspots.empty(); rats++) { rn = rng(0, ratspots.size() - 1); rat.spawn(ratspots[rn].x, ratspots[rn].y); g->add_zombie(rat); ratspots.erase(ratspots.begin() + rn); } }
void mdeath::worm(monster *z) { if (g->u_see(z)) { if(z->type->dies.size() == 1) { add_msg(m_good, _("The %s splits in two!"), z->name().c_str()); } else { add_msg(m_warning, _("Two worms crawl out of the %s's corpse."), z->name().c_str()); } } std::vector <point> wormspots; int wormx, wormy; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { wormx = z->posx() + i; wormy = z->posy() + j; if (g->m.has_flag("DIGGABLE", wormx, wormy) && !(g->u.posx == wormx && g->u.posy == wormy)) { wormspots.push_back(point(wormx, wormy)); } } } int worms = 0; while(worms < 2 && !wormspots.empty()) { monster worm(GetMType("mon_halfworm")); int rn = rng(0, wormspots.size() - 1); if(-1 == g->mon_at(wormspots[rn])) { worm.spawn(wormspots[rn].x, wormspots[rn].y); g->add_zombie(worm); worms++; } wormspots.erase(wormspots.begin() + rn); } }
void mdeath::ratking(monster *z) { g->u.remove_effect("rat"); if (g->u_see(z)) { add_msg(m_warning, _("Rats suddenly swarm into view.")); } std::vector <point> ratspots; int ratx, raty; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { ratx = z->posx() + i; raty = z->posy() + j; if (g->is_empty(ratx, raty)) { ratspots.push_back(point(ratx, raty)); } } } monster rat(GetMType("mon_sewer_rat")); for (int rats = 0; rats < 7 && !ratspots.empty(); rats++) { int rn = rng(0, ratspots.size() - 1); point rp = ratspots[rn]; ratspots.erase(ratspots.begin() + rn); rat.spawn(rp.x, rp.y); g->add_zombie(rat); } }
/** Create a new monster of the given type. */ monster *create_monster(std::string mon_type, int x, int y) { monster new_monster(GetMType(mon_type), x, y); if(!g->add_zombie(new_monster)) { return NULL; } else { return &(g->zombie(g->mon_at(x, y))); } }
// mtype = game.monster_type(name) static int game_monster_type(lua_State *L) { const char* parameter1 = (const char*) lua_tostring(L, 1); mtype** monster_type = (mtype**) lua_newuserdata(L, sizeof(mtype*)); *monster_type = GetMType(parameter1); luah_setmetatable(L, "mtype_metatable"); return 1; // 1 return values }
void defense_game::spawn_wave(game *g) { g->add_msg("********"); int diff = initial_difficulty + current_wave * wave_difficulty; bool themed_wave = one_in(SPECIAL_WAVE_CHANCE); // All a single monster type g->u.cash += cash_per_wave + (current_wave - 1) * cash_increase; std::vector<std::string> valid; valid = pick_monster_wave(g); while (diff > 0) { // Clear out any monsters that exceed our remaining difficulty for (int i = 0; i < valid.size(); i++) { if (GetMType(valid[i])->difficulty > diff) { valid.erase(valid.begin() + i); i--; } } if (valid.empty()) { g->add_msg(_("Welcome to Wave %d!"), current_wave); g->add_msg("********"); return; } int rn = rng(0, valid.size() - 1); mtype *type = GetMType(valid[rn]); if (themed_wave) { int num = diff / type->difficulty; if (num >= SPECIAL_WAVE_MIN) { // TODO: Do we want a special message here? for (int i = 0; i < num; i++) spawn_wave_monster(g, type); g->add_msg( special_wave_message(type->name).c_str() ); g->add_msg("********"); return; } else themed_wave = false; // No partially-themed waves } diff -= type->difficulty; spawn_wave_monster(g, type); } g->add_msg(_("Welcome to Wave %d!"), current_wave); g->add_msg("********"); }
void trapfuncm::goo(monster *z, int x, int y) { if (z->type->id == "mon_blob") { z->speed += 15; z->hp = z->speed; } else { z->poly(GetMType("mon_blob")); z->speed -= 15; z->hp = z->speed; } g->m.remove_trap(x, y); }
void mdeath::jackson(monster *z) { for( size_t i = 0; i < g->num_zombies(); i++ ) { monster *candidate = &g->zombie( i ); if(candidate->type->id == "mon_zombie_dancer" ) { candidate->poly(GetMType("mon_zombie_hulk")); candidate->remove_effect("controlled"); } if (g->u_see(z->posx(), z->posy())) { add_msg(m_warning, _("The music stops!")); } } }
bool monster::make_fungus() { char polypick = 0; std::string tid = type->id; if (type->in_species("FUNGUS")) { // No friendly-fungalizing ;-) return true; } if (tid == "mon_ant" || tid == "mon_ant_soldier" || tid == "mon_ant_queen" || tid == "mon_fly" || tid == "mon_bee" || tid == "mon_dermatik") { polypick = 1; } else if (tid == "mon_zombie" || tid == "mon_zombie_shrieker" || tid == "mon_zombie_electric" || tid == "mon_zombie_spitter" || tid == "mon_zombie_dog" || tid == "mon_zombie_brute" || tid == "mon_zombie_hulk" || tid == "mon_zombie_soldier" || tid == "mon_zombie_tough" || tid == "mon_zombie_scientist" || tid == "mon_zombie_hunter" || tid == "mon_zombie_child"|| tid == "mon_zombie_bio_op" || tid == "mon_zombie_survivor" || tid == "mon_zombie_fireman" || tid == "mon_zombie_cop" || tid == "mon_zombie_fat") { polypick = 2; } else if (tid == "mon_boomer" || tid == "mon_zombie_gasbag") { polypick = 3; } else if (tid == "mon_triffid" || tid == "mon_triffid_young" || tid == "mon_triffid_queen") { polypick = 4; } switch (polypick) { case 1: // bugs, why do they all turn into fungal ants? poly(GetMType("mon_ant_fungus")); return true; case 2: // zombies, non-boomer poly(GetMType("mon_zombie_fungus")); return true; case 3: poly(GetMType("mon_boomer_fungus")); return true; case 4: poly(GetMType("mon_fungaloid")); return true; default: return false; } }
void game::wishmonster( const tripoint &p ) { const std::map<std::string, mtype *> montypes = MonsterGenerator::generator().get_all_mtypes(); uimenu wmenu; wmenu.w_x = 0; wmenu.w_width = TERMX; // disabled due to foldstring crash //( TERMX - getmaxx(w_terrain) - 30 > 24 ? getmaxx(w_terrain) : TERMX ); wmenu.pad_right = ( wmenu.w_width - 30 ); wmenu.return_invalid = true; wmenu.selected = uistate.wishmonster_selected; wish_monster_callback *cb = new wish_monster_callback(); wmenu.callback = cb; int i = 0; for( const auto &montype : montypes ) { wmenu.addentry( i, true, 0, "%s", montype.second->nname().c_str() ); wmenu.entries[i].extratxt.txt = montype.second->sym; wmenu.entries[i].extratxt.color = montype.second->color; wmenu.entries[i].extratxt.left = 1; ++i; } do { wmenu.query(); if ( wmenu.ret >= 0 ) { monster mon = monster(GetMType(wmenu.ret)); mon.reset_last_load(); if (cb->friendly) { mon.friendly = -1; } if (cb->hallucination) { mon.hallucination = true; } tripoint spawn = ( p == tripoint_min ? look_around() : p ); if( spawn != tripoint_min ) { std::vector<tripoint> spawn_points = closest_tripoints_first( cb->group, spawn ); for( auto spawn_point : spawn_points ) { mon.spawn( spawn_point ); add_zombie(mon); } cb->msg = _("Monster spawned, choose another or 'q' to quit."); uistate.wishmonster_selected = wmenu.ret; wmenu.redraw(); } } } while ( wmenu.keypress != 'q' && wmenu.keypress != KEY_ESCAPE && wmenu.keypress != ' ' ); delete cb; cb = NULL; return; }
virtual void select(int entnum, uimenu *menu) { if ( ! started ) { started = true; setup(menu); } if (entnum != lastent) { lastent = entnum; tmp = monster(GetMType(entnum)); if (friendly) { tmp.friendly = -1; } } werase(w_info); tmp.print_info(w_info); std::string header = string_format("#%d: %s", entnum, GetMType(entnum)->name.c_str()); mvwprintz(w_info, 1, ( getmaxx(w_info) - header.size() ) / 2, c_cyan, "%s", header.c_str()); mvwprintz(w_info, getmaxy(w_info) - 3, 0, c_green, "%s", msg.c_str()); msg = padding; mvwprintw(w_info, getmaxy(w_info) - 2, 0, _("[/] find, [f] friendly, [q]uit")); }
void game::wishmonster(int x, int y) { const std::map<std::string, mtype *> montypes = MonsterGenerator::generator().get_all_mtypes(); uimenu wmenu; wmenu.w_x = 0; wmenu.w_width = TERMX; // disabled due to foldstring crash //( TERMX - getmaxx(w_terrain) - 30 > 24 ? getmaxx(w_terrain) : TERMX ); wmenu.pad_right = ( wmenu.w_width - 30 ); wmenu.return_invalid = true; wmenu.selected = uistate.wishmonster_selected; wish_monster_callback *cb = new wish_monster_callback(); wmenu.callback = cb; int i = 0; for (std::map<std::string, mtype *>::const_iterator mon = montypes.begin(); mon != montypes.end(); ++mon) { wmenu.addentry( i, true, 0, "%s", mon->second->name.c_str() ); wmenu.entries[i].extratxt.txt = string_format("%c", mon->second->sym); wmenu.entries[i].extratxt.color = mon->second->color; wmenu.entries[i].extratxt.left = 1; ++i; } do { wmenu.query(); if ( wmenu.ret >= 0 ) { monster mon = monster(GetMType(wmenu.ret)); if (cb->friendly) { mon.friendly = -1; } point spawn = ( x == -1 && y == -1 ? look_around() : point ( x, y ) ); if (spawn.x != -1) { mon.spawn(spawn.x, spawn.y); add_zombie(mon); cb->msg = _("Monster spawned, choose another or 'q' to quit."); uistate.wishmonster_selected = wmenu.ret; wmenu.redraw(); } } } while ( wmenu.keypress != 'q' && wmenu.keypress != KEY_ESCAPE && wmenu.keypress != ' ' ); delete cb; cb = NULL; return; }
void mdeath::blobsplit(monster *z) { int speed = z->speed - rng(30, 50); g->m.spawn_item(z->posx(), z->posy(), "slime_scrap", 1, 0, calendar::turn, rng(1, 4)); if (speed <= 0) { if (g->u_see(z)) { // TODO: Add vermin-tagged tiny versions of the splattered blob :) add_msg(m_good, _("The %s splatters apart."), z->name().c_str()); } return; } monster blob(GetMType((speed < 50 ? "mon_blob_small" : "mon_blob"))); blob.speed = speed; // If we're tame, our kids are too blob.friendly = z->friendly; if (g->u_see(z)) { if(z->type->dies.size() == 1) { add_msg(m_good, _("The %s splits in two!"), z->name().c_str()); } else { add_msg(m_bad, _("Two small blobs slither out of the corpse."), z->name().c_str()); } } blob.hp = blob.speed; std::vector <point> valid; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { bool moveOK = (g->m.move_cost(z->posx() + i, z->posy() + j) > 0); bool monOK = g->mon_at(z->posx() + i, z->posy() + j) == -1; bool posOK = (g->u.posx != z->posx() + i || g->u.posy != z->posy() + j); if (moveOK && monOK && posOK) { valid.push_back(point(z->posx() + i, z->posy() + j)); } } } int rn; for (int s = 0; s < 2 && !valid.empty(); s++) { rn = rng(0, valid.size() - 1); blob.spawn(valid[rn].x, valid[rn].y); g->add_zombie(blob); valid.erase(valid.begin() + rn); } }
void event::per_turn() { switch (type) { case EVENT_WANTED: { // About once every 10 minutes. Suppress in classic zombie mode. if (g->levz >= 0 && one_in(100) && !ACTIVE_WORLD_OPTIONS["CLASSIC_ZOMBIES"]) { monster eyebot(GetMType("mon_eyebot")); eyebot.faction_id = faction_id; point place = g->m.random_outdoor_tile(); if (place.x == -1 && place.y == -1) return; // We're safely indoors! eyebot.spawn(place.x, place.y); g->add_zombie(eyebot); if (g->u_see(place.x, place.y)) add_msg(_("An eyebot swoops down nearby!")); } } break; case EVENT_SPAWN_WYRMS: if (g->levz >= 0) { turn--; return; } if (int(calendar::turn) % 3 == 0) add_msg(_("You hear screeches from the rock above and around you!")); break; case EVENT_AMIGARA: add_msg(_("The entire cavern shakes!")); break; case EVENT_TEMPLE_OPEN: add_msg(_("The earth rumbles.")); break; default: break; // Nothing happens for other events } }
void monster::deserialize(JsonIn &jsin) { JsonObject data = jsin.get_object(); int iidtmp; std::string sidtmp; // load->str->int if ( ! data.read("typeid", sidtmp) ) { // or load->int->str->possibly_shifted_int data.read("typeid", iidtmp); sidtmp = legacy_mon_id[ iidtmp ]; } type = GetMType(sidtmp); data.read("posx", _posx); data.read("posy", _posy); data.read("wandx", wandx); data.read("wandy", wandy); data.read("wandf", wandf); data.read("moves", moves); data.read("speed", speed); data.read("hp", hp); data.read("sp_timeout", sp_timeout); data.read("friendly", friendly); data.read("faction_id", faction_id); data.read("mission_id", mission_id); data.read("no_extra_death_drops", no_extra_death_drops); data.read("dead", dead); data.read("anger", anger); data.read("morale", morale); data.read("hallucination", hallucination); data.read("onstairs", onstairs); data.read("stairscount", staircount); // really? data.read("plans", plans); data.read("effects", effects); data.read("inv", inv); if (!data.read("ammo", ammo)) { ammo = 100; } }
// fish-with-rod fish catching function. static void rod_fish( player *p, int sSkillLevel, int fishChance ) { if( sSkillLevel > fishChance ) { std::vector<monster *> fishables = g->get_fishable(60); //get the nearby fish list. //if the vector is empty (no fish around) the player is still given a small chance to get a (let us say it was hidden) fish if( fishables.size() < 1 ) { if( one_in(20) ) { item fish; std::vector<std::string> fish_group = MonsterGroupManager::GetMonstersFromGroup( mongroup_id( "GROUP_FISH" ) ); std::string fish_mon = fish_group[rng(1, fish_group.size()) - 1]; fish.make_corpse( fish_mon, calendar::turn ); g->m.add_item_or_charges(p->pos(), fish); p->add_msg_if_player(m_good, _("You caught a %s."), GetMType(fish_mon)->nname().c_str()); } else { p->add_msg_if_player(_("You didn't catch anything.")); } } else { g->catch_a_monster(fishables, p->pos3(), p, 30000); } } else { p->add_msg_if_player(_("You didn't catch anything.")); } }
void event::actualize() { switch( type ) { case EVENT_HELP: debugmsg("Currently disabled while NPC and monster factions are being rewritten."); /* { int num = 1; if( faction_id >= 0 ) { num = rng( 1, 6 ); } for( int i = 0; i < num; i++ ) { npc *temp = new npc(); temp->normalize(); if( faction_id != -1 ) { faction *fac = g->faction_by_id( faction_id ); if( fac ) { temp->randomize_from_faction( fac ); } else { debugmsg( "EVENT_HELP run with invalid faction_id" ); temp->randomize(); } } else { temp->randomize(); } temp->attitude = NPCATT_DEFEND; // important: npc::spawn_at must be called to put the npc into the overmap temp->spawn_at( g->get_abs_levx(), g->get_abs_levy(), g->get_abs_levz() ); // spawn at the border of the reality bubble, outside of the players view if( one_in( 2 ) ) { temp->posx = rng( 0, SEEX * MAPSIZE - 1 ); temp->posy = rng( 0, 1 ) * SEEY * MAPSIZE; } else { temp->posx = rng( 0, 1 ) * SEEX * MAPSIZE; temp->posy = rng( 0, SEEY * MAPSIZE - 1 ); } // And tell the npc to go to the player. temp->goal.x = g->om_global_location().x; temp->goal.y = g->om_global_location().y; // The npcs will be loaded later by game::load_npcs() } } */ break; case EVENT_ROBOT_ATTACK: { if (rl_dist(g->get_abs_levx(), g->get_abs_levy(), map_point.x, map_point.y) <= 4) { mtype *robot_type = GetMType("mon_tripod"); if (faction_id == 0) { // The cops! if (one_in(2)) { robot_type = GetMType("mon_copbot"); } else { robot_type = GetMType("mon_riotbot"); } g->u.add_memorial_log(pgettext("memorial_male", "Became wanted by the police!"), pgettext("memorial_female", "Became wanted by the police!")); } monster robot(robot_type); int robx = (g->get_abs_levx() > map_point.x ? 0 - SEEX * 2 : SEEX * 4), roby = (g->get_abs_levy() > map_point.y ? 0 - SEEY * 2 : SEEY * 4); robot.spawn(robx, roby); g->add_zombie(robot); } } break; case EVENT_SPAWN_WYRMS: { if (g->levz >= 0) return; g->u.add_memorial_log(pgettext("memorial_male", "Awoke a group of dark wyrms!"), pgettext("memorial_female", "Awoke a group of dark wyrms!")); monster wyrm(GetMType("mon_dark_wyrm")); int num_wyrms = rng(1, 4); for (int i = 0; i < num_wyrms; i++) { int tries = 0; int monx = -1, mony = -1; do { monx = rng(0, SEEX * MAPSIZE); mony = rng(0, SEEY * MAPSIZE); tries++; } while (tries < 10 && !g->is_empty(monx, mony) && rl_dist(g->u.posx, g->u.posy, monx, mony) <= 2); if (tries < 10) { wyrm.spawn(monx, mony); g->add_zombie(wyrm); } } if (!one_in(25)) // They just keep coming! g->add_event(EVENT_SPAWN_WYRMS, int(calendar::turn) + rng(15, 25)); } break; case EVENT_AMIGARA: { g->u.add_memorial_log(pgettext("memorial_male", "Angered a group of amigara horrors!"), pgettext("memorial_female", "Angered a group of amigara horrors!")); int num_horrors = rng(3, 5); int faultx = -1, faulty = -1; bool horizontal = false; for (int x = 0; x < SEEX * MAPSIZE && faultx == -1; x++) { for (int y = 0; y < SEEY * MAPSIZE && faulty == -1; y++) { if (g->m.ter(x, y) == t_fault) { faultx = x; faulty = y; if (g->m.ter(x - 1, y) == t_fault || g->m.ter(x + 1, y) == t_fault) horizontal = true; else horizontal = false; } } } monster horror(GetMType("mon_amigara_horror")); for (int i = 0; i < num_horrors; i++) { int tries = 0; int monx = -1, mony = -1; do { if (horizontal) { monx = rng(faultx, faultx + 2 * SEEX - 8); for (int n = -1; n <= 1; n++) { if (g->m.ter(monx, faulty + n) == t_rock_floor) mony = faulty + n; } } else { // Vertical fault mony = rng(faulty, faulty + 2 * SEEY - 8); for (int n = -1; n <= 1; n++) { if (g->m.ter(faultx + n, mony) == t_rock_floor) monx = faultx + n; } } tries++; } while ((monx == -1 || mony == -1 || g->is_empty(monx, mony)) && tries < 10); if (tries < 10) { horror.spawn(monx, mony); g->add_zombie(horror); } } } break; case EVENT_ROOTS_DIE: g->u.add_memorial_log(pgettext("memorial_male", "Destroyed a triffid grove."), pgettext("memorial_female", "Destroyed a triffid grove.")); for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) { if (g->m.ter(x, y) == t_root_wall && one_in(3)) g->m.ter_set(x, y, t_underbrush); } } break; case EVENT_TEMPLE_OPEN: { g->u.add_memorial_log(pgettext("memorial_male", "Opened a strange temple."), pgettext("memorial_female", "Opened a strange temple.")); bool saw_grate = false; for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) { if (g->m.ter(x, y) == t_grate) { g->m.ter_set(x, y, t_stairs_down); if (!saw_grate && g->u_see(x, y)) saw_grate = true; } } } if (saw_grate) add_msg(_("The nearby grates open to reveal a staircase!")); } break; case EVENT_TEMPLE_FLOOD: { bool flooded = false; ter_id flood_buf[SEEX*MAPSIZE][SEEY*MAPSIZE]; for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) flood_buf[x][y] = g->m.ter(x, y); } for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) { if (g->m.ter(x, y) == t_water_sh) { bool deepen = false; for (int wx = x - 1; wx <= x + 1 && !deepen; wx++) { for (int wy = y - 1; wy <= y + 1 && !deepen; wy++) { if (g->m.ter(wx, wy) == t_water_dp) deepen = true; } } if (deepen) { flood_buf[x][y] = t_water_dp; flooded = true; } } else if (g->m.ter(x, y) == t_rock_floor) { bool flood = false; for (int wx = x - 1; wx <= x + 1 && !flood; wx++) { for (int wy = y - 1; wy <= y + 1 && !flood; wy++) { if (g->m.ter(wx, wy) == t_water_dp || g->m.ter(wx, wy) == t_water_sh) flood = true; } } if (flood) { flood_buf[x][y] = t_water_sh; flooded = true; } } } } if (!flooded) return; // We finished flooding the entire chamber! // Check if we should print a message if (flood_buf[g->u.posx][g->u.posy] != g->m.ter(g->u.posx, g->u.posy)) { if (flood_buf[g->u.posx][g->u.posy] == t_water_sh) { add_msg(m_warning, _("Water quickly floods up to your knees.")); g->u.add_memorial_log(pgettext("memorial_male", "Water level reached knees."), pgettext("memorial_female", "Water level reached knees.")); } else { // Must be deep water! add_msg(m_warning, _("Water fills nearly to the ceiling!")); g->u.add_memorial_log(pgettext("memorial_male", "Water level reached the ceiling."), pgettext("memorial_female", "Water level reached the ceiling.")); g->plswim(g->u.posx, g->u.posy); } } // flood_buf is filled with correct tiles; now copy them back to g->m for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) g->m.ter_set(x, y, flood_buf[x][y]); } g->add_event(EVENT_TEMPLE_FLOOD, int(calendar::turn) + rng(2, 3)); } break; case EVENT_TEMPLE_SPAWN: { std::string montype = "mon_null"; switch (rng(1, 4)) { case 1: montype = "mon_sewer_snake"; break; case 2: montype = "mon_centipede"; break; case 3: montype = "mon_dermatik"; break; case 4: montype = "mon_spider_widow_giant"; break; } monster spawned( GetMType(montype) ); int tries = 0, x, y; do { x = rng(g->u.posx - 5, g->u.posx + 5); y = rng(g->u.posy - 5, g->u.posy + 5); tries++; } while (tries < 20 && !g->is_empty(x, y) && rl_dist(x, y, g->u.posx, g->u.posy) <= 2); if (tries < 20) { spawned.spawn(x, y); g->add_zombie(spawned); } } break; default: break; // Nothing happens for other events } }
void mdeath::thing(monster *z) { monster thing(GetMType("mon_thing")); thing.spawn(z->posx(), z->posy()); g->add_zombie(thing); }
void mdeath::fungus(monster *z) { monster spore(GetMType("mon_spore")); bool fungal = false; int mondex = -1; int sporex, sporey; //~ the sound of a fungus dying g->sound(z->posx(), z->posy(), 10, _("Pouf!")); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { sporex = z->posx() + i; sporey = z->posy() + j; mondex = g->mon_at(sporex, sporey); if (g->m.move_cost(sporex, sporey) > 0) { if (mondex != -1) { // Spores hit a monster fungal = g->zombie(mondex).type->in_species("FUNGUS"); if (g->u_see(sporex, sporey) && !fungal) { add_msg(_("The %s is covered in tiny spores!"), g->zombie(mondex).name().c_str()); } monster &critter = g->zombie( mondex ); if( !critter.make_fungus() ) { critter.die( z ); // counts as kill by monster z } } else if (g->u.posx == sporex && g->u.posy == sporey) { // Spores hit the player if (g->u.has_trait("TAIL_CATTLE") && one_in(20 - g->u.dex_cur - g->u.skillLevel("melee"))) { add_msg(_("The spores land on you, but you quickly swat them off with your tail!")); return; } bool hit = false; if (one_in(4) && g->u.infect("spores", bp_head, 3, 90, false, 1, 3, 120, 1, true)) { hit = true; } if (one_in(2) && g->u.infect("spores", bp_torso, 3, 90, false, 1, 3, 120, 1, true)) { hit = true; } if (one_in(4) && g->u.infect("spores", bp_arm_l, 3, 90, false, 1, 3, 120, 1, true)) { hit = true; } if (one_in(4) && g->u.infect("spores", bp_arm_r, 3, 90, false, 1, 3, 120, 1, true)) { hit = true; } if (one_in(4) && g->u.infect("spores", bp_leg_l, 3, 90, false, 1, 3, 120, 1, true)) { hit = true; } if (one_in(4) && g->u.infect("spores", bp_leg_r, 3, 90, false, 1, 3, 120, 1, true)) { hit = true; } if (hit && (g->u.has_trait("TAIL_CATTLE") && one_in(20 - g->u.dex_cur - g->u.skillLevel("melee")))) { add_msg(_("The spores land on you, but you quickly swat them off with your tail!")); hit = false; } if (hit) { add_msg(m_warning, _("You're covered in tiny spores!")); } } else if (one_in(2) && g->num_zombies() <= 1000) { // Spawn a spore spore.spawn(sporex, sporey); g->add_zombie(spore); } } } } }
void event::actualize(game *g) { switch (type) { case EVENT_HELP: { npc tmp; int num = 1; if (faction_id >= 0) num = rng(1, 6); for (int i = 0; i < num; i++) { if (faction_id != -1) { faction* fac = g->faction_by_id(faction_id); if (fac) tmp.randomize_from_faction(g, fac); else debugmsg("EVENT_HELP run with invalid faction_id"); } else tmp.randomize(g); tmp.attitude = NPCATT_DEFEND; tmp.posx = g->u.posx - SEEX * 2 + rng(-5, 5); tmp.posy = g->u.posy - SEEY * 2 + rng(-5, 5); g->active_npc.push_back(&tmp); } } break; case EVENT_ROBOT_ATTACK: { if (rl_dist(g->levx, g->levy, map_point.x, map_point.y) <= 4) { mtype *robot_type = GetMType("mon_tripod"); if (faction_id == 0) { // The cops! robot_type = GetMType("mon_copbot"); g->u.add_memorial_log(_("Became wanted by the police!")); } monster robot(robot_type); int robx = (g->levx > map_point.x ? 0 - SEEX * 2 : SEEX * 4), roby = (g->levy > map_point.y ? 0 - SEEY * 2 : SEEY * 4); robot.spawn(robx, roby); g->add_zombie(robot); } } break; case EVENT_SPAWN_WYRMS: { if (g->levz >= 0) return; g->u.add_memorial_log(_("Awoke a group of dark wyrms!")); monster wyrm(GetMType("mon_dark_wyrm")); int num_wyrms = rng(1, 4); for (int i = 0; i < num_wyrms; i++) { int tries = 0; int monx = -1, mony = -1; do { monx = rng(0, SEEX * MAPSIZE); mony = rng(0, SEEY * MAPSIZE); tries++; } while (tries < 10 && !g->is_empty(monx, mony) && rl_dist(g->u.posx, g->u.posx, monx, mony) <= 2); if (tries < 10) { wyrm.spawn(monx, mony); g->add_zombie(wyrm); } } if (!one_in(25)) // They just keep coming! g->add_event(EVENT_SPAWN_WYRMS, int(g->turn) + rng(15, 25)); } break; case EVENT_AMIGARA: { g->u.add_memorial_log(_("Angered a group of amigara horrors!")); int num_horrors = rng(3, 5); int faultx = -1, faulty = -1; bool horizontal = false; for (int x = 0; x < SEEX * MAPSIZE && faultx == -1; x++) { for (int y = 0; y < SEEY * MAPSIZE && faulty == -1; y++) { if (g->m.ter(x, y) == t_fault) { faultx = x; faulty = y; if (g->m.ter(x - 1, y) == t_fault || g->m.ter(x + 1, y) == t_fault) horizontal = true; else horizontal = false; } } } monster horror(GetMType("mon_amigara_horror")); for (int i = 0; i < num_horrors; i++) { int tries = 0; int monx = -1, mony = -1; do { if (horizontal) { monx = rng(faultx, faultx + 2 * SEEX - 8); for (int n = -1; n <= 1; n++) { if (g->m.ter(monx, faulty + n) == t_rock_floor) mony = faulty + n; } } else { // Vertical fault mony = rng(faulty, faulty + 2 * SEEY - 8); for (int n = -1; n <= 1; n++) { if (g->m.ter(faultx + n, mony) == t_rock_floor) monx = faultx + n; } } tries++; } while ((monx == -1 || mony == -1 || g->is_empty(monx, mony)) && tries < 10); if (tries < 10) { horror.spawn(monx, mony); g->add_zombie(horror); } } } break; case EVENT_ROOTS_DIE: g->u.add_memorial_log(_("Destroyed a triffid grove.")); for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) { if (g->m.ter(x, y) == t_root_wall && one_in(3)) g->m.ter_set(x, y, t_underbrush); } } break; case EVENT_TEMPLE_OPEN: { g->u.add_memorial_log(_("Opened a strange temple.")); bool saw_grate = false; for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) { if (g->m.ter(x, y) == t_grate) { g->m.ter_set(x, y, t_stairs_down); if (!saw_grate && g->u_see(x, y)) saw_grate = true; } } } if (saw_grate) g->add_msg(_("The nearby grates open to reveal a staircase!")); } break; case EVENT_TEMPLE_FLOOD: { bool flooded = false; ter_id flood_buf[SEEX*MAPSIZE][SEEY*MAPSIZE]; for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) flood_buf[x][y] = g->m.ter(x, y); } for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) { if (g->m.ter(x, y) == t_water_sh) { bool deepen = false; for (int wx = x - 1; wx <= x + 1 && !deepen; wx++) { for (int wy = y - 1; wy <= y + 1 && !deepen; wy++) { if (g->m.ter(wx, wy) == t_water_dp) deepen = true; } } if (deepen) { flood_buf[x][y] = t_water_dp; flooded = true; } } else if (g->m.ter(x, y) == t_rock_floor) { bool flood = false; for (int wx = x - 1; wx <= x + 1 && !flood; wx++) { for (int wy = y - 1; wy <= y + 1 && !flood; wy++) { if (g->m.ter(wx, wy) == t_water_dp || g->m.ter(wx, wy) == t_water_sh) flood = true; } } if (flood) { flood_buf[x][y] = t_water_sh; flooded = true; } } } } if (!flooded) return; // We finished flooding the entire chamber! // Check if we should print a message if (flood_buf[g->u.posx][g->u.posy] != g->m.ter(g->u.posx, g->u.posy)) { if (flood_buf[g->u.posx][g->u.posy] == t_water_sh) { g->add_msg(_("Water quickly floods up to your knees.")); g->u.add_memorial_log(_("Water level reached knees.")); } else { // Must be deep water! g->add_msg(_("Water fills nearly to the ceiling!")); g->u.add_memorial_log(_("Water level reached the ceiling.")); g->plswim(g->u.posx, g->u.posy); } } // flood_buf is filled with correct tiles; now copy them back to g->m for (int x = 0; x < SEEX * MAPSIZE; x++) { for (int y = 0; y < SEEY * MAPSIZE; y++) g->m.ter_set(x, y, flood_buf[x][y]); } g->add_event(EVENT_TEMPLE_FLOOD, int(g->turn) + rng(2, 3)); } break; case EVENT_TEMPLE_SPAWN: { std::string montype = "mon_null"; switch (rng(1, 4)) { case 1: montype = "mon_sewer_snake"; break; case 2: montype = "mon_centipede"; break; case 3: montype = "mon_dermatik"; break; case 4: montype = "mon_spider_widow"; break; } monster spawned( GetMType(montype) ); int tries = 0, x, y; do { x = rng(g->u.posx - 5, g->u.posx + 5); y = rng(g->u.posy - 5, g->u.posy + 5); tries++; } while (tries < 20 && !g->is_empty(x, y) && rl_dist(x, y, g->u.posx, g->u.posy) <= 2); if (tries < 20) { spawned.spawn(x, y); g->add_zombie(spawned); } } break; default: break; // Nothing happens for other events } }
void tutorial_game::post_action(action_id act) { switch (act) { case ACTION_RELOAD: if (g->u.weapon.is_gun() && !tutorials_seen[LESSON_GUN_FIRE]) { monster tmp(GetMType("mon_zombie"), tripoint( g->u.posx(), g->u.posy() - 6, g->u.posz() ) ); g->add_zombie(tmp); tmp.spawn(g->u.posx() + 2, g->u.posy() - 5); g->add_zombie(tmp); tmp.spawn(g->u.posx() - 2, g->u.posy() - 5); g->add_zombie(tmp); add_message(LESSON_GUN_FIRE); } break; case ACTION_OPEN: add_message(LESSON_CLOSE); break; case ACTION_CLOSE: add_message(LESSON_SMASH); break; case ACTION_USE: if (g->u.has_amount("grenade_act", 1)) add_message(LESSON_ACT_GRENADE); for (int x = g->u.posx() - 1; x <= g->u.posx() + 1; x++) { for (int y = g->u.posy() - 1; y <= g->u.posy() + 1; y++) { if (g->m.tr_at(x, y) == tr_bubblewrap) add_message(LESSON_ACT_BUBBLEWRAP); } } break; case ACTION_EAT: if (g->u.last_item == "codeine") add_message(LESSON_TOOK_PAINKILLER); else if (g->u.last_item == "cig") add_message(LESSON_TOOK_CIG); else if (g->u.last_item == "water") add_message(LESSON_DRANK_WATER); break; case ACTION_WEAR: { item it( g->u.last_item, 0 ); if (it.is_armor()) { if (it.get_coverage() >= 2 || it.get_thickness() >= 2) add_message(LESSON_WORE_ARMOR); if (it.get_storage() >= 20) add_message(LESSON_WORE_STORAGE); if (it.get_env_resist() >= 2) add_message(LESSON_WORE_MASK); } } break; case ACTION_WIELD: if (g->u.weapon.is_gun()) add_message(LESSON_GUN_LOAD); break; case ACTION_EXAMINE: add_message(LESSON_INTERACT); // Fall through to... case ACTION_PICKUP: { item it( g->u.last_item, 0 ); if (it.is_armor()) add_message(LESSON_GOT_ARMOR); else if (it.is_gun()) add_message(LESSON_GOT_GUN); else if (it.is_ammo()) add_message(LESSON_GOT_AMMO); else if (it.is_tool()) add_message(LESSON_GOT_TOOL); else if (it.is_food()) add_message(LESSON_GOT_FOOD); else if (it.is_weap()) add_message(LESSON_GOT_WEAPON); if (g->u.volume_carried() > g->u.volume_capacity() - 2) add_message(LESSON_OVERLOADED); } break; default: //TODO: add more actions here break; } }
//Quantity is adjusted directly as a side effect of this function MonsterGroupResult MonsterGroupManager::GetResultFromGroup( std::string group_name, int *quantity, int turn ) { int spawn_chance = rng(1, 1000); MonsterGroup group = monsterGroupMap[group_name]; //Our spawn details specify, by default, a single instance of the default monster MonsterGroupResult spawn_details = MonsterGroupResult(group.defaultMonster,1); //If the default monster is too difficult, replace this with "mon_null" if(turn!=-1 && (turn + 900 < MINUTES(STARTING_MINUTES) + HOURS(GetMType(group.defaultMonster)->difficulty))){ spawn_details = MonsterGroupResult("mon_null",0); } bool monster_found = false; // Step through spawn definitions from the monster group until one is found or for (FreqDef_iter it = group.monsters.begin(); it != group.monsters.end() && !monster_found; ++it){ // There's a lot of conditions to work through to see if this spawn definition is valid bool valid_entry = true; // I don't know what turn == -1 is checking for, but it makes monsters always valid for difficulty purposes valid_entry = valid_entry && (turn == -1 || (turn+900) >= (MINUTES(STARTING_MINUTES) + HOURS(GetMType(it->name)->difficulty))); // If we are in classic mode, require the monster type to be either CLASSIC or WILDLIFE if(ACTIVE_WORLD_OPTIONS["CLASSIC_ZOMBIES"]){ valid_entry = valid_entry && (GetMType(it->name)->in_category("CLASSIC") || GetMType(it->name)->in_category("WILDLIFE")); } //Insure that the time is not before the spawn first appears or after it stops appearing valid_entry = valid_entry && (HOURS(it->starts) < g->turn.get_turn()); valid_entry = valid_entry && (it->lasts_forever() || HOURS(it->ends) > g->turn.get_turn()); std::vector<std::pair<int,int> > valid_times_of_day; bool season_limited = false; bool season_matched = false; //Collect the various spawn conditions, and then insure they are met appropriately for(std::vector<std::string>::iterator condition = it->conditions.begin(); condition != it->conditions.end(); ++condition){ //Collect valid time of day ranges if( (*condition) == "DAY" || (*condition) == "NIGHT" || (*condition) == "DUSK" || (*condition) == "DAWN" ){ int sunset = g->turn.sunset().get_turn(); int sunrise = g->turn.sunrise().get_turn(); if((*condition) == "DAY"){ valid_times_of_day.push_back( std::make_pair(sunrise,sunset) ); } else if((*condition) == "NIGHT"){ valid_times_of_day.push_back( std::make_pair(sunset,sunrise) ); } else if((*condition) == "DUSK"){ valid_times_of_day.push_back( std::make_pair(sunset-HOURS(1),sunset+HOURS(1)) ); } else if((*condition) == "DAWN"){ valid_times_of_day.push_back( std::make_pair(sunrise-HOURS(1),sunrise+HOURS(1)) ); } } //If we have any seasons listed, we know to limit by season, and if any season matches this season, we are good to spawn if( (*condition) == "SUMMER" || (*condition) == "WINTER" || (*condition) == "SPRING" || (*condition) == "AUTUMN" ){ season_limited = true; if( (g->turn.get_season() == SUMMER && (*condition) == "SUMMER") || (g->turn.get_season() == WINTER && (*condition) == "WINTER") || (g->turn.get_season() == SPRING && (*condition) == "SPRING") || (g->turn.get_season() == AUTUMN && (*condition) == "AUTUMN") ){ season_matched = true; } } } //Make sure the current time of day is within one of the valid time ranges for this spawn bool is_valid_time_of_day = false; if(valid_times_of_day.size() < 1){ //Then it can spawn whenever, since no times were defined is_valid_time_of_day = true; } else { //Otherwise, it's valid if it matches any of the times of day for(std::vector<std::pair<int,int> >::iterator time_pair = valid_times_of_day.begin(); time_pair != valid_times_of_day.end(); ++time_pair){ int time_now = g->turn.get_turn(); if(time_now > time_pair->first && time_now < time_pair->second){ is_valid_time_of_day = true; } } } if(!is_valid_time_of_day){ valid_entry = false; } //If we are limited by season, make sure we matched a season if(season_limited && !season_matched){ valid_entry = false; } //If the entry was valid, check to see if we actually spawn it if(valid_entry){ //If the monsters frequency is greater than the spawn_chance, select this spawn rule if(it->frequency >= spawn_chance){ if(it->pack_maximum > 1){ spawn_details = MonsterGroupResult(it->name, rng(it->pack_minimum,it->pack_maximum)); } else { spawn_details = MonsterGroupResult(it->name, 1); } //And if a quantity pointer with remaining value was passed, will will modify the external value as a side effect //We will reduce it by the spawn rule's cost multiplier if(quantity){ *quantity -= it->cost_multiplier * spawn_details.pack_size; } monster_found = true; //Otherwise, subtract the frequency from spawn result for the next loop around }else{ spawn_chance -= it->frequency; } } } return spawn_details; }