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); if( dam.effects.count("NOGIB") ) { total_damage = std::min( total_damage, get_hp() + 1 ); } apply_damage(source, bp, side, total_damage); return dealt_damage_instance(dealt_dams); }
void Building::draw_hp(){ if(get_hp()<get_max_hp()){ Display::CubeLight* building_light=new Display::CubeLight(); building_light->color=glm::vec3(3,0,0); building_light->cube_size=glm::vec3( Map::CUBE_SIZE*1.0*get_cube_large_size().x, Map::CUBE_SIZE*1.0*get_cube_large_size().y* ((get_max_hp()-get_hp())/(double)get_max_hp()), Map::CUBE_SIZE*1.0*get_cube_large_size().z); building_light->pos=glm::vec3( x*Map::CUBE_SIZE+0.49*building_light->cube_size.x, y*Map::CUBE_SIZE+0.49*building_light->cube_size.y, z*Map::CUBE_SIZE+0.49*building_light->cube_size.z); Display::Draw::get_cur_object()->lightControl->push_temp_light(building_light); } }
void Damageable::default_render_health(Graphic& graphic, const Color& color, float frames_count) const { if (has_hp()) { Box health_box; health_box.set_size(50.f * get_hp() / get_default_hp(), 5.f); health_box.set_left_top( get_position().x - health_box.get_width() / 2 + get_current_speed().x * frames_count, get_position().y - get_circle().get_radius() + get_current_speed().y * frames_count ); graphic.render_box(health_box, color); } }
void HutObj::update(){ if(get_hp() < 0){ set_dead(true); } if(get_dead()){ btTransform trans; get_body()->getMotionState()->getWorldTransform(trans); if( !spawn_list.empty() ){ GameObj* new_obj = new HutObj( spawn_list, col_list, trans.getOrigin() ); spawn_new_obj( new_obj ); } } }
void new_ship( char *t ) { Sint32 frames; Sint32 delay; Sint32 speed; Sint32 x, y; x = screen_width() / 2; y = screen_height() - 50; frames = get_num_frames( t ); delay = get_frame_delay( t ); speed = get_speed( t ); ship.hp = get_hp( t ) * PLAYER_HP_FACTOR; ship.hp_max = ship.hp; ship.type = strdup( t ); ship.left = new_sprite_array( x, y, frames, get_left( t ), delay ); if( ship.left == NULL ) { fprintf( stderr, "Error creating new sprite: %s.\n", SDL_GetError() ); exit( 1 ); } set_speed( ship.left, speed ); no_off_screen( ship.left ); ship.right = new_sprite_array( x, y, frames, get_right( t ), delay ); if( ship.right == NULL ) { fprintf( stderr, "Error creating new sprite: %s.\n", SDL_GetError() ); exit( 1 ); } set_speed( ship.right, speed ); no_off_screen( ship.right ); ship.center = new_sprite_array( x, y, frames, get_center( t ), delay ); if( ship.center == NULL ) { fprintf( stderr, "Error creating new sprite: %s.\n", SDL_GetError() ); exit( 1 ); } set_speed( ship.center, speed ); no_off_screen( ship.center ); ship.current = ship.center; ship_center(); }
/** * Attempts to harm a creature with a projectile. * * @param source Pointer to the creature who shot the projectile. * @param attack A structure describing the attack and its results. */ void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack &attack ) { const double missed_by = attack.missed_by; if( missed_by >= 1.0 ) { // Total miss return; } const projectile &proj = attack.proj; dealt_damage_instance &dealt_dam = attack.dealt_dam; const auto &proj_effects = proj.proj_effects; const bool u_see_this = g->u.sees(*this); const int avoid_roll = dodge_roll(); // Do dice(10, speed) instead of dice(speed, 10) because speed could potentially be > 10000 const int diff_roll = dice( 10, proj.speed ); // Partial dodge, capped at [0.0, 1.0], added to missed_by const double dodge_rescaled = avoid_roll / static_cast<double>( diff_roll ); const double goodhit = missed_by + std::max( 0.0, std::min( 1.0, dodge_rescaled ) ) ; if( goodhit >= 1.0 ) { // "Avoid" rather than "dodge", because it includes removing self from the line of fire // rather than just Matrix-style bullet dodging if( source != nullptr && g->u.sees( *source ) ) { add_msg_player_or_npc( m_warning, _("You avoid %s projectile!"), _("<npcname> avoids %s projectile."), source->disp_name(true).c_str() ); } else { add_msg_player_or_npc( m_warning, _("You avoid an incoming projectile!"), _("<npcname> avoids an incoming projectile.") ); } attack.missed_by = 1.0; // Arbitrary value return; } // Bounce applies whether it does damage or not. if( proj.proj_effects.count( "BOUNCE" ) ) { add_effect( effect_bounced, 1_turns ); } body_part bp_hit; double hit_value = missed_by + rng_float(-0.5, 0.5); // Headshots considered elsewhere if( hit_value <= 0.4 ) { bp_hit = bp_torso; } else if (one_in(4)) { if( one_in(2)) { bp_hit = bp_leg_l; } else { bp_hit = bp_leg_r; } } else { if( one_in(2)) { bp_hit = bp_arm_l; } else { bp_hit = bp_arm_r; } } double damage_mult = 1.0; std::string message = ""; game_message_type gmtSCTcolor = m_neutral; if( goodhit < accuracy_headshot ) { message = _("Headshot!"); gmtSCTcolor = m_headshot; damage_mult *= rng_float(1.95, 2.05); bp_hit = bp_head; // headshot hits the head, of course } else if( goodhit < accuracy_critical ) { message = _("Critical!"); gmtSCTcolor = m_critical; damage_mult *= rng_float(1.5, 2.0); } else if( goodhit < accuracy_goodhit ) { message = _("Good hit!"); gmtSCTcolor = m_good; damage_mult *= rng_float(1, 1.5); } else if( goodhit < accuracy_standard ) { damage_mult *= rng_float(0.5, 1); } else if( goodhit < accuracy_grazing ) { message = _("Grazing hit."); gmtSCTcolor = m_grazing; damage_mult *= rng_float(0, .25); } if( source != nullptr && !message.empty() ) { source->add_msg_if_player(m_good, message.c_str()); } attack.missed_by = goodhit; // copy it, since we're mutating damage_instance impact = proj.impact; if( damage_mult > 0.0f && proj_effects.count( "NO_DAMAGE_SCALING" ) ) { damage_mult = 1.0f; } impact.mult_damage(damage_mult); if( proj_effects.count( "NOGIB" ) > 0 ) { float dmg_ratio = (float)impact.total_damage() / get_hp_max( player::bp_to_hp( bp_hit ) ); if( dmg_ratio > 1.25f ) { impact.mult_damage( 1.0f / dmg_ratio ); } } dealt_dam = deal_damage(source, bp_hit, impact); dealt_dam.bp_hit = bp_hit; // Apply ammo effects to target. if (proj.proj_effects.count("FLAME")) { if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) || made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) || made_of( material_id( "wood" ) ) ) { add_effect( effect_onfire, rng( 8_turns, 20_turns ), bp_hit ); } else if (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) { add_effect( effect_onfire, rng( 5_turns, 10_turns ), bp_hit ); } } else if (proj.proj_effects.count("INCENDIARY") ) { if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) || made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) || made_of( material_id( "wood" ) ) ) { add_effect( effect_onfire, rng( 2_turns, 6_turns ), bp_hit ); } else if ( (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) && one_in(4) ) { add_effect( effect_onfire, rng( 1_turns, 4_turns ), bp_hit ); } } else if (proj.proj_effects.count("IGNITE")) { if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) || made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) || made_of( material_id( "wood" ) ) ) { add_effect( effect_onfire, 6_turns, bp_hit ); } else if (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) { add_effect( effect_onfire, 10_turns, bp_hit ); } } if( bp_hit == bp_head && proj_effects.count( "BLINDS_EYES" ) ) { // TODO: Change this to require bp_eyes add_env_effect( effect_blind, bp_eyes, 5, rng( 3_turns, 10_turns ) ); } if( proj_effects.count( "APPLY_SAP" ) ) { add_effect( effect_sap, 1_turns * dealt_dam.total_damage() ); } int stun_strength = 0; if (proj.proj_effects.count("BEANBAG")) { stun_strength = 4; } if (proj.proj_effects.count("LARGE_BEANBAG")) { stun_strength = 16; } if( stun_strength > 0 ) { switch( get_size() ) { case MS_TINY: stun_strength *= 4; break; case MS_SMALL: stun_strength *= 2; break; case MS_MEDIUM: default: break; case MS_LARGE: stun_strength /= 2; break; case MS_HUGE: stun_strength /= 4; break; } add_effect( effect_stunned, 1_turns * rng( stun_strength / 2, stun_strength ) ); } if(u_see_this) { if( damage_mult == 0 ) { if( source != nullptr ) { add_msg( source->is_player() ? _("You miss!") : _("The shot misses!") ); } } else if( dealt_dam.total_damage() == 0 ) { //~ 1$ - monster name, 2$ - character's bodypart or monster's skin/armor add_msg( _("The shot reflects off %1$s %2$s!"), disp_name(true).c_str(), is_monster() ? skin_name().c_str() : body_part_name_accusative(bp_hit).c_str() ); } else if( is_player() ) { //monster hits player ranged //~ Hit message. 1$s is bodypart name in accusative. 2$d is damage value. add_msg_if_player(m_bad, _( "You were hit in the %1$s for %2$d damage." ), body_part_name_accusative(bp_hit).c_str(), dealt_dam.total_damage()); } else if( source != nullptr ) { if( source->is_player() ) { //player hits monster ranged SCT.add(posx(), posy(), direction_from(0, 0, posx() - source->posx(), posy() - source->posy()), get_hp_bar(dealt_dam.total_damage(), get_hp_max(), true).first, m_good, message, gmtSCTcolor); if (get_hp() > 0) { SCT.add(posx(), posy(), direction_from(0, 0, posx() - source->posx(), posy() - source->posy()), get_hp_bar(get_hp(), get_hp_max(), true).first, m_good, //~ "hit points", used in scrolling combat text _("hp"), m_neutral, "hp"); } else { SCT.removeCreatureHP(); } add_msg(m_good, _("You hit %s for %d damage."), disp_name().c_str(), dealt_dam.total_damage()); } else if( u_see_this ) { //~ 1$ - shooter, 2$ - target add_msg(_("%1$s shoots %2$s."), source->disp_name().c_str(), disp_name().c_str()); } } } check_dead_state(); attack.hit_critter = this; attack.missed_by = goodhit; }
void new_enemy( Sint32 x, Sint32 y, const char *t ) { /* Paths to directions. */ Sint32 frames; Sint32 delay; Uint32 speed; ENEMY *e; /* Create new ENEMY and add it to the list. */ e = (ENEMY*) malloc( sizeof(ENEMY) ); e->flags = 0; e->next = head; head = e; /* Set defaults. */ e->hp = 1; e->type = "no_type"; e->move_funct = NULL; speed = 1; delay = 100; frames = 1; memset( e->move_vars, -1, NUM_MOVE_VARS ); frames = get_num_frames( t ); delay = get_frame_delay( t ); speed = get_speed( t ); e->hp = get_hp( t ); e->type = strdup( t ); e->move_funct = get_move_funct( t ); /* Make the left facing sprite */ e->left = new_sprite_array( x, y, frames, get_left( t ), delay ); if( e->left == NULL ) { fprintf( stderr, "Error creating new sprite: %s.\n", SDL_GetError() ); exit(1); } set_speed( e->left, speed ); /* Make the left facing sprite */ e->right = new_sprite_array( x, y, frames, get_right( t ), delay ); if( e->right == NULL ) { fprintf( stderr, "Error creating new sprite: %s.\n", SDL_GetError() ); exit(1); } set_speed( e->right, speed ); /* Make the left facing sprite */ e->center = new_sprite_array( x, y, frames, get_center( t ), delay ); if( e->center == NULL ) { fprintf( stderr, "Error creating new sprite: %s.\n", SDL_GetError() ); exit(1); } set_speed( e->center, speed ); e->current = e->center; enemy_center( e ); num_enemies++; }
/** * Attempts to harm a creature with a projectile. * * @param source Pointer to the creature who shot the projectile. * @param missed_by Deviation of the projectile. * @param proj Reference to the projectile hitting the creature. * @param dealt_dam A reference storing the damage dealt. * @return 0 signals that the projectile should stop, * 1 signals that the projectile should not stop (i.e. dodged, passed through). */ int Creature::deal_projectile_attack(Creature *source, double missed_by, const projectile &proj, dealt_damage_instance &dealt_dam) { bool u_see_this = g->u.sees(*this); body_part bp_hit; // do 10,speed because speed could potentially be > 10000 if (dodge_roll() >= dice(10, proj.speed)) { if (is_player()) add_msg(_("You dodge %s projectile!"), source->disp_name(true).c_str()); else if (u_see_this) add_msg(_("%s dodges %s projectile."), disp_name().c_str(), source->disp_name(true).c_str()); return 1; } // Bounce applies whether it does damage or not. if (proj.proj_effects.count("BOUNCE")) { add_effect("bounced", 1); } double hit_value = missed_by + rng_float(-0.5, 0.5); // headshots considered elsewhere if (hit_value <= 0.4) { bp_hit = bp_torso; } else if (one_in(4)) { if( one_in(2)) { bp_hit = bp_leg_l; } else { bp_hit = bp_leg_r; } } else { if( one_in(2)) { bp_hit = bp_arm_l; } else { bp_hit = bp_arm_r; } } double monster_speed_penalty = std::max(double(get_speed()) / 80., 1.0); double goodhit = missed_by / monster_speed_penalty; double damage_mult = 1.0; std::string message = ""; game_message_type gmtSCTcolor = m_neutral; if (goodhit <= .1) { message = _("Headshot!"); source->add_msg_if_player(m_good, message.c_str()); gmtSCTcolor = m_headshot; damage_mult *= rng_float(2.45, 3.35); bp_hit = bp_head; // headshot hits the head, of course } else if (goodhit <= .2) { message = _("Critical!"); source->add_msg_if_player(m_good, message.c_str()); gmtSCTcolor = m_critical; damage_mult *= rng_float(1.75, 2.3); } else if (goodhit <= .4) { message = _("Good hit!"); source->add_msg_if_player(m_good, message.c_str()); gmtSCTcolor = m_good; damage_mult *= rng_float(1, 1.5); } else if (goodhit <= .6) { damage_mult *= rng_float(0.5, 1); } else if (goodhit <= .8) { message = _("Grazing hit."); source->add_msg_if_player(m_good, message.c_str()); gmtSCTcolor = m_grazing; damage_mult *= rng_float(0, .25); } else { damage_mult *= 0; } // copy it, since we're mutating damage_instance impact = proj.impact; if( item(proj.ammo->id, 0).has_flag("NOGIB") ) { impact.add_effect("NOGIB"); } impact.mult_damage(damage_mult); dealt_dam = deal_damage(source, bp_hit, impact); dealt_dam.bp_hit = bp_hit; // Apply ammo effects to target. const std::string target_material = get_material(); if (proj.proj_effects.count("FLAME")) { if (0 == target_material.compare("veggy") || 0 == target_material.compare("cotton") || 0 == target_material.compare("wool") || 0 == target_material.compare("paper") || 0 == target_material.compare("wood" ) ) { add_effect("onfire", rng(8, 20)); } else if (0 == target_material.compare("flesh") || 0 == target_material.compare("iflesh") ) { add_effect("onfire", rng(5, 10)); } } else if (proj.proj_effects.count("INCENDIARY") ) { if (0 == target_material.compare("veggy") || 0 == target_material.compare("cotton") || 0 == target_material.compare("wool") || 0 == target_material.compare("paper") || 0 == target_material.compare("wood") ) { add_effect("onfire", rng(2, 6)); } else if ( (0 == target_material.compare("flesh") || 0 == target_material.compare("iflesh") ) && one_in(4) ) { add_effect("onfire", rng(1, 4)); } } else if (proj.proj_effects.count("IGNITE")) { if (0 == target_material.compare("veggy") || 0 == target_material.compare("cotton") || 0 == target_material.compare("wool") || 0 == target_material.compare("paper") || 0 == target_material.compare("wood") ) { add_effect("onfire", rng(6, 6)); } else if (0 == target_material.compare("flesh") || 0 == target_material.compare("iflesh") ) { add_effect("onfire", rng(10, 10)); } } int stun_strength = 0; if (proj.proj_effects.count("BEANBAG")) { stun_strength = 4; } if(proj.proj_effects.count("WHIP")) { stun_strength = rng(4, 10); } if (proj.proj_effects.count("LARGE_BEANBAG")) { stun_strength = 16; } if( stun_strength > 0 ) { switch( get_size() ) { case MS_TINY: stun_strength *= 4; break; case MS_SMALL: stun_strength *= 2; break; case MS_MEDIUM: default: break; case MS_LARGE: stun_strength /= 2; break; case MS_HUGE: stun_strength /= 4; break; } add_effect( "stunned", rng(stun_strength / 2, stun_strength) ); } if(u_see_this) { if (damage_mult == 0) { if(source != NULL) { add_msg(source->is_player() ? _("You miss!") : _("The shot misses!")); } } else if (dealt_dam.total_damage() == 0) { add_msg(_("The shot reflects off %s %s!"), disp_name(true).c_str(), skin_name().c_str()); } else if (source != NULL) { if (source->is_player()) { //player hits monster ranged SCT.add(posx(), posy(), direction_from(0, 0, posx() - source->posx(), posy() - source->posy()), get_hp_bar(dealt_dam.total_damage(), get_hp_max(), true).first, m_good, message, gmtSCTcolor); if (get_hp() > 0) { SCT.add(posx(), posy(), direction_from(0, 0, posx() - source->posx(), posy() - source->posy()), get_hp_bar(get_hp(), get_hp_max(), true).first, m_good, //~ “hit points”, used in scrolling combat text _("hp"), m_neutral, "hp"); } else { SCT.removeCreatureHP(); } add_msg(m_good, _("You hit %s for %d damage."), disp_name().c_str(), dealt_dam.total_damage()); } else if(this->is_player()) { //monster hits player ranged //~ Hit message. 1$s is bodypart name in accusative. 2$d is damage value. add_msg_if_player(m_bad, _( "You were hit in the %1$s for %2$d damage." ), body_part_name_accusative(bp_hit).c_str( ), dealt_dam.total_damage()); } else if( u_see_this ) { add_msg(_("%s shoots %s."), source->disp_name().c_str(), disp_name().c_str()); } } } check_dead_state(); return 0; }
int monster::hp_percentage() const { return ( get_hp( hp_torso ) * 100 ) / get_hp_max(); }
body_part Creature::select_body_part(Creature *source, int hit_roll) { // Get size difference (-1,0,1); int szdif = source->get_size() - get_size(); if(szdif < -1) { szdif = -1; } else if (szdif > 1) { szdif = 1; } add_msg( m_debug, "source size = %d", source->get_size() ); add_msg( m_debug, "target size = %d", get_size() ); add_msg( m_debug, "difference = %d", szdif ); std::map<body_part, double> hit_weights = default_hit_weights[szdif]; std::map<body_part, double>::iterator iter; // If the target is on the ground, even small/tiny creatures may target eyes/head. Also increases chances of larger creatures. // Any hit modifiers to locations should go here. (Tags, attack style, etc) if(is_on_ground()) { hit_weights[bp_eyes] += 10; hit_weights[bp_head] += 20; } //Adjust based on hit roll: Eyes, Head & Torso get higher, while Arms and Legs get lower. //This should eventually be replaced with targeted attacks and this being miss chances. hit_weights[bp_eyes] = floor(hit_weights[bp_eyes] * std::pow(hit_roll, 1.15) * 10); hit_weights[bp_head] = floor(hit_weights[bp_head] * std::pow(hit_roll, 1.15) * 10); hit_weights[bp_torso] = floor(hit_weights[bp_torso] * std::pow(hit_roll, 1) * 10); hit_weights[bp_arm_l] = floor(hit_weights[bp_arm_l] * std::pow(hit_roll, 0.95) * 10); hit_weights[bp_arm_r] = floor(hit_weights[bp_arm_r] * std::pow(hit_roll, 0.95) * 10); hit_weights[bp_leg_l] = floor(hit_weights[bp_leg_l] * std::pow(hit_roll, 0.975) * 10); hit_weights[bp_leg_r] = floor(hit_weights[bp_leg_r] * std::pow(hit_roll, 0.975) * 10); // Debug for seeing weights. add_msg( m_debug, "eyes = %f", hit_weights.at( bp_eyes ) ); add_msg( m_debug, "head = %f", hit_weights.at( bp_head ) ); add_msg( m_debug, "torso = %f", hit_weights.at( bp_torso ) ); add_msg( m_debug, "arm_l = %f", hit_weights.at( bp_arm_l ) ); add_msg( m_debug, "arm_r = %f", hit_weights.at( bp_arm_r ) ); add_msg( m_debug, "leg_l = %f", hit_weights.at( bp_leg_l ) ); add_msg( m_debug, "leg_r = %f", hit_weights.at( bp_leg_r ) ); double totalWeight = 0; std::set<std::pair<body_part, double>, weight_compare> adjusted_weights; for(iter = hit_weights.begin(); iter != hit_weights.end(); ++iter) { totalWeight += iter->second; adjusted_weights.insert(*iter); } body_part selected_part = bp_torso; // Blood thirsty monsters can discard body part and go to more damaged int part_rolls = 1; int repick_chance = 50; if (source->has_flag(MF_BLOODTHIRSTY)) { part_rolls += 2; if (is_player() && g->u.has_trait("ANIMALEMPATH")) { part_rolls -= 1; repick_chance -= 10; } if (is_player() && g->u.has_trait("ANIMALDISCORD")) { part_rolls += 1; repick_chance += 10; } } body_part last_part = selected_part; for(int r = 0; r < part_rolls; ++r) { double roll = rng_float(1, totalWeight); std::set<std::pair<body_part, double>, weight_compare>::iterator adj_iter; for(adj_iter = adjusted_weights.begin(); adj_iter != adjusted_weights.end(); ++adj_iter) { roll -= adj_iter->second; if(roll <= 0) { selected_part = adj_iter->first; break; } } if (r != 0) { hp_part hpart_cur = bodypart_to_hp_part(selected_part); hp_part hpart_lst = bodypart_to_hp_part(last_part); double ratio_cur = get_hp(hpart_cur) / float(get_hp_max(hpart_cur)); double ratio_lst = get_hp(hpart_lst) / float(get_hp_max(hpart_lst)); body_part cur_pick_part = selected_part; if(ratio_cur > ratio_lst && repick_chance >= rng(1,100)) selected_part = last_part; add_msg( m_debug, "picked %s from %s(%.2f)/%s(%.2f)", body_part_name(selected_part).c_str(), body_part_name(cur_pick_part).c_str(), ratio_cur, body_part_name(last_part).c_str(), ratio_lst); } last_part = selected_part; } return selected_part; }