/* Random walking even when we've moved * To simulate zombie stumbling and ineffective movement * Note that this is sub-optimal; stumbling may INCREASE a zombie's speed. * Most of the time (out in the open) this effect is insignificant compared to * the negative effects, but in a hallway it's perfectly even */ void monster::stumble(bool moved) { // don't stumble every turn. every 3rd turn, or 8th when walking. if((moved && !one_in(8)) || !one_in(3)) { return; } std::vector <point> valid_stumbles; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { const int nx = posx() + i; const int ny = posy() + j; if ((i || j) && can_move_to(nx, ny) && /* Don't ever stumble into impassable terrain, even if we normally could * smash it, as this is uncoordinated movement (and is forced). */ g->m.move_cost(nx, ny) != 0 && //Stop zombies and other non-breathing monsters wandering INTO water //(Unless they can swim/are aquatic) //But let them wander OUT of water if they are there. !(has_flag(MF_NO_BREATHE) && !has_flag(MF_SWIMS) && !has_flag(MF_AQUATIC) && g->m.has_flag("SWIMMABLE", nx, ny) && !g->m.has_flag("SWIMMABLE", posx(), posy())) && (g->u.posx != nx || g->u.posy != ny) && (g->mon_at(nx, ny) == -1)) { point tmp(nx, ny); valid_stumbles.push_back(tmp); } } } if (valid_stumbles.size() == 0) //nowhere to stumble? { return; } int choice = rng(0, valid_stumbles.size() - 1); int cx = valid_stumbles[choice].x; int cy = valid_stumbles[choice].y; moves -= calc_movecost(posx(), posy(), cx, cy); setpos(cx, cy); // Here we have to fix our plans[] list, // acquiring a new path to the previous target. // target == either end of current plan, or the player. int tc; if (plans.size() > 0) { if (g->m.sees(posx(), posy(), plans.back().x, plans.back().y, -1, tc)) set_dest(plans.back().x, plans.back().y, tc); else if (sees_player( tc )) set_dest(g->u.posx, g->u.posy, tc); else //durr, i'm suddenly calm. what was i doing? plans.clear(); } }
void monster::plan(const std::vector<int> &friendlies) { int sightrange = g->light_level(); int closest = -1; int dist = 1000; int tc = 0; int stc = 0; bool fleeing = false; if (friendly != 0) { // Target monsters, not the player! for (int i = 0, numz = g->num_zombies(); i < numz; i++) { monster *tmp = &(g->zombie(i)); if (tmp->friendly == 0) { int d = rl_dist(posx(), posy(), tmp->posx(), tmp->posy()); if (d < dist && g->m.sees(posx(), posy(), tmp->posx(), tmp->posy(), sightrange, tc)) { closest = i; dist = d; stc = tc; } } } if (has_effect("docile")) { closest = -1; } if (closest >= 0) { set_dest(g->zombie(closest).posx(), g->zombie(closest).posy(), stc); } else if (friendly > 0 && one_in(3)) { // Grow restless with no targets friendly--; } else if (friendly < 0 && sees_player( tc ) ) { if (rl_dist(posx(), posy(), g->u.posx, g->u.posy) > 2) { set_dest(g->u.posx, g->u.posy, tc); } else { plans.clear(); } } return; } // If we can see, and we can see a character, move toward them or flee. if (can_see() && sees_player( tc ) ) { dist = rl_dist(posx(), posy(), g->u.posx, g->u.posy); if (is_fleeing(g->u)) { // Wander away. fleeing = true; set_dest(posx() * 2 - g->u.posx, posy() * 2 - g->u.posy, tc); } else { // Chase the player. closest = -2; stc = tc; } } for (int i = 0; i < g->active_npc.size(); i++) { npc *me = (g->active_npc[i]); int medist = rl_dist(posx(), posy(), me->posx, me->posy); if ((medist < dist || (!fleeing && is_fleeing(*me))) && (can_see() && g->m.sees(posx(), posy(), me->posx, me->posy, sightrange, tc))) { if (is_fleeing(*me)) { fleeing = true; set_dest(posx() * 2 - me->posx, posy() * 2 - me->posy, tc); \ } else { closest = i; stc = tc; } dist = medist; } } if (!fleeing) { fleeing = attitude() == MATT_FLEE; if (can_see()) { for (int f = 0, numf = friendlies.size(); f < numf; f++) { const int i = friendlies[f]; monster *mon = &(g->zombie(i)); int mondist = rl_dist(posx(), posy(), mon->posx(), mon->posy()); if (mondist < dist && g->m.sees(posx(), posy(), mon->posx(), mon->posy(), sightrange, tc)) { dist = mondist; if (fleeing) { wandx = posx() * 2 - mon->posx(); wandy = posy() * 2 - mon->posy(); wandf = 40; } else { closest = -3 - i; stc = tc; } } } } if (closest == -2) { if (one_in(2)) {//random for the diversity of the trajectory ++stc; } else { --stc; } set_dest(g->u.posx, g->u.posy, stc); } else if (closest <= -3) set_dest(g->zombie(-3 - closest).posx(), g->zombie(-3 - closest).posy(), stc); else if (closest >= 0) set_dest(g->active_npc[closest]->posx, g->active_npc[closest]->posy, stc); } }
void monster::plan(const std::vector<int> &friendlies) { int sightrange = g->light_level(); int closest = -1; int dist = 1000; int tc = 0; int stc = 0; bool fleeing = false; if (friendly != 0) { // Target monsters, not the player! for (int i = 0, numz = g->num_zombies(); i < numz; i++) { monster *tmp = &(g->zombie(i)); if (tmp->friendly == 0) { int d = rl_dist(posx(), posy(), tmp->posx(), tmp->posy()); if (d < dist && g->m.sees(posx(), posy(), tmp->posx(), tmp->posy(), sightrange, tc)) { closest = i; dist = d; stc = tc; } } } if (has_effect("docile")) { closest = -1; } if (closest >= 0) { set_dest(g->zombie(closest).posx(), g->zombie(closest).posy(), stc); } else if (friendly > 0 && one_in(3)) { // Grow restless with no targets friendly--; } else if (friendly < 0 && sees_player( tc ) ) { if (rl_dist(posx(), posy(), g->u.posx, g->u.posy) > 2) { set_dest(g->u.posx, g->u.posy, tc); } else { plans.clear(); } } return; } // If we can see, and we can see a character, move toward them or flee. if (can_see() && sees_player( tc ) ) { dist = rl_dist(posx(), posy(), g->u.posx, g->u.posy); if (is_fleeing(g->u)) { // Wander away. fleeing = true; set_dest(posx() * 2 - g->u.posx, posy() * 2 - g->u.posy, tc); } else { // Chase the player. closest = -2; stc = tc; } } for (size_t i = 0; i < g->active_npc.size(); i++) { npc *me = (g->active_npc[i]); int medist = rl_dist(posx(), posy(), me->posx, me->posy); if ((medist < dist || (!fleeing && is_fleeing(*me))) && (can_see() && g->m.sees(posx(), posy(), me->posx, me->posy, sightrange, tc))) { if (is_fleeing(*me)) { fleeing = true; set_dest(posx() * 2 - me->posx, posy() * 2 - me->posy, tc);\ } else { closest = i; stc = tc; } dist = medist; } } if (!fleeing) { fleeing = attitude() == MATT_FLEE; if (can_see()) { for( auto &friendlie : friendlies ) { const int i = friendlie; monster *mon = &(g->zombie(i)); int mondist = rl_dist(posx(), posy(), mon->posx(), mon->posy()); if (mondist < dist && g->m.sees(posx(), posy(), mon->posx(), mon->posy(), sightrange, tc)) { dist = mondist; if (fleeing) { wandx = posx() * 2 - mon->posx(); wandy = posy() * 2 - mon->posy(); wandf = 40; } else { closest = -3 - i; stc = tc; } } } } if (closest == -2) { if (one_in(2)) {//random for the diversity of the trajectory ++stc; } else { --stc; } set_dest(g->u.posx, g->u.posy, stc); } else if (closest <= -3) { set_dest(g->zombie(-3 - closest).posx(), g->zombie(-3 - closest).posy(), stc); } else if (closest >= 0) { set_dest(g->active_npc[closest]->posx, g->active_npc[closest]->posy, stc); } } // If we're not adjacent to the start of our plan path, don't act on it. // This is to catch when we had pre-existing invalid plans and // made it through the function without changing them. if( !plans.empty() && square_dist(pos().x, pos().y, plans.front().x, plans.front().y ) > 1 ) { plans.clear(); } }