void ribi::xnz::SpriteEnemyMedium::Shoot(std::vector<boost::shared_ptr<Sprite> >& newSprites) { ++mTimer; if (mTimer % mTimeShoot == 0) { const int missileY = GetY() + GetHeight(); const int missileX = GetX() + (GetWidth() / 2) + (mTurretDirection == turretDownLeft ? -2 : 0) + (mTurretDirection == turretDownRight ? 2 : 0); const int dx = 0 + (mTurretDirection == turretDownLeft ? -1 : 0) + (mTurretDirection == turretDownRight ? 1 : 0); const int dy = 1; boost::shared_ptr<Sprite> missile(new SpriteMissile(missileX,missileY,dx,dy,2)); newSprites.push_back(missile); } else { mTurretDirection = static_cast<EnumTurretDirection>(std::rand() % 3); switch(mTurretDirection) { case turretDownLeft: SetGraphic(GetSpriteShootDownLeft()); break; case turretDown: SetGraphic(GetSpriteShootDown()); break; case turretDownRight: SetGraphic(GetSpriteShootDownRight()); break; default: assert(!"Should not get here"); } } }
void CombatShip::FireAt(CombatObjectPtr target) { float range_squared = (target->position() - position()).lengthSquared(); float structure_factor = FractionalStructure(); for (CombatShip::SRVec::reverse_iterator it = m_unfired_SR_weapons.rbegin(); it != m_unfired_SR_weapons.rend(); ++it) { if (range_squared < it->m_range * it->m_range) { Listener().ShipFired(shared_from_this(), target, it->m_name); target->Damage(it->m_damage, CombatObject::NON_PD_DAMAGE); } else { m_unfired_SR_weapons.resize(std::distance(it, m_unfired_SR_weapons.rend())); break; } } std::size_t i = 0; for (std::multimap<float, const PartType*>::const_iterator it = GetShip()->Design()->LRWeapons().begin(); it != GetShip()->Design()->LRWeapons().end(); ++it, ++i) { if (m_next_LR_fire_turns[i] < m_turn) { float weapon_range_squared = it->first * it->first; if (range_squared < weapon_range_squared) { OpenSteer::Vec3 direction = (target->position() - position()).normalize(); MissilePtr missile( new Missile(GetShip(), *it->second, target, position(), direction, *m_pathing_engine)); m_pathing_engine->AddObject(missile); GetShip()->RemoveMissiles(it->second->Name(), 1); if (m_next_LR_fire_turns[i] == INVALID_TURN) m_next_LR_fire_turns[i] = m_turn; m_next_LR_fire_turns[i] += GetShip()->GetPartMeter(METER_ROF, it->second->Name())->Current() * structure_factor; Listener().MissileLaunched(missile); } } } for (CombatShip::PDList::iterator it = m_unfired_PD_weapons.begin(); it != m_unfired_PD_weapons.end(); ++it) { if (range_squared < it->m_range * it->m_range) { Listener().ShipFired(shared_from_this(), target, it->m_name); target->Damage(it->m_damage, CombatObject::PD_DAMAGE); } else { m_unfired_PD_weapons.erase(it, m_unfired_PD_weapons.end()); break; } } }
/** * Activate is basically a switch/redirect to the appropriate function */ bool PowerManager::activate(int power_index, StatBlock *src_stats, Point target) { // logic for different types of powers are very different. We allow these // separate functions to handle the details. if (powers[power_index].type == POWTYPE_SINGLE) return single(power_index, src_stats, target); else if (powers[power_index].type == POWTYPE_MISSILE) return missile(power_index, src_stats, target); else if (powers[power_index].type == POWTYPE_REPEATER) return repeater(power_index, src_stats, target); else if (powers[power_index].type == POWTYPE_EFFECT) return effect(power_index, src_stats, target); return false; }
void MissileLauncher::create_missile(double x_pos, double y_pos, double x_vel, double y_vel) { std::unique_ptr<Missile> missile( new Missile(x_pos, y_pos, x_vel, y_vel, 5, missile_graphic_path_)); game_object_mediator_.add_projectile(team_, std::move(missile)); game_object_mediator_.play_sound(missile_launch_sound_path_); }
int chase(struct thing *tp, coord *ee, int flee) { int x, y; int dist, thisdist, monst_dist = INT_MAX; struct linked_list *weapon; coord *er = &tp->t_pos; coord shoot; coord *shootit_dir = NULL; int ch; char mch; int next_player = FALSE; /* Take care of shooting directions */ if (on(*tp, CANBREATHE) || on(*tp, CANSHOOT) || on(*tp, CANCAST)) { if (good_monster(*tp)) { shootit_dir = find_shoot(tp, &shoot); /* find a mean monster */ if (wizard && shootit_dir) msg("Found monster to attack towards (%d,%d).", shootit_dir->x, shootit_dir->y); } else shootit_dir = can_shoot(er, ee, &shoot); /* shoot hero */ } /* * If the thing is confused, let it move randomly. Some monsters are * slightly confused all of the time. */ if ((on(*tp, ISHUH) && rnd(10) < 8) || ((on(*tp, ISINVIS) || on(*tp, ISSHADOW)) && rnd(100) < 20) || (on(player, ISINVIS) && off(*tp, CANSEE))) { /* Player is invisible */ /* get a valid random move */ tp->t_nxtpos = rndmove(tp); dist = DISTANCE(tp->t_nxtpos, *ee); if (on(*tp, ISHUH) && rnd(20) == 0) /* monster might lose confusion */ turn_off(*tp, ISHUH); /* * check to see if random move takes creature away from * player if it does then turn off ISHELD */ if (dist > 1 && on(*tp, DIDHOLD)) { turn_off(*tp, DIDHOLD); turn_on(*tp, CANHOLD); if (--hold_count == 0) turn_off(player, ISHELD); } } /* If we can breathe, we may do so */ else if (on(*tp, CANBREATHE) && (shootit_dir) && (rnd(100) < 67) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)) && (DISTANCE(*er, *ee) < BOLT_LENGTH * BOLT_LENGTH)) { int chance; char *breath; /* Will it breathe at random */ if (on(*tp, CANBRANDOM)) { if (rnd(level / 20) == 0 && tp->t_index != nummonst + 1 && !(good_monster(*tp))) turn_off(*tp, CANBRANDOM); /* Select type of breath */ chance = rnd(100); if (chance < 11) breath = "acid"; else if (chance < 22) breath = "flame"; else if (chance < 33) breath = "lightning bolt"; else if (chance < 44) breath = "chlorine gas"; else if (chance < 55) breath = "ice"; else if (chance < 66) breath = "nerve gas"; else if (chance < 77) breath = "sleeping gas"; else if (chance < 88) breath = "slow gas"; else breath = "fear gas"; } /* Or can it breathe acid? */ else if (on(*tp, CANBACID)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBACID); breath = "acid"; } /* Or can it breathe fire */ else if (on(*tp, CANBFIRE)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBFIRE); breath = "flame"; } /* Or can it breathe electricity? */ else if (on(*tp, CANBBOLT)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBBOLT); breath = "lightning bolt"; } /* Or can it breathe gas? */ else if (on(*tp, CANBGAS)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBGAS); breath = "chlorine gas"; } /* Or can it breathe ice? */ else if (on(*tp, CANBICE)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBICE); breath = "ice"; } else if (on(*tp, CANBPGAS)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBPGAS); breath = "nerve gas"; } else if (on(*tp, CANBSGAS)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBSGAS); breath = "sleeping gas"; } else if (on(*tp, CANBSLGAS)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBSLGAS); breath = "slow gas"; } else { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBFGAS); breath = "fear gas"; } shoot_bolt(tp, *er, *shootit_dir, (tp == THINGPTR(fam_ptr)), tp->t_index, breath, roll(tp->t_stats.s_lvl, 6)); tp->t_nxtpos = *er; dist = DISTANCE(tp->t_nxtpos, *ee); if (!curr_mons) return (TRUE); } else if (shootit_dir && on(*tp, CANCAST) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6))) { /* If we can cast spells we might do so - even if adjacent fleeing monsters are restricted to certain spells */ incant(tp, *shootit_dir); tp->t_nxtpos = *er; dist = DISTANCE(tp->t_nxtpos, *ee); } else if (shootit_dir && on(*tp, CANSHOOT)) { weapon = get_hurl(tp); if (weapon && (off(*tp, ISFLEE) || rnd(DISTANCE(*er, *ee)) > 2) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6))) { /* Should we shoot or throw something? fleeing monsters may to shoot anyway if far enough away */ missile(shootit_dir->y, shootit_dir->x, weapon, tp); tp->t_nxtpos = *er; dist = DISTANCE(tp->t_nxtpos, *ee); } } else { /* Otherwise, find the empty spot next to the chaser that is closest to the chasee. */ int ey, ex; struct room *rer, *ree; int dist_to_old = INT_MIN; /* Dist from goal to old position */ /* Get rooms */ rer = roomin(*er); ree = roomin(*ee); /* * This will eventually hold where we move to get closer. If * we can't find an empty spot, we stay where we are. */ dist = flee ? 0 : INT_MAX; tp->t_nxtpos = *er; /* Are we at our goal already? */ if (!flee && ce(tp->t_nxtpos, *ee)) return (FALSE); ey = er->y + 1; ex = er->x + 1; for (x = er->x - 1; x <= ex; x++) for (y = er->y - 1; y <= ey; y++) { coord tryp; /* test position */ /* Don't try off the screen */ if ((x < 0) || (x >= COLS) || (y < 1) || (y >= LINES - 2)) continue; /* * Don't try the player if not going after * the player or he's disguised and monster is dumb */ if (((off(*tp, ISFLEE) && !ce(hero, *ee)) || (on(player, ISDISGUISE) && (rnd(tp->t_stats.s_lvl) < 6)) || good_monster(*tp)) && x == hero.x && y == hero.y) continue; tryp.x = x; tryp.y = y; /* * Is there a monster on this spot closer to * our goal? Don't look in our spot or where * we were. */ if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) && isalpha( (mch = CCHAR(mvwinch(mw, y, x))) ) ) { int test_dist; test_dist = DISTANCE(tryp,*ee); if (test_dist <= 25 && /* Let's be fairly close */ test_dist < monst_dist) { /* Could we really move there? */ mvwaddch(mw, y, x, ' '); /* Temp blank monst */ if (diag_ok(er, &tryp, tp)) monst_dist = test_dist; mvwaddch(mw, y, x, mch); /* Restore monster */ } } if (!diag_ok(er, &tryp, tp)) continue; ch = mvwinch(cw, y, x); /* Screen character */ /* * Stepping on player is NOT okay if we are * fleeing */ if (on(*tp, ISFLEE) && (ch == PLAYER)) next_player = TRUE; if (step_ok(y, x, NOMONST, tp) && (off(*tp, ISFLEE) || ch != PLAYER)) { /* * If it is a trap, an intelligent * monster may not step on it (unless * our hero is on top!) */ if (isatrap(ch)) { if (!(ch == RUSTTRAP) && !(ch == FIRETRAP && on(*tp, NOFIRE)) && rnd(10) < tp->t_stats.s_intel && (y != hero.y || x != hero.x)) continue; } /* * OK -- this place counts */ thisdist = DISTANCE(tryp, *ee); /* * Adjust distance if we are being * shot at to moving out of line of sight. */ if (tp->t_wasshot && tp->t_stats.s_intel > 5 && ce(hero, *ee)) { /* Move out of line of sight */ if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) { if (flee) thisdist -= SHOTPENALTY; else thisdist += SHOTPENALTY; } /* * But do we want to leave * the room? */ else if (rer && rer == ree && ch == DOOR) thisdist += DOORPENALTY; } /* * Don't move to the last position if * we can help it */ if (ce(tryp, tp->t_oldpos)) dist_to_old = thisdist; else if ((flee && (thisdist > dist)) || (!flee && (thisdist < dist))) { tp->t_nxtpos = tryp; dist = thisdist; } } } /* * If we are running from the player and he is in our way, go * ahead and slug him. */ if (next_player && DISTANCE(*er,*ee) < dist && step_ok(tp->t_chasee->t_pos.y, tp->t_chasee->t_pos.x, NOMONST, tp)) { tp->t_nxtpos = tp->t_chasee->t_pos; /* Okay to hit player */ return(FALSE); } /* * If we can't get closer to the player (if that's our goal) * because other monsters are in the way, just stay put */ if (!flee && ce(hero, *ee) && monst_dist < INT_MAX && DISTANCE(*er, hero) < dist) tp->t_nxtpos = *er; /* Do we want to go back to the last position? */ else if (dist_to_old != INT_MIN && /* It is possible to move back */ ((flee && dist == 0) || /* No other possible moves */ (!flee && dist == INT_MAX))) { /* Do we move back or just stay put (default)? */ dist = DISTANCE(*er,*ee); /* Current distance */ if (!flee || (flee && (dist_to_old > dist))) tp->t_nxtpos = tp->t_oldpos; } } /* Make sure we have the real distance now */ dist = DISTANCE(tp->t_nxtpos, *ee); /* Mark monsters in a wall */ switch(mvinch(tp->t_nxtpos.y, tp->t_nxtpos.x)) { case WALL: case '-': case '|': turn_on(*tp, ISINWALL); break; default: turn_off(*tp, ISINWALL); } if (off(*tp, ISFLEE) && !(!SAME_POS((tp->t_chasee->t_pos),hero) || off(player, ISINWALL) || on(*tp, CANINWALL))) return(dist != 0); else /* May actually hit here from a confused move */ return(!ce(tp->t_nxtpos, hero)); }
void ZombieGame::init() { keyboard_ = DevicePtr(new InputKeyboard(SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT, SDLK_SPACE, SDLK_r, SDLK_LSHIFT, SDLK_e)); clipsize_ = 0; bulletsInWeapon_ = 0; health_ = 0; scale_ = 1.f; lastSpawnTime_ = engine_.getTime(); spawnPeriod_ = 0.5f; addKeyListener([&](gui::Component& component, const SDL_Event& keyEvent) { keyboard_->eventUpdate(keyEvent); }); if (zombieEntry_.getDeepChildEntry("music switch").getBool()) { music_ = zombieEntry_.getDeepChildEntry("music track").getMusic(); music_.setVolume(zombieEntry_.getDeepChildEntry("music volume").getFloat()); music_.play(-1); } tree_ = zombieEntry_.getDeepChildEntry("tree image").getSprite(); wall_ = zombieEntry_.getDeepChildEntry("buildings wallImage").getSprite(); nbrUnits_ = 0; unitMaxLimit_ = zombieEntry_.getDeepChildEntry("settings unitLimit").getInt(); innerSpawnRadius_ = zombieEntry_.getDeepChildEntry("settings innerSpawnRadius").getFloat(); outerSpawnRadius_ = zombieEntry_.getDeepChildEntry("settings outerSpawnRadius").getFloat(); terrain_.loadRoadSprites(zombieEntry_.getDeepChildEntry("roads")); loadTerrain(); explosionProperties_ = zombie::loadExplosion(zombieEntry_.getDeepChildEntry("explosion")); humanInjured_ = zombieEntry_.getDeepChildEntry("human injuredAnimation").getAnimation(); humanDie_ = zombieEntry_.getDeepChildEntry("human dieAnimation").getAnimation(); Unit2D human(loadUnit(this, "human", zombieEntry_, false)); human.setDieSound(zombieEntry_.getDeepChildEntry("human dieSound").getSound()); human.setHitSound(zombieEntry_.getDeepChildEntry("human hitSound").getSound()); zombieInjured_ = zombieEntry_.getDeepChildEntry("zombie injuredAnimation").getAnimation(); zombieDie_ = zombieEntry_.getDeepChildEntry("zombie dieAnimation").getAnimation(); Unit2D zombie(loadUnit(this, "zombie", zombieEntry_, true)); zombie.setDieSound(zombieEntry_.getDeepChildEntry("zombie dieSound").getSound()); zombie.setHitSound(zombieEntry_.getDeepChildEntry("zombie hitSound").getSound()); // Add human to engine. { State state(Position(85,120), ORIGO, 0); //Position p = generatePosition(spawningPoints_); //State state(Position(200,200), ORIGO, 0); Unit* unit = units_.pushBack(human); engine_.add(unit); unit->setState(state); unit->setActive(true); unit->setAwake(true); players_.push_back(std::unique_ptr<HumanPlayer>(new HumanPlayer(keyboard_, unit))); viewPosition_ = state.position_; refViewPosition_ = viewPosition_; ++nbrUnits_; } // Add zombies to engine. calculateValidSpawningPoints(units_[0]); unsigned int unitLevel = zombieEntry_.getDeepChildEntry("settings unitLevel").getInt(); for (unsigned int i = 1; i <= unitLevel && i < units_.getMaxSize(); ++i) { Position p = generatePosition(vaildSpawningPoints_); float angle = calculateAnglePointToPoint(p, units_[0].getPosition()); State state(p, ORIGO, angle); Unit* unit = units_.pushBack(zombie); engine_.add(unit); unit->setState(state); unit->setActive(true); unit->setAwake(true); players_.push_back(std::unique_ptr<ZombieBehavior>(new ZombieBehavior(unit))); } // Add cars to engine. Car2D car(zombie::loadCar(zombieEntry_.getDeepChildEntry("car"))); for (unsigned int i = 0; i < 8 && i < units_.getMaxSize(); ++i) { State state(Position(85,130), ORIGO, 0); Car* c = cars_.pushBack(car); engine_.add(c); c->setState(state); c->setActive(true); c->setAwake(true); } // Add missile to engine. Missile2D missile(loadMissile2D(this, zombieEntry_.getDeepChildEntry("equipment missile"))); for (unsigned int i = 0; i < 10 && i < units_.getMaxSize(); ++i) { engine_.add(missiles_.emplaceBack(missile)); } setBackgroundColor(0, 0.1f, 0); zombiesKilled_ = 0; drawBuildings_.createVBO(buildings_, wall_.getTexture()); }
/* * chase: * Find the spot for the chaser(er) to move closer to the * chasee(ee). Returns TRUE if we want to keep on chasing later * FALSE if we reach the goal. */ int chase(struct thing *tp, coord *ee, int flee, int *mdead) { register int x, y; register int dist, thisdist, monst_dist = MAXINT; register struct linked_list *weapon; register coord *er = &tp->t_pos, *shoot_dir; register int ch, mch; register int next_player = FALSE; int deadflg; if (mdead != NULL) *mdead = 0; shoot_dir = can_shoot(er, ee); weapon = get_hurl(tp); /* * If the thing is confused, let it move randomly. Invisible * Stalkers are slightly confused all of the time. */ if ((on(*tp, ISHUH) && rnd(10) < 8) || ((on(*tp, ISINVIS) || on(*tp, ISSHADOW)) && rnd(100) < 20) || (on(player, ISINVIS) && off(*tp, CANSEE))) { /* Player is invisible */ /* * get a valid random move */ ch_ret = *rndmove(tp); dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); if (on(*tp, ISHUH) && rnd(20) == 0) /* monster might lose confusion */ turn_off(*tp, ISHUH); /* * check to see if random move takes creature away from player * if it does then turn off ISHELD */ if (dist > 1 && on(*tp, DIDHOLD)) { turn_off(*tp, DIDHOLD); turn_on(*tp, CANHOLD); if (--hold_count <= 0) { hold_count = 0; turn_off(player, ISHELD); } } } /* If we can breathe, we may do so */ else if (on(*tp, CANBREATHE) && (shoot_dir) && (rnd(100) < 67) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)) && (DISTANCE(er->y, er->x, ee->y, ee->x) < BOLT_LENGTH*BOLT_LENGTH)) { register int chance; register char *breath; /* Will it breathe at random */ if (on(*tp, CANBRANDOM)) { if (rnd(level/20) == 0 && tp->t_index != NUMMONST+1) turn_off(*tp, CANBRANDOM); /* Select type of breath */ chance = rnd(100); if (chance < 11) breath = "acid"; else if (chance < 22) breath = "flame"; else if (chance < 33) breath = "lightning bolt"; else if (chance < 44) breath = "chlorine gas"; else if (chance < 55) breath = "ice"; else if (chance < 66) breath = "nerve gas"; else if (chance < 77) breath = "sleeping gas"; else if (chance < 88) breath = "slow gas"; else breath = "fear gas"; } /* Or can it breathe acid? */ else if (on(*tp, CANBACID)) { if (rnd(level/20) == 0) turn_off(*tp, CANBACID); breath = "acid"; } /* Or can it breathe fire */ else if (on(*tp, CANBFIRE)) { if (rnd(level/20) == 0) turn_off(*tp, CANBFIRE); breath = "flame"; } /* Or can it breathe electricity? */ else if (on(*tp, CANBBOLT)) { if (rnd(level/20) == 0) turn_off(*tp, CANBBOLT); breath = "lightning bolt"; } /* Or can it breathe gas? */ else if (on(*tp, CANBGAS)) { if (rnd(level/20) == 0) turn_off(*tp, CANBGAS); breath = "chlorine gas"; } /* Or can it breathe ice? */ else if (on(*tp, CANBICE)) { if (rnd(level/20) == 0) turn_off(*tp, CANBICE); breath = "ice"; } else if (on(*tp, CANBPGAS)) { if (rnd(level/20) == 0) turn_off(*tp, CANBPGAS); breath = "nerve gas"; } else if (on(*tp, CANBSGAS)) { if (rnd(level/20) == 0) turn_off(*tp, CANBSGAS); breath = "sleeping gas"; } else if (on(*tp, CANBSLGAS)) { if (rnd(level/20) == 0) turn_off(*tp, CANBSLGAS); breath = "slow gas"; } else { if (rnd(level/20) == 0) turn_off(*tp, CANBFGAS); breath = "fear gas"; } /* Now breathe -- returns TRUE if kills itself */ deadflg = shoot_bolt(tp, *er, *shoot_dir, FALSE, tp->t_index, breath, (save(VS_BREATH) ? tp->t_stats.s_hpt/2 : tp->t_stats.s_hpt)); if (deadflg && mdead != NULL) *mdead = 1; ch_ret = *er; dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); if (deadflg) return(TRUE); } /* * If we can shoot or throw something, we might do so * if we are running away, we may decide to shoot anyway if we are far * enough */ else if((off(*tp, ISFLEE) || rnd(DISTANCE(er->y,er->x,ee->y,ee->x)) > 2) && on(*tp, CANSHOOT) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)) && (shoot_dir) && (weapon)) { missile(shoot_dir->y, shoot_dir->x, weapon, tp); ch_ret = *er; dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); } /* * Otherwise, find the empty spot next to the chaser that is * closest to the chasee. */ else { register int ey, ex; register struct room *rer, *ree; register int dist_to_old = MININT; /* Dist from goal to old position */ /* Get rooms */ rer = roomin(er); ree = roomin(ee); /* * This will eventually hold where we move to get closer * If we can't find an empty spot, we stay where we are. */ dist = flee ? 0 : MAXINT; ch_ret = *er; /* Are we at our goal already? */ if (!flee && ce(ch_ret, *ee)) return(FALSE); ey = er->y + 1; ex = er->x + 1; for (x = er->x - 1; x <= ex; x++) for (y = er->y - 1; y <= ey; y++) { coord tryp; /* Don't try off the board */ if ((x < 0) || (x >= COLS) || (y < 1) || (y >= LINES - 2)) continue; /* Don't try the player if not going after the player */ /* or he's disguised */ if ( ((off(*tp, ISFLEE) && !ce(hero, *ee)) || (on(player, ISDISGUISE) && (rnd(tp->t_stats.s_lvl) < 6))) && x == hero.x && y == hero.y) continue; tryp.x = x; tryp.y = y; /* Is there a monster on this spot closer to our goal? * Don't look in our spot or where we were. */ if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) && isalpha(mch = CCHAR( mvwinch(mw, y, x) ))) { register int test_dist; test_dist = DISTANCE(y, x, ee->y, ee->x); if (test_dist <= 25 && /* Let's be fairly close */ test_dist < monst_dist) { /* Could we really move there? */ mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */ if (diag_ok(er, &tryp, tp)) monst_dist = test_dist; mvwaddch(mw, y, x, mch); /* Restore monster */ } } if (!diag_ok(er, &tryp, tp)) continue; ch = CCHAR( mvwinch(cw, y, x) ); /* Screen character */ if (on(*tp, ISFLEE) && (ch == PLAYER)) next_player = TRUE; /* Stepping on player is NOT okay if we are fleeing */ if (step_ok(y, x, NOMONST, tp) && (off(*tp, ISFLEE) || ch != PLAYER)) { /* * If it is a trap, an intelligent monster may not * step on it (unless our hero is on top!) */ if (isatrap(ch)) { if (!(ch == RUSTTRAP) && !(ch == FIRETRAP && on(*tp,NOFIRE)) && rnd(10) < tp->t_stats.s_intel && (y != hero.y || x != hero.x)) continue; } /* * OK -- this place counts */ thisdist = DISTANCE(y, x, ee->y, ee->x); /* Adjust distance if we are being shot at */ if (tp->t_wasshot && tp->t_stats.s_intel > 5 && ce(hero, *ee)) { /* Move out of line of sight */ if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) { if (flee) thisdist -= SHOTPENALTY; else thisdist += SHOTPENALTY; } /* But do we want to leave the room? */ else if (rer && rer == ree && ch == DOOR) thisdist += DOORPENALTY; } /* Don't move to the last position if we can help it */ if (ce(tryp, tp->t_oldpos)) dist_to_old = thisdist; else if ((flee && (thisdist > dist)) || (!flee && (thisdist < dist))) { ch_ret = tryp; dist = thisdist; } } } /* If we are running from the player and he is in our way, * go ahead and slug him. */ if (next_player && DISTANCE(er->y, er->x, ee->y, ee->x) < dist && step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) { ch_ret = *(tp->t_dest); /* Okay to hit player */ return FALSE; } /* If we can't get closer to the player (if that's our goal) * because other monsters are in the way, just stay put */ if (!flee && ce(hero, *ee) && monst_dist < MAXINT && DISTANCE(er->y, er->x, hero.y, hero.x) < dist) ch_ret = *er; /* Do we want to go back to the last position? */ else if (dist_to_old != MININT && /* It is possible to move back */ ((flee && dist == 0) || /* No other possible moves */ (!flee && dist == MAXINT))) { /* Do we move back or just stay put (default)? */ dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */ if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos; } } /* Make sure we have the real distance now */ dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); /* Mark monsters in a wall */ if (isrock(CCHAR( mvinch(ch_ret.y, ch_ret.x) ))) turn_on(*tp, ISINWALL); else turn_off(*tp, ISINWALL); if (off(*tp, ISFLEE) && ((tp->t_dest != &hero) || off(player, ISINWALL) || on(*tp, CANINWALL))) return (dist != 0); /* May actually hit here from a confused move */ else return(!ce(ch_ret, hero)); }