void monster::process_effects() { for( auto effect_it = effects.begin(); effect_it != effects.end(); ++effect_it ) { std::string id = effect_it->second.get_id(); if (id == "nasty_poisoned") { mod_speed_bonus( -rng(3, 5) ); apply_damage( nullptr, bp_torso, rng( 3, 6 ) ); } if (id == "poisoned") { mod_speed_bonus( -rng(0, 3) ); apply_damage( nullptr, bp_torso, rng( 1, 3 ) ); // MATERIALS-TODO: use fire resistance } else if (id == "onfire") { if (made_of("flesh") || made_of("iflesh")) apply_damage( nullptr, bp_torso, rng( 3, 8 ) ); if (made_of("veggy")) apply_damage( nullptr, bp_torso, rng( 10, 20 ) ); if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") || made_of("wool")) apply_damage( nullptr, bp_torso, rng( 15, 40 ) ); } } Creature::process_effects(); }
dealt_damage_instance Creature::deal_damage(Creature *source, body_part bp, const damage_instance &dam) { if( is_dead_state() ) { return dealt_damage_instance(); } int total_damage = 0; int total_pain = 0; damage_instance d = dam; // copy, since we will mutate in absorb_hit dealt_damage_instance dealt_dams; absorb_hit(bp, d); // Add up all the damage units dealt for( const auto &it : d.damage_units ) { int cur_damage = 0; deal_damage_handle_type( it, bp, cur_damage, total_pain ); if( cur_damage > 0 ) { dealt_dams.dealt_dams[ it.type ] += cur_damage; total_damage += cur_damage; } } mod_pain(total_pain); apply_damage( source, bp, total_damage ); return dealt_dams; }
dealt_damage_instance Creature::deal_damage(Creature *source, body_part bp, int side, const damage_instance &dam) { int total_damage = 0; int total_pain = 0; damage_instance d = dam; // copy, since we will mutate in absorb_hit std::vector<int> dealt_dams(NUM_DT, 0); absorb_hit(bp, side, d); // add up all the damage units dealt int cur_damage; for (std::vector<damage_unit>::const_iterator it = d.damage_units.begin(); it != d.damage_units.end(); ++it) { cur_damage = 0; deal_damage_handle_type(*it, bp, cur_damage, total_pain); if (cur_damage > 0) { dealt_dams[it->type] += cur_damage; total_damage += cur_damage; } } mod_pain(total_pain); apply_damage(source, bp, side, total_damage); return dealt_damage_instance(dealt_dams); }
bool Unit::interact(Unit *target) { // Verify that the Unit hasn't interacted already. if(interacted) { return false; } // Verify second is within range of first. if(!is_within_range(target)) { return false; } // If this Unit is a healer, calculate heals. First verify target is friendly. if(type == HEALER) { if(player_id != target->get_player_id()) { return false; } target->apply_heal(); interacted = true; moved = true; return true; } // If we're not healing, verify the unit we're attacking isn't friendly. if(player_id == target->get_player_id()) { return false; } // Note that this Unit can no longer move or interact. interacted = true; moved = true; // Let's see if it hits. There's a 25% chance of missing. if(rand() % 4 == 0) { // Even though we aren't applying damage, this was still a valid outcome. return true; } // Time to attack the target! target->apply_damage(this, false); // There's also a chance that the defender can counterattack. if(target->is_within_range(this) && target->get_type() != HEALER) { apply_damage(this, true); } // If we've gotten here, everything was successful! return true; }
void monster::add_eff_effects(effect e, bool reduced) { int val = e.get_amount("HURT", reduced); if (val > 0) { if(e.activated(calendar::turn, "HURT", val, reduced)) { apply_damage(nullptr, bp_torso, val); } } Creature::add_eff_effects(e, reduced); }
void monster::process_effects() { for( auto effect_it = effects.begin(); effect_it != effects.end(); ++effect_it ) { std::string id = effect_it->second.get_id(); if (id == "nasty_poisoned") { mod_speed_bonus( -rng(3, 5) ); apply_damage( nullptr, bp_torso, rng( 3, 6 ) ); } if (id == "poisoned") { mod_speed_bonus( -rng(0, 3) ); apply_damage( nullptr, bp_torso, rng( 1, 3 ) ); // MATERIALS-TODO: use fire resistance } else if (id == "onfire") { if (made_of("flesh") || made_of("iflesh")) apply_damage( nullptr, bp_torso, rng( 3, 8 ) ); if (made_of("veggy")) apply_damage( nullptr, bp_torso, rng( 10, 20 ) ); if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") || made_of("wool")) apply_damage( nullptr, bp_torso, rng( 15, 40 ) ); } } //If this monster has the ability to heal in combat, do it now. if( has_flag( MF_REGENERATES_50 ) ) { if( hp < type->hp ) { if( one_in( 2 ) && g->u.sees( this ) ) { add_msg( m_warning, _( "The %s is visibly regenerating!" ), name().c_str() ); } hp += 50; if( hp > type->hp ) { hp = type->hp; } } } if( has_flag( MF_REGENERATES_10 ) ) { if( hp < type->hp ) { if( one_in( 2 ) && g->u.sees( this ) ) { add_msg( m_warning, _( "The %s seems a little healthier." ), name().c_str() ); } hp += 10; if( hp > type->hp ) { hp = type->hp; } } } //Monster will regen morale and aggression if it is on max HP //It regens more morale and aggression if is currently fleeing. if( has_flag( MF_REGENMORALE ) && hp >= type->hp ) { if( is_fleeing( g->u ) ) { morale = type->morale; anger = type->agro; } if( morale <= type->morale ) { morale += 1; } if( anger <= type->agro ) { anger += 1; } if( morale < 0 ) { morale += 5; } if( anger < 0 ) { anger += 5; } } // If this critter dies in sunlight, check & assess damage. if( has_flag( MF_SUNDEATH ) && g->is_in_sunlight( posx(), posy() ) ) { if( g->u.sees( this ) ) { add_msg( m_good, _( "The %s burns horribly in the sunlight!" ), name().c_str() ); } hp -= 100; if( hp < 0 ) { hp = 0; } } Creature::process_effects(); }
void monster::knock_back_from(int x, int y) { if (x == posx() && y == posy()) return; // No effect if( is_hallucination() ) { die( nullptr ); return; } point to(posx(), posy()); if (x < posx()) to.x++; if (x > posx()) to.x--; if (y < posy()) to.y++; if (y > posy()) to.y--; bool u_see = g->u.sees( to ); // First, see if we hit another monster int mondex = g->mon_at(to.x, to.y); if( mondex != -1 && g->zombie( mondex ).is_hallucination() ) { // hallucinations should not affect real monsters. If they interfer, just remove them. g->zombie( mondex ).die( this ); mondex = -1; } if (mondex != -1) { monster *z = &(g->zombie(mondex)); apply_damage( z, bp_torso, z->type->size ); add_effect("stunned", 1); if (type->size > 1 + z->type->size) { z->knock_back_from(posx(), posy()); // Chain reaction! z->apply_damage( this, bp_torso, type->size ); z->add_effect("stunned", 1); } else if (type->size > z->type->size) { z->apply_damage( this, bp_torso, type->size ); z->add_effect("stunned", 1); } z->check_dead_state(); if (u_see) add_msg(_("The %s bounces off a %s!"), name().c_str(), z->name().c_str()); return; } int npcdex = g->npc_at(to.x, to.y); if (npcdex != -1) { npc *p = g->active_npc[npcdex]; apply_damage( p, bp_torso, 3 ); add_effect("stunned", 1); p->deal_damage( this, bp_torso, damage_instance( DT_BASH, type->size ) ); if (u_see) add_msg(_("The %s bounces off %s!"), name().c_str(), p->name.c_str()); p->check_dead_state(); return; } // If we're still in the function at this point, we're actually moving a tile! if (g->m.ter_at(to.x, to.y).has_flag(TFLAG_DEEP_WATER)) { if (g->m.has_flag("LIQUID", to.x, to.y) && can_drown()) { die( nullptr ); if (u_see) { add_msg(_("The %s drowns!"), name().c_str()); } } else if (has_flag(MF_AQUATIC)) { // We swim but we're NOT in water die( nullptr ); if (u_see) { add_msg(_("The %s flops around and dies!"), name().c_str()); } } } if (g->m.move_cost(to.x, to.y) == 0) { // It's some kind of wall. apply_damage( nullptr, bp_torso, type->size ); add_effect("stunned", 2); if (u_see) { add_msg(_("The %s bounces off a %s."), name().c_str(), g->m.tername(to.x, to.y).c_str()); } } else { // It's no wall setpos(to); } check_dead_state(); }
int monster::move_to(int x, int y, bool force) { // Make sure that we can move there, unless force is true. if(!force) if(!g->is_empty(x, y) || !can_move_to(x, y)) { return 0; } if (!plans.empty()) { plans.erase(plans.begin()); } if (!force) { moves -= calc_movecost(posx(), posy(), x, y); } //Check for moving into/out of water bool was_water = g->m.is_divable(posx(), posy()); bool will_be_water = !has_flag( MF_FLIES ) && can_submerge() && g->m.is_divable(x, y); if(was_water && !will_be_water && g->u.sees(x, y)) { //Use more dramatic messages for swimming monsters add_msg(m_warning, _("A %s %s from the %s!"), name().c_str(), has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("leaps") : _("emerges"), g->m.tername(posx(), posy()).c_str()); } else if(!was_water && will_be_water && g->u.sees(x, y)) { add_msg(m_warning, _("A %s %s into the %s!"), name().c_str(), has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("dives") : _("sinks"), g->m.tername(x, y).c_str()); } setpos(x, y); footsteps(x, y); underwater = will_be_water; if(is_hallucination()) { //Hallucinations don't do any of the stuff after this point return 1; } if (type->size != MS_TINY && g->m.has_flag("SHARP", posx(), posy()) && !one_in(4)) { apply_damage( nullptr, bp_torso, rng( 2, 3 ) ); } if (type->size != MS_TINY && g->m.has_flag("ROUGH", posx(), posy()) && one_in(6)) { apply_damage( nullptr, bp_torso, rng( 1, 2 ) ); } if (g->m.has_flag("UNSTABLE", x, y)) { add_effect("bouldering", 1, num_bp, true); } else if (has_effect("bouldering")) { remove_effect("bouldering"); } if (!digging() && !has_flag(MF_FLIES) && g->m.tr_at(posx(), posy()) != tr_null) { // Monster stepped on a trap! trap* tr = traplist[g->m.tr_at(posx(), posy())]; if (dice(3, type->sk_dodge + 1) < dice(3, tr->get_avoidance())) { tr->trigger(this, posx(), posy()); } } if( !will_be_water && ( has_flag(MF_DIGS) || has_flag(MF_CAN_DIG) ) ) { underwater = g->m.has_flag("DIGGABLE", posx(), posy() ); } // Diggers turn the dirt into dirtmound if (digging()){ int factor = 0; switch (type->size) { case MS_TINY: factor = 100; break; case MS_SMALL: factor = 30; break; case MS_MEDIUM: factor = 6; break; case MS_LARGE: factor = 3; break; case MS_HUGE: factor = 1; break; } if (has_flag(MF_VERMIN)) { factor *= 100; } if (one_in(factor)) { g->m.ter_set(posx(), posy(), t_dirtmound); } } // Acid trail monsters leave... a trail of acid if (has_flag(MF_ACIDTRAIL)){ g->m.add_field(posx(), posy(), fd_acid, 3); } if (has_flag(MF_SLUDGETRAIL)) { for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { const int fstr = 3 - (abs(dx) + abs(dy)); if (fstr >= 2) { g->m.add_field(posx() + dx, posy() + dy, fd_sludge, fstr); } } } } if (has_flag(MF_LEAKSGAS)){ if (one_in(6)){ g->m.add_field(posx() + rng(-1,1), posy() + rng(-1, 1), fd_toxic_gas, 3); } } return 1; }
bool monster::move_to( const tripoint &p, bool force, const float stagger_adjustment ) { const bool digs = digging(); const bool flies = has_flag( MF_FLIES ); const bool on_ground = !digs && !flies; const bool climbs = has_flag( MF_CLIMBS ) && g->m.has_flag( TFLAG_NO_FLOOR, p ); // Allows climbing monsters to move on terrain with movecost <= 0 Creature *critter = g->critter_at( p, is_hallucination() ); if( g->m.has_flag( "CLIMBABLE", p ) ) { if( g->m.impassable( p ) && critter == nullptr ) { if( flies ) { moves -= 100; force = true; if( g->u.sees( *this ) ) { add_msg( _( "The %1$s flies over the %2$s." ), name().c_str(), g->m.has_flag_furn( "CLIMBABLE", p ) ? g->m.furnname( p ).c_str() : g->m.tername( p ).c_str() ); } } else if( has_flag( MF_CLIMBS ) ) { moves -= 150; force = true; if( g->u.sees( *this ) ) { add_msg( _( "The %1$s climbs over the %2$s." ), name().c_str(), g->m.has_flag_furn( "CLIMBABLE", p ) ? g->m.furnname( p ).c_str() : g->m.tername( p ).c_str() ); } } } } if( critter != nullptr && !force ) { return false; } // Make sure that we can move there, unless force is true. if( !force && !can_move_to( p ) ) { return false; } if( !force ) { // This adjustment is to make it so that monster movement speed relative to the player // is consistent even if the monster stumbles, // and the same regardless of the distance measurement mode. const int cost = stagger_adjustment * ( float )( climbs ? calc_climb_cost( pos(), p ) : calc_movecost( pos(), p ) ); if( cost > 0 ) { moves -= cost; } else { return false; } } //Check for moving into/out of water bool was_water = g->m.is_divable( pos() ); bool will_be_water = on_ground && can_submerge() && g->m.is_divable( p ); if( was_water && !will_be_water && g->u.sees( p ) ) { //Use more dramatic messages for swimming monsters add_msg( m_warning, _( "A %1$s %2$s from the %3$s!" ), name().c_str(), has_flag( MF_SWIMS ) || has_flag( MF_AQUATIC ) ? _( "leaps" ) : _( "emerges" ), g->m.tername( pos() ).c_str() ); } else if( !was_water && will_be_water && g->u.sees( p ) ) { add_msg( m_warning, _( "A %1$s %2$s into the %3$s!" ), name().c_str(), has_flag( MF_SWIMS ) || has_flag( MF_AQUATIC ) ? _( "dives" ) : _( "sinks" ), g->m.tername( p ).c_str() ); } setpos( p ); footsteps( p ); underwater = will_be_water; if( is_hallucination() ) { //Hallucinations don't do any of the stuff after this point return true; } // TODO: Make tanks stop taking damage from rubble, because it's just silly if( type->size != MS_TINY && on_ground ) { if( g->m.has_flag( "SHARP", pos() ) && !one_in( 4 ) ) { apply_damage( nullptr, bp_torso, rng( 1, 10 ) ); } if( g->m.has_flag( "ROUGH", pos() ) && one_in( 6 ) ) { apply_damage( nullptr, bp_torso, rng( 1, 2 ) ); } } if( g->m.has_flag( "UNSTABLE", p ) && on_ground ) { add_effect( effect_bouldering, 1, num_bp, true ); } else if( has_effect( effect_bouldering ) ) { remove_effect( effect_bouldering ); } g->m.creature_on_trap( *this ); if( !will_be_water && ( has_flag( MF_DIGS ) || has_flag( MF_CAN_DIG ) ) ) { underwater = g->m.has_flag( "DIGGABLE", pos() ); } // Diggers turn the dirt into dirtmound if( digging() ) { int factor = 0; switch( type->size ) { case MS_TINY: factor = 100; break; case MS_SMALL: factor = 30; break; case MS_MEDIUM: factor = 6; break; case MS_LARGE: factor = 3; break; case MS_HUGE: factor = 1; break; } if( one_in( factor ) ) { g->m.ter_set( pos(), t_dirtmound ); } } // Acid trail monsters leave... a trail of acid if( has_flag( MF_ACIDTRAIL ) ) { g->m.add_field( pos(), fd_acid, 3, 0 ); } if( has_flag( MF_SLUDGETRAIL ) ) { for( const tripoint &sludge_p : g->m.points_in_radius( pos(), 1 ) ) { const int fstr = 3 - ( abs( sludge_p.x - posx() ) + abs( sludge_p.y - posy() ) ); if( fstr >= 2 ) { g->m.add_field( sludge_p, fd_sludge, fstr, 0 ); } } } return true; }
void monster::knock_back_from( const tripoint &p ) { if( p == pos() ) { return; // No effect } if( is_hallucination() ) { die( nullptr ); return; } tripoint to = pos();; if( p.x < posx() ) { to.x++; } if( p.x > posx() ) { to.x--; } if( p.y < posy() ) { to.y++; } if( p.y > posy() ) { to.y--; } bool u_see = g->u.sees( to ); // First, see if we hit another monster if( monster *const z = g->critter_at<monster>( to ) ) { apply_damage( z, bp_torso, z->type->size ); add_effect( effect_stunned, 1 ); if( type->size > 1 + z->type->size ) { z->knock_back_from( pos() ); // Chain reaction! z->apply_damage( this, bp_torso, type->size ); z->add_effect( effect_stunned, 1 ); } else if( type->size > z->type->size ) { z->apply_damage( this, bp_torso, type->size ); z->add_effect( effect_stunned, 1 ); } z->check_dead_state(); if( u_see ) { add_msg( _( "The %1$s bounces off a %2$s!" ), name().c_str(), z->name().c_str() ); } return; } if( npc *const p = g->critter_at<npc>( to ) ) { apply_damage( p, bp_torso, 3 ); add_effect( effect_stunned, 1 ); p->deal_damage( this, bp_torso, damage_instance( DT_BASH, type->size ) ); if( u_see ) { add_msg( _( "The %1$s bounces off %2$s!" ), name().c_str(), p->name.c_str() ); } p->check_dead_state(); return; } // If we're still in the function at this point, we're actually moving a tile! if( g->m.has_flag_ter( TFLAG_DEEP_WATER, to ) ) { if( g->m.has_flag( "LIQUID", to ) && can_drown() ) { die( nullptr ); if( u_see ) { add_msg( _( "The %s drowns!" ), name().c_str() ); } } else if( has_flag( MF_AQUATIC ) ) { // We swim but we're NOT in water die( nullptr ); if( u_see ) { add_msg( _( "The %s flops around and dies!" ), name().c_str() ); } } } if( g->m.impassable( to ) ) { // It's some kind of wall. apply_damage( nullptr, bp_torso, type->size ); add_effect( effect_stunned, 2 ); if( u_see ) { add_msg( _( "The %1$s bounces off a %2$s." ), name().c_str(), g->m.obstacle_name( to ).c_str() ); } } else { // It's no wall setpos( to ); } check_dead_state(); }
void monster::process_effects() { // Monster only effects int mod = 1; for( auto &elem : effects ) { for( auto &_effect_it : elem.second ) { auto &it = _effect_it.second; // Monsters don't get trait-based reduction, but they do get effect based reduction bool reduced = has_effect(it.get_resist_effect()); mod_speed_bonus(it.get_mod("SPEED", reduced)); int val = it.get_mod("HURT", reduced); if (val > 0) { if(it.activated(calendar::turn, "HURT", val, reduced, mod)) { apply_damage(nullptr, bp_torso, val); } } std::string id = _effect_it.second.get_id(); // MATERIALS-TODO: use fire resistance if (id == "onfire") { if (made_of("flesh") || made_of("iflesh")) apply_damage( nullptr, bp_torso, rng( 3, 8 ) ); if (made_of("veggy")) apply_damage( nullptr, bp_torso, rng( 10, 20 ) ); if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") || made_of("wool")) apply_damage( nullptr, bp_torso, rng( 15, 40 ) ); } } } //If this monster has the ability to heal in combat, do it now. if( has_flag( MF_REGENERATES_50 ) ) { if( hp < type->hp ) { if( one_in( 2 ) && g->u.sees( *this ) ) { add_msg( m_warning, _( "The %s is visibly regenerating!" ), name().c_str() ); } hp += 50; if( hp > type->hp ) { hp = type->hp; } } } if( has_flag( MF_REGENERATES_10 ) ) { if( hp < type->hp ) { if( one_in( 2 ) && g->u.sees( *this ) ) { add_msg( m_warning, _( "The %s seems a little healthier." ), name().c_str() ); } hp += 10; if( hp > type->hp ) { hp = type->hp; } } } //Monster will regen morale and aggression if it is on max HP //It regens more morale and aggression if is currently fleeing. if( has_flag( MF_REGENMORALE ) && hp >= type->hp ) { if( is_fleeing( g->u ) ) { morale = type->morale; anger = type->agro; } if( morale <= type->morale ) { morale += 1; } if( anger <= type->agro ) { anger += 1; } if( morale < 0 ) { morale += 5; } if( anger < 0 ) { anger += 5; } } // If this critter dies in sunlight, check & assess damage. if( has_flag( MF_SUNDEATH ) && g->is_in_sunlight( posx(), posy() ) ) { if( g->u.sees( *this ) ) { add_msg( m_good, _( "The %s burns horribly in the sunlight!" ), name().c_str() ); } apply_damage( nullptr, bp_torso, 100 ); if( hp < 0 ) { hp = 0; } } Creature::process_effects(); }
// Why put this in a Big Switch? Why not let bionics have pointers to // functions, much like monsters and items? // // Well, because like diseases, which are also in a Big Switch, bionics don't // share functions.... void player::activate_bionic(int b) { bionic bio = my_bionics[b]; int power_cost = bionics[bio.id]->power_cost; if ((weapon.type->id == "bio_claws_weapon" && bio.id == "bio_claws_weapon") || (weapon.type->id == "bio_blade_weapon" && bio.id == "bio_blade_weapon")) { power_cost = 0; } if (power_level < power_cost) { if (my_bionics[b].powered) { add_msg(m_neutral, _("Your %s powers down."), bionics[bio.id]->name.c_str()); my_bionics[b].powered = false; } else { add_msg(m_info, _("You cannot power your %s"), bionics[bio.id]->name.c_str()); } return; } if (my_bionics[b].powered && my_bionics[b].charge > 0) { // Already-on units just lose a bit of charge my_bionics[b].charge--; } else { // Not-on units, or those with zero charge, have to pay the power cost if (bionics[bio.id]->charge_time > 0) { my_bionics[b].powered = true; my_bionics[b].charge = bionics[bio.id]->charge_time - 1; } power_level -= power_cost; } std::vector<point> traj; std::vector<std::string> good; std::vector<std::string> bad; int dirx, diry; item tmp_item; if(bio.id == "bio_painkiller") { pkill += 6; pain -= 2; if (pkill > pain) { pkill = pain; } } else if (bio.id == "bio_nanobots") { rem_disease("bleed"); healall(4); } else if (bio.id == "bio_night") { if (calendar::turn % 5) { add_msg(m_neutral, _("Artificial night generator active!")); } } else if (bio.id == "bio_resonator") { g->sound(posx, posy, 30, _("VRRRRMP!")); for (int i = posx - 1; i <= posx + 1; i++) { for (int j = posy - 1; j <= posy + 1; j++) { g->m.bash( i, j, 40 ); g->m.bash( i, j, 40 ); // Multibash effect, so that doors &c will fall g->m.bash( i, j, 40 ); if (g->m.is_destructable(i, j) && rng(1, 10) >= 4) { g->m.ter_set(i, j, t_rubble); } } } } else if (bio.id == "bio_time_freeze") { moves += power_level; power_level = 0; add_msg(m_good, _("Your speed suddenly increases!")); if (one_in(3)) { add_msg(m_bad, _("Your muscles tear with the strain.")); apply_damage( nullptr, bp_arm_l, rng( 5, 10 ) ); apply_damage( nullptr, bp_arm_r, rng( 5, 10 ) ); apply_damage( nullptr, bp_leg_l, rng( 7, 12 ) ); apply_damage( nullptr, bp_leg_r, rng( 7, 12 ) ); apply_damage( nullptr, bp_torso, rng( 5, 15 ) ); } if (one_in(5)) { add_disease("teleglow", rng(50, 400)); } } else if (bio.id == "bio_teleport") { g->teleport(); add_disease("teleglow", 300); } // TODO: More stuff here (and bio_blood_filter) else if(bio.id == "bio_blood_anal") { WINDOW *w = newwin(20, 40, 3 + ((TERMY > 25) ? (TERMY - 25) / 2 : 0), 10 + ((TERMX > 80) ? (TERMX - 80) / 2 : 0)); draw_border(w); if (has_disease("fungus")) { bad.push_back(_("Fungal Parasite")); } if (has_disease("dermatik")) { bad.push_back(_("Insect Parasite")); } if (has_effect("stung")) { bad.push_back(_("Stung")); } if (has_effect("poison")) { bad.push_back(_("Poison")); } if (radiation > 0) { bad.push_back(_("Irradiated")); } if (has_disease("pkill1")) { good.push_back(_("Minor Painkiller")); } if (has_disease("pkill2")) { good.push_back(_("Moderate Painkiller")); } if (has_disease("pkill3")) { good.push_back(_("Heavy Painkiller")); } if (has_disease("pkill_l")) { good.push_back(_("Slow-Release Painkiller")); } if (has_disease("drunk")) { good.push_back(_("Alcohol")); } if (has_disease("cig")) { good.push_back(_("Nicotine")); } if (has_disease("meth")) { good.push_back(_("Methamphetamines")); } if (has_disease("high")) { good.push_back(_("Intoxicant: Other")); } if (has_disease("weed_high")) { good.push_back(_("THC Intoxication")); } if (has_disease("hallu") || has_disease("visuals")) { bad.push_back(_("Magic Mushroom")); } if (has_disease("iodine")) { good.push_back(_("Iodine")); } if (has_disease("datura")) { good.push_back(_("Anticholinergic Tropane Alkaloids")); } if (has_disease("took_xanax")) { good.push_back(_("Xanax")); } if (has_disease("took_prozac")) { good.push_back(_("Prozac")); } if (has_disease("took_flumed")) { good.push_back(_("Antihistamines")); } if (has_disease("adrenaline")) { good.push_back(_("Adrenaline Spike")); } if (has_disease("tapeworm")) { // This little guy is immune to the blood filter though, as he lives in your bowels. good.push_back(_("Intestinal Parasite")); } if (has_disease("bloodworms")) { good.push_back(_("Hemolytic Parasites")); } if (has_disease("brainworm")) { // This little guy is immune to the blood filter too, as he lives in your brain. good.push_back(_("Intracranial Parasite")); } if (has_disease("paincysts")) { // These little guys are immune to the blood filter too, as they live in your muscles. good.push_back(_("Intramuscular Parasites")); } if (has_disease("tetanus")) { // Tetanus infection. good.push_back(_("Clostridium Tetani Infection")); } if (good.empty() && bad.empty()) { mvwprintz(w, 1, 1, c_white, _("No effects.")); } else { for (unsigned line = 1; line < 39 && line <= good.size() + bad.size(); line++) { if (line <= bad.size()) { mvwprintz(w, line, 1, c_red, "%s", bad[line - 1].c_str()); } else { mvwprintz(w, line, 1, c_green, "%s", good[line - 1 - bad.size()].c_str()); } } } wrefresh(w); refresh(); getch(); delwin(w); } else if(bio.id == "bio_blood_filter") { add_msg(m_neutral, _("You activate your blood filtration system.")); rem_disease("fungus"); rem_disease("dermatik"); rem_disease("bloodworms"); rem_disease("tetanus"); remove_effect("poison"); remove_effect("stung"); rem_disease("pkill1"); rem_disease("pkill2"); rem_disease("pkill3"); rem_disease("pkill_l"); rem_disease("drunk"); rem_disease("cig"); rem_disease("high"); rem_disease("hallu"); rem_disease("visuals"); rem_disease("iodine"); rem_disease("datura"); rem_disease("took_xanax"); rem_disease("took_prozac"); rem_disease("took_flumed"); rem_disease("adrenaline"); rem_disease("meth"); pkill = 0; stim = 0; } else if(bio.id == "bio_evap") { item water = item("water_clean", 0); int humidity = g->weatherGen.get_weather(pos(), calendar::turn).humidity; int water_charges = (humidity * 3.0) / 100.0 + 0.5; // At 50% relative humidity or more, the player will draw 2 units of water // At 16% relative humidity or less, the player will draw 0 units of water water.charges = water_charges; if (water_charges == 0) { add_msg_if_player(m_bad, _("There was not enough moisture in the air from which to draw water!")); } if (g->handle_liquid(water, true, false)) { moves -= 100; } else if (query_yn(_("Drink from your hands?"))) { inv.push_back(water); consume(inv.position_by_type(water.typeId())); moves -= 350; } else if (water.charges == water_charges && water_charges != 0) { power_level += bionics["bio_evap"]->power_cost; } } else if(bio.id == "bio_lighter") { if(!choose_adjacent(_("Start a fire where?"), dirx, diry) || (!g->m.add_field(dirx, diry, fd_fire, 1))) { add_msg_if_player(m_info, _("You can't light a fire there.")); power_level += bionics["bio_lighter"]->power_cost; } } if(bio.id == "bio_leukocyte") { add_msg(m_neutral, _("You activate your leukocyte breeder system.")); g->u.set_healthy(std::min(100, g->u.get_healthy() + 2)); g->u.mod_healthy_mod(20); } if(bio.id == "bio_geiger") { add_msg(m_info, _("Your radiation level: %d"), radiation); } if(bio.id == "bio_radscrubber") { add_msg(m_neutral, _("You activate your radiation scrubber system.")); if (radiation > 4) { radiation -= 5; } else { radiation = 0; } } if(bio.id == "bio_adrenaline") { add_msg(m_neutral, _("You activate your adrenaline pump.")); if (has_disease("adrenaline")) { add_disease("adrenaline", 50); } else { add_disease("adrenaline", 200); } } else if(bio.id == "bio_claws") { if (weapon.type->id == "bio_claws_weapon") { add_msg(m_neutral, _("You withdraw your claws.")); weapon = ret_null; } else if (weapon.has_flag ("NO_UNWIELD")) { add_msg(m_info, _("Deactivate your %s first!"), weapon.tname().c_str()); power_level += bionics[bio.id]->power_cost; return; } else if(weapon.type->id != "null") { add_msg(m_warning, _("Your claws extend, forcing you to drop your %s."), weapon.tname().c_str()); g->m.add_item_or_charges(posx, posy, weapon); weapon = item("bio_claws_weapon", 0); weapon.invlet = '#'; } else { add_msg(m_neutral, _("Your claws extend!")); weapon = item("bio_claws_weapon", 0); weapon.invlet = '#'; } } else if(bio.id == "bio_blade") { if (weapon.type->id == "bio_blade_weapon") { add_msg(m_neutral, _("You retract your blade.")); weapon = ret_null; } else if (weapon.has_flag ("NO_UNWIELD")) { add_msg(m_info, _("Deactivate your %s first!"), weapon.tname().c_str()); power_level += bionics[bio.id]->power_cost; return; } else if(weapon.type->id != "null") { add_msg(m_warning, _("Your blade extends, forcing you to drop your %s."), weapon.tname().c_str()); g->m.add_item_or_charges(posx, posy, weapon); weapon = item("bio_blade_weapon", 0); weapon.invlet = '#'; } else { add_msg(m_neutral, _("You extend your blade!")); weapon = item("bio_blade_weapon", 0); weapon.invlet = '#'; } } else if(bio.id == "bio_blaster") { tmp_item = weapon; weapon = item("bio_blaster_gun", 0); g->refresh_all(); g->plfire(false); if(weapon.charges == 1) { // not fired power_level += bionics[bio.id]->power_cost; } weapon = tmp_item; } else if (bio.id == "bio_laser") { tmp_item = weapon; weapon = item("bio_laser_gun", 0); g->refresh_all(); g->plfire(false); if(weapon.charges == 1) { // not fired power_level += bionics[bio.id]->power_cost; } weapon = tmp_item; } else if(bio.id == "bio_chain_lightning") { tmp_item = weapon; weapon = item("bio_lightning", 0); g->refresh_all(); g->plfire(false); if(weapon.charges == 1) { // not fired power_level += bionics[bio.id]->power_cost; } weapon = tmp_item; } else if (bio.id == "bio_emp") { if(choose_adjacent(_("Create an EMP where?"), dirx, diry)) { g->emp_blast(dirx, diry); } else { power_level += bionics["bio_emp"]->power_cost; } } else if (bio.id == "bio_hydraulics") { add_msg(m_good, _("Your muscles hiss as hydraulic strength fills them!")); // Sound of hissing hydraulic muscle! (not quite as loud as a car horn) g->sound(posx, posy, 19, _("HISISSS!")); } else if (bio.id == "bio_water_extractor") { bool extracted = false; for (std::vector<item>::iterator it = g->m.i_at(posx, posy).begin(); it != g->m.i_at(posx, posy).end(); ++it) { if (it->type->id == "corpse" ) { int avail = 0; if ( it->item_vars.find("remaining_water") != it->item_vars.end() ) { avail = atoi ( it->item_vars["remaining_water"].c_str() ); } else { avail = it->volume() / 2; } if(avail > 0 && query_yn(_("Extract water from the %s"), it->tname().c_str())) { item water = item("water_clean", 0); if (g->handle_liquid(water, true, true)) { moves -= 100; } else if (query_yn(_("Drink directly from the condenser?"))) { inv.push_back(water); consume(inv.position_by_type(water.typeId())); moves -= 350; } extracted = true; avail--; it->item_vars["remaining_water"] = string_format("%d", avail); break; } } } if (!extracted) { power_level += bionics["bio_water_extractor"]->power_cost; } } else if(bio.id == "bio_magnet") { for (int i = posx - 10; i <= posx + 10; i++) { for (int j = posy - 10; j <= posy + 10; j++) { if (g->m.i_at(i, j).size() > 0) { int t; //not sure why map:sees really needs this, but w/e if (g->m.sees(i, j, posx, posy, -1, t)) { traj = line_to(i, j, posx, posy, t); } else { traj = line_to(i, j, posx, posy, 0); } } traj.insert(traj.begin(), point(i, j)); for (unsigned k = 0; k < g->m.i_at(i, j).size(); k++) { if (g->m.i_at(i, j)[k].made_of("iron") || g->m.i_at(i, j)[k].made_of("steel")) { tmp_item = g->m.i_at(i, j)[k]; g->m.i_rem(i, j, k); std::vector<point>::iterator it; for (it = traj.begin(); it != traj.end(); ++it) { int index = g->mon_at(it->x, it->y); if (index != -1) { g->zombie(index).apply_damage( this, bp_torso, tmp_item.weight() / 225 ); g->m.add_item_or_charges(it->x, it->y, tmp_item); break; } else if (it != traj.begin() && g->m.move_cost(it->x, it->y) == 0) { g->m.bash( it->x, it->y, tmp_item.weight() / 225 ); if (g->m.move_cost(it->x, it->y) == 0) { g->m.add_item_or_charges((it - 1)->x, (it - 1)->y, tmp_item); break; } } } if (it == traj.end()) { g->m.add_item_or_charges(posx, posy, tmp_item); } } } } } } else if(bio.id == "bio_lockpick") { if(!choose_adjacent(_("Activate your bio lockpick where?"), dirx, diry)) { power_level += bionics["bio_lockpick"]->power_cost; return; } ter_id type = g->m.ter(dirx, diry); if (type == t_door_locked || type == t_door_locked_alarm || type == t_door_locked_interior ) { moves -= 40; std::string door_name = rm_prefix(_("<door_name>door")); add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."), door_name.c_str()); g->m.ter_set(dirx, diry, t_door_c); // Locked metal doors are the Lab and Bunker entries. Those need to stay locked. } else if(type == t_door_bar_locked) { moves -= 40; std::string door_name = rm_prefix(_("<door_name>door")); add_msg_if_player(m_neutral, _("The %s swings open..."), door_name.c_str()); //Could better copy the messages from lockpick.... g->m.ter_set(dirx, diry, t_door_bar_o); } else if(type == t_chaingate_l) { moves -= 40; std::string gate_name = rm_prefix (_("<door_name>gate")); add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."), gate_name.c_str()); g->m.ter_set(dirx, diry, t_chaingate_c); } else if(type == t_door_c) { add_msg(m_info, _("That door isn't locked.")); } else { add_msg_if_player(m_neutral, _("You can't unlock that %s."), g->m.tername(dirx, diry).c_str()); } } else if(bio.id == "bio_flashbang") { add_msg_if_player(m_neutral, _("You activate your integrated flashbang generator!")); g->flashbang(posx, posy, true); } else if(bio.id == "bio_shockwave") { g->shockwave(posx, posy, 3, 4, 2, 8, true); add_msg_if_player(m_neutral, _("You unleash a powerful shockwave!")); } }
void curr_attack() { // see if nv status allow for attack switch (CURR_POKEMON->nv.nvstatus) { case NON_S: case BRN_S: case PSN_S: case TXC_S: break; case FRZ_S: if (roll(.2)) { sprintf(msg, "%s thawed out!", CURR_PNAME); send(); CURR_POKEMON->nv.nvstatus = NON_S; break; } else { sprintf(msg, "%s is frozen solid!", CURR_PNAME); send(); return; } case PAR_S: if (roll(.25)) { sprintf(msg, "%s is fully paralyzed!", CURR_PNAME); send(); return; } else { break; } case SLP_S: if (CURR_POKEMON->nv.nv_arg > 0) { sprintf(msg, "%s is fast asleep!", CURR_PNAME); send(); CURR_POKEMON->nv.nv_arg--; return; } else { sprintf(msg, "%s woke up!", CURR_PNAME); send(); CURR_POKEMON->nv.nvstatus = NON_S; break; } case FNT_S: // should never happen default: return; } // see if v status allows for attack if (CURR_POKEMON->v.is_flinch) { sprintf(msg, "%s flinched!", CURR_PNAME); send(); CURR_POKEMON->v.is_flinch = false; return; } if (CURR_POKEMON->v.is_recharge) { sprintf(msg, "%s is recharging!", CURR_PNAME); send(); CURR_POKEMON->v.is_recharge = false; return; } if (CURR_POKEMON->v.is_confuse) { sprintf(msg, "%s is confused!", CURR_PNAME); send(); if (roll(.25)) { // this is not quite how it works in Pokemon sprintf(msg, "%s snapped out of confusion!", CURR_PNAME); send(); CURR_POKEMON->v.is_confuse = false; } else { if (roll(.5)) { sprintf(msg, "%s hurt itself in confusion!", CURR_PNAME); send(); int damage = calc_damage(CURR_POKEMON, CURR_POKEMON, 40, PHYSICAL_MT); // printf("[%s applied %i damage to himself]", CURR_PNAME, damage); apply_damage(CURR_POKEMON, damage); return; } } } move_s *move = curr_move(); sprintf(msg, "%s used %s!", CURR_PNAME, move->name); send(); // check if unique if (move->unique) { switch (move->unique) { default: // no unique moves at the moment return; } } // check accuracy if (is_aggressive(move)) { if (!roll(move->accuracy * calc_accuracy(CURR_POKEMON, OTHR_POKEMON))) { // swift support? sprintf(msg, "It missed!"); send(); return; } if (move->movetype != STATUS_MT) { int damage = calc_damage(CURR_POKEMON, OTHR_POKEMON, move->damage, move->movetype); double stab_bonus = (has_type(CURR_POKEMON, move->type) ? 1.5 : 1); // STAB bonus double effective_bonus = calc_effective(move->type, OTHR_POKEMON); // type bonus double crit_chance = (move->effect == HIGH_CRIT_E2 ? .125 : .0625); double crit_bonus = (roll(crit_chance) ? 1.5 : 1.0); // this is not quite how it works in Pokemon double rndm = (rand() % 16 + 85) / 100.0; // printf("%i, %lf, %lf, %lf, %lf", damage, stab_bonus, effective_bonus, crit_bonus, rndm); int total_damage = (int)(damage * stab_bonus * effective_bonus * crit_bonus * rndm); // if burnt, physical damage output is halfed if (CURR_POKEMON->nv.nvstatus == BRN_S && move->movetype == PHYSICAL_MT) { total_damage /= 2; } if (effective_bonus > 1) { sprintf(msg, "It's super effective!"); send(); } else if (effective_bonus == 0) { sprintf(msg, "It has no effect!"); send(); } else if (effective_bonus < 1) { sprintf(msg, "It's not very effective!"); send(); } if (crit_bonus > 1) { sprintf(msg, "Critical hit!"); send(); } // printf("[%s applies %i damage to %s]", CURR_PNAME, total_damage, OTHR_PNAME); apply_damage(OTHR_POKEMON, total_damage); } else { if (calc_effective(move->type, OTHR_POKEMON) == 0) { // thunder wave can't work on ground sprintf(msg, "It has no effect!"); send(); return; } } } int calculation; // can be used for some of the switch cases // check secondary effect if (move->effect != NON_E2) { if (roll(move->chance)) { switch (move->effect) { case APPLY_BRN_E2: apply_nvstatus(OTHR_POKEMON, BRN_S); break; case APPLY_FRZ_E2: apply_nvstatus(OTHR_POKEMON, FRZ_S); break; case APPLY_PAR_E2: apply_nvstatus(OTHR_POKEMON, PAR_S); break; case APPLY_PSN_E2: apply_nvstatus(OTHR_POKEMON, PSN_S); break; case APPLY_TXC_E2: apply_nvstatus(OTHR_POKEMON, TXC_S); break; case APPLY_SLP_E2: apply_nvstatus(OTHR_POKEMON, SLP_S); break; case APPLY_FLINCH_E2: OTHR_POKEMON->v.is_flinch = true; break; case APPLY_CONFUSE_E2: sprintf(msg, "%s became confused!", OTHR_PNAME); send(); OTHR_POKEMON->v.is_confuse = true; break; case HIGH_CRIT_E2: break; // this doesn't happen here case SELF_KILL_E2: apply_nvstatus(CURR_POKEMON, FNT_S); break; case SELF_ATTACK_E2: apply_attackstage(CURR_POKEMON, move->m_arg); break; case SELF_DEFENSE_E2: apply_defensestage(CURR_POKEMON, move->m_arg); break; case SELF_SATTACK_E2: apply_sattackstage(CURR_POKEMON, move->m_arg); break; case SELF_SDEFENSE_E2: apply_sdefensestage(CURR_POKEMON, move->m_arg); break; case SELF_SPEED_E2: apply_speedstage(CURR_POKEMON, move->m_arg); break; case SELF_ACCURACY_E2: apply_accuracystage(CURR_POKEMON, move->m_arg); break; case SELF_EVASION_E2: apply_evasionstage(CURR_POKEMON, move->m_arg); break; case OTHR_ATTACK_E2: apply_attackstage(OTHR_POKEMON, move->m_arg); break; case OTHR_DEFENSE_E2: apply_defensestage(OTHR_POKEMON, move->m_arg); break; case OTHR_SATTACK_E2: apply_sattackstage(OTHR_POKEMON, move->m_arg); break; case OTHR_SDEFENSE_E2: apply_sdefensestage(OTHR_POKEMON, move->m_arg); break; case OTHR_SPEED_E2: apply_speedstage(OTHR_POKEMON, move->m_arg); break; case OTHR_ACCURACY_E2: apply_accuracystage(OTHR_POKEMON, move->m_arg); break; case OTHR_EVASION_E2: apply_evasionstage(OTHR_POKEMON, move->m_arg); break; case SELF_ATTACK_SATTACK_E2: apply_attackstage(CURR_POKEMON, move->m_arg); apply_sattackstage(CURR_POKEMON, move->m_arg); break; case HAZE_E2: reset_stages(CURR_POKEMON); reset_stages(OTHR_POKEMON); break; case RECOIL_E2: calculation = battle.last_dmg / move->m_arg; // pos is recoil, neg is heal if (calculation > 0) { sprintf(msg, "%s was hit with recoil!", CURR_PNAME); send(); // printf("[%s took %i damage in recoil]", CURR_PNAME, calculation); } else if (calculation < 0) { sprintf(msg, "%s regained health!", CURR_PNAME); send(); // printf("[%s restored %i damage]", CURR_PNAME, calculation); } apply_damage(CURR_POKEMON, calculation); break; // this doesn't happen here case RECHARGE_E2: CURR_POKEMON->v.is_recharge = true; break; case NON_E2: // shouldn't happen break; } } } }