bool Creature::remove_effect(efftype_id eff_id, body_part bp) { if (!has_effect(eff_id, bp)) { //Effect doesn't exist, so do nothing return false; } if (is_player()) { // Print the removal message and add the memorial log if needed if(effect_types[eff_id].get_remove_message() != "") { add_msg(effect_types[eff_id].lose_game_message_type(), _(effect_types[eff_id].get_remove_message().c_str())); } add_memorial_log(pgettext("memorial_male", effect_types[eff_id].get_remove_memorial_log().c_str()), pgettext("memorial_female", effect_types[eff_id].get_remove_memorial_log().c_str())); } // num_bp means remove all of a given effect id if (bp == num_bp) { effects.erase(eff_id); } else { effects[eff_id].erase(bp); // If there are no more effects of a given type remove the type map if (effects[eff_id].empty()) { effects.erase(eff_id); } } return true; }
void Creature::process_effects() { // id's and body_part's of all effects to be removed. If we ever get player or // monster specific removals these will need to be moved down to that level and then // passed in to this function. std::vector<efftype_id> rem_ids; std::vector<body_part> rem_bps; // Decay/removal of effects for( auto &elem : *effects ) { for( auto &_it : elem.second ) { // Add any effects that others remove to the removal list for( const auto& removed_effect : _it.second.get_removes_effects() ) { rem_ids.push_back( removed_effect ); rem_bps.push_back(num_bp); } effect &e = _it.second; const int prev_int = e.get_intensity(); // Run decay effects, marking effects for removal as necessary. e.decay( rem_ids, rem_bps, calendar::turn, is_player() ); if( e.get_intensity() != prev_int && e.get_duration() > 0_turns ) { on_effect_int_change( e.get_id(), e.get_intensity(), e.get_bp() ); } } } // Actually remove effects. This should be the last thing done in process_effects(). for (size_t i = 0; i < rem_ids.size(); ++i) { remove_effect( rem_ids[i], rem_bps[i] ); } }
void Creature::process_effects() { // id's and body_part's of all effects to be removed. If we ever get player or // monster specific removals these will need to be moved down to that level and then // passed in to this function. std::vector<std::string> rem_ids; std::vector<body_part> rem_bps; // Decay/removal of effects for( auto &elem : effects ) { for( auto &_it : elem.second ) { // Add any effects that others remove to the removal list for( const auto removed_effect : _it.second.get_removes_effects() ) { rem_ids.push_back( removed_effect ); rem_bps.push_back(num_bp); } // Run decay effects, marking effects for removal as necessary. _it.second.decay( rem_ids, rem_bps, calendar::turn, is_player() ); } } // Actually remove effects. This should be the last thing done in process_effects(). for (size_t i = 0; i < rem_ids.size(); ++i) { remove_effect( rem_ids[i], rem_bps[i] ); } }
int play(t_map *map, t_token *token, int x, int y) { int i; int j; int touch; int xtoplay; int ytoplay; touch = 0; i = 0; while (i < token->rows && touch < 2) { j = 0; while (j < token->cols && touch < 2) { xtoplay = i + x < 0 ? map->rows + i + x : x + i; ytoplay = y + j < 0 ? map->cols + j + y : y + j; if (is_player(map->token[xtoplay][ytoplay]) && is_shape(token->token[i][j])) touch++; if (is_opponent_player(map->token[xtoplay][ytoplay]) && is_shape(token->token[i][j])) touch += 2; j++; } i++; } return (touch == 1); }
bool Creature::sees( const Creature &critter ) const { if( critter.is_hallucination() ) { // hallucinations are imaginations of the player character, npcs or monsters don't hallucinate. // Invisible hallucinations would be pretty useless (nobody would see them at all), therefor // the player will see them always. return is_player(); } const auto p = dynamic_cast< const player* >( &critter ); if( p != nullptr && p->is_invisible() ) { // Let invisible players see themselves (simplifies drawing) return p == this; } if( !fov_3d && !debug_mode && posz() != critter.posz() ) { return false; } const int wanted_range = rl_dist( pos(), critter.pos() ); if( wanted_range <= 1 && ( posz() == critter.posz() || g->m.valid_move( pos(), critter.pos(), false, true ) ) ) { return true; } else if( ( wanted_range > 1 && critter.digging() ) || (critter.has_flag(MF_NIGHT_INVISIBILITY) && g->m.light_at(critter.pos()) <= LL_LOW ) || ( critter.is_underwater() && !is_underwater() && g->m.is_divable( critter.pos() ) ) ) { return false; } return sees( critter.pos(), critter.is_player() ); }
/* * Effect-related methods */ void Creature::add_effect(efftype_id eff_id, int dur, int intensity, bool permanent) { // check if we already have it auto found_effect = effects.find( eff_id ); if (found_effect != effects.end()) { effect &e = found_effect->second; // if we do, mod the duration e.mod_duration(dur); // Adding a permanent effect makes it permanent if( e.is_permanent() ) { e.pause_effect(); } if( e.get_intensity() + intensity <= e.get_max_intensity() ) { e.mod_intensity( intensity ); } } else { // if we don't already have it then add a new one if (effect_types.find(eff_id) == effect_types.end()) { return; } effect new_eff(&effect_types[eff_id], dur, intensity, permanent); effects[eff_id] = new_eff; if (is_player()) { // only print the message if we didn't already have it add_msg( effect_types[eff_id].gain_game_message_type(), effect_types[eff_id].get_apply_message().c_str() ); g->u.add_memorial_log(pgettext("memorial_male", effect_types[eff_id].get_apply_memorial_log().c_str()), pgettext("memorial_female", effect_types[eff_id].get_apply_memorial_log().c_str())); } } }
void live(t_op_run *run, t_env *env) { int player; int p; int in; player = read_int(run->arg[0]); p = 0; while (p < env->p_count) { if (PLAYER(p).p_num == player) { env->last_live = player; PLAYER(p).last_live = -1; } p++; } in = is_player(player, env); if (in != -1) { env->live_calls++; ft_printf("A process shows that player %s is alive\n", PLAYER(in).name); } }
bool Creature::sees( const Creature &critter, int &bresen1, int &bresen2 ) const { if( critter.is_hallucination() ) { // hallucinations are imaginations of the player character, npcs or monsters don't hallucinate. // Invisible hallucinations would be pretty useless (nobody would see them at all), therefor // the player will see them always. return is_player(); } const auto p = dynamic_cast< const player* >( &critter ); if( p != nullptr && p->is_invisible() ) { // Let invisible players see themselves (simplifies drawing) return p == this; } if( posz() != critter.posz() && !debug_mode ) { return false; // TODO: Remove this } const int wanted_range = rl_dist( pos3(), critter.pos3() ); if( wanted_range <= 1 ) { return true; } else if( ( wanted_range > 1 && critter.digging() ) || ( g->m.is_divable( critter.pos3() ) && critter.is_underwater() && !is_underwater() ) ) { return false; } return sees( critter.pos3(), bresen1, bresen2 ); }
void Creature::add_effect(efftype_id eff_id, int dur, int intensity, bool permanent) { // check if we already have it std::vector<effect>::iterator first_eff = std::find_if(effects.begin(), effects.end(), is_id_functor(eff_id)); if (first_eff != effects.end()) { // if we do, mod the duration first_eff->mod_duration(dur); // Adding a permanent effect makes it permanent if (first_eff->is_permanent()) { first_eff->pause_effect(); } if (first_eff->get_intensity() + intensity <= first_eff->get_max_intensity()) { first_eff->mod_intensity(intensity); } } else { // if we don't already have it then add a new one if (effect_types.find(eff_id) == effect_types.end()) { return; } effect new_eff(&effect_types[eff_id], dur, intensity, permanent); effects.push_back(new_eff); if (is_player()) { // only print the message if we didn't already have it add_msg(effect_types[eff_id].gain_game_message_type(), effect_types[eff_id].get_apply_message().c_str()); g->u.add_memorial_log(pgettext("memorial_male", effect_types[eff_id].get_apply_memorial_log().c_str()), pgettext("memorial_female", effect_types[eff_id].get_apply_memorial_log().c_str())); } } }
void Creature::add_effect(efftype_id eff_id, int dur) { // check if we already have it std::vector<effect>::iterator first_eff = std::find_if(effects.begin(), effects.end(), is_id_functor(eff_id)); if (first_eff != effects.end()) { // if we do, mod the duration first_eff->mod_duration(dur); } else { // if we don't already have it then add a new one if (effect_types.find(eff_id) == effect_types.end()) { return; } effect new_eff(&effect_types[eff_id], dur); effects.push_back(new_eff); if (is_player()) { // only print the message if we didn't already have it g->add_msg_string(effect_types[eff_id].get_apply_message()); g->u.add_memorial_log(pgettext("memorial_male", effect_types[eff_id].get_apply_memorial_log().c_str()), pgettext("memorial_female", effect_types[eff_id].get_apply_memorial_log().c_str())); } } }
bool Actor::go(std::string direction) { if (current_place->has_neighbor(direction)) { go(current_place->neighbor(direction)); return true; } else { if (is_player()) std::cout << "Can't go there" << std::endl; return false; } }
void Creature::deal_melee_hit(Creature *source, int hit_spread, bool critical_hit, const damage_instance &dam, dealt_damage_instance &dealt_dam) { damage_instance d = dam; // copy, since we will mutate in block_hit body_part bp_hit = select_body_part(source, hit_spread); block_hit(source, bp_hit, d); // Bashing crit if (critical_hit) { int turns_stunned = (d.type_damage(DT_BASH) + hit_spread) / 20; if (turns_stunned > 6) { turns_stunned = 6; } if (turns_stunned > 0) { add_effect("stunned", turns_stunned); } } // Stabbing effects int stab_moves = rng(d.type_damage(DT_STAB) / 2, d.type_damage(DT_STAB) * 1.5); if (critical_hit) { stab_moves *= 1.5; } if (stab_moves >= 150) { if (is_player() && (!g->u.has_trait("LEG_TENT_BRACE") || g->u.footwear_factor() == 1 || (g->u.footwear_factor() == .5 && one_in(2))) ) { // can the player force their self to the ground? probably not. source->add_msg_if_npc( m_bad, _("<npcname> forces you to the ground!")); } else { source->add_msg_player_or_npc( m_good, _("You force %s to the ground!"), _("<npcname> forces %s to the ground!"), disp_name().c_str() ); } if (!g->u.has_trait("LEG_TENT_BRACE") || g->u.footwear_factor() == 1 || (g->u.footwear_factor() == .5 && one_in(2))) { add_effect("downed", 1); mod_moves(-stab_moves / 2); } } else { mod_moves(-stab_moves); } on_gethit(source, bp_hit, d); // trigger on-gethit events dealt_dam = deal_damage(source, bp_hit, d); dealt_dam.bp_hit = bp_hit; }
void Creature::deal_melee_hit( Creature *source, int hit_spread, bool critical_hit, const damage_instance &dam, dealt_damage_instance &dealt_dam ) { damage_instance d = dam; // copy, since we will mutate in block_hit body_part bp_hit = select_body_part(source, hit_spread); block_hit(source, bp_hit, d); // Bashing critical if( critical_hit && !is_immune_effect( effect_stunned ) ) { if( d.type_damage(DT_BASH) * hit_spread > get_hp_max() ) { add_effect( effect_stunned, 1_turns ); // 1 turn is enough } } // Stabbing effects int stab_moves = rng( d.type_damage(DT_STAB) / 2, d.type_damage(DT_STAB) * 1.5 ); if (critical_hit) { stab_moves *= 1.5; } if( stab_moves >= 150 && !is_immune_effect( effect_downed ) ) { if( is_player() ) { source->add_msg_if_npc( m_bad, _("<npcname> forces you to the ground!")); } else { source->add_msg_player_or_npc( m_good, _("You force %s to the ground!"), _("<npcname> forces %s to the ground!"), disp_name().c_str() ); } add_effect( effect_downed, 1_turns ); mod_moves(-stab_moves / 2); } else { mod_moves(-stab_moves); } on_hit( source, bp_hit ); // trigger on-gethit events dealt_dam = deal_damage(source, bp_hit, d); dealt_dam.bp_hit = bp_hit; }
bool Creature::remove_effect( const efftype_id &eff_id, body_part bp ) { if (!has_effect(eff_id, bp)) { //Effect doesn't exist, so do nothing return false; } const effect_type &type = eff_id.obj(); if (is_player()) { // Print the removal message and add the memorial log if needed if( !type.get_remove_message().empty() ) { add_msg(type.lose_game_message_type(), _(type.get_remove_message().c_str())); } add_memorial_log(pgettext("memorial_male", type.get_remove_memorial_log().c_str()), pgettext("memorial_female", type.get_remove_memorial_log().c_str())); } // num_bp means remove all of a given effect id if (bp == num_bp) { for( auto &it : ( *effects )[eff_id] ) { on_effect_int_change( eff_id, 0, it.first ); } effects->erase(eff_id); } else { ( *effects )[eff_id].erase(bp); on_effect_int_change( eff_id, 0, bp ); // If there are no more effects of a given type remove the type map if (( *effects )[eff_id].empty()) { effects->erase(eff_id); } } return true; }
/* * move_drone: * Move the drone to the next square * Returns FALSE if the drone need no longer be tracked. */ static int move_drone(BULLET *bp) { int mask, count; int n, dir = -1; PLAYER *pp; /* See if we can give someone a blast: */ if (is_player(Maze[bp->b_y][bp->b_x - 1])) { dir = WEST; goto drone_move; } if (is_player(Maze[bp->b_y - 1][bp->b_x])) { dir = NORTH; goto drone_move; } if (is_player(Maze[bp->b_y + 1][bp->b_x])) { dir = SOUTH; goto drone_move; } if (is_player(Maze[bp->b_y][bp->b_x + 1])) { dir = EAST; goto drone_move; } /* Find out what directions are clear and move that way: */ mask = count = 0; if (!iswall(bp->b_y, bp->b_x - 1)) mask |= WEST, count++; if (!iswall(bp->b_y - 1, bp->b_x)) mask |= NORTH, count++; if (!iswall(bp->b_y + 1, bp->b_x)) mask |= SOUTH, count++; if (!iswall(bp->b_y, bp->b_x + 1)) mask |= EAST, count++; /* All blocked up, just wait: */ if (count == 0) return TRUE; /* Only one way to go: */ if (count == 1) { dir = mask; goto drone_move; } /* Avoid backtracking, and remove the direction we came from: */ switch (bp->b_face) { case LEFTS: if (mask & EAST) mask &= ~EAST, count--; break; case RIGHT: if (mask & WEST) mask &= ~WEST, count--; break; case ABOVE: if (mask & SOUTH) mask &= ~SOUTH, count--; break; case BELOW: if (mask & NORTH) mask &= ~NORTH, count--; break; } /* Pick one of the remaining directions: */ n = rand_num(count); if (n >= 0 && mask & NORTH) dir = NORTH, n--; if (n >= 0 && mask & SOUTH) dir = SOUTH, n--; if (n >= 0 && mask & EAST) dir = EAST, n--; if (n >= 0 && mask & WEST) dir = WEST, n--; drone_move: /* Move the drone: */ switch (dir) { case -1: /* no move */ case WEST: bp->b_x--; bp->b_face = LEFTS; break; case EAST: bp->b_x++; bp->b_face = RIGHT; break; case NORTH: bp->b_y--; bp->b_face = ABOVE; break; case SOUTH: bp->b_y++; bp->b_face = BELOW; break; } /* Look at what the drone moved onto: */ switch (Maze[bp->b_y][bp->b_x]) { case LEFTS: case RIGHT: case BELOW: case ABOVE: /* * Players have a 1% chance of absorbing a drone, * if they are facing it. */ if (rand_num(100) < conf_pdroneabsorb && opposite(bp->b_face, Maze[bp->b_y][bp->b_x])) { /* Feel the power: */ pp = play_at(bp->b_y, bp->b_x); pp->p_ammo += bp->b_charge; message(pp, "**** Absorbed drone ****"); /* Release drone storage: */ free(bp); /* Update ammo: */ ammo_update(pp); /* No need for caller to keep tracking drone: */ return FALSE; } /* Detonate the drone: */ bp->b_expl = TRUE; break; } /* Keep tracking the drone. */ return TRUE; }
int Creature::deal_projectile_attack(Creature *source, double missed_by, const projectile &proj, dealt_damage_instance &dealt_dam) { bool u_see_this = g->u_see(this); body_part bp_hit; int side = rng(0, 1); // 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 0; } // 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)) { bp_hit = bp_legs; } else { bp_hit = bp_arms; } 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, side, 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 nc_color color; std::string health_bar = ""; get_HP_Bar(dealt_dam.total_damage(), this->get_hp_max(), color, health_bar, true); SCT.add(this->xpos(), this->ypos(), direction_from(0, 0, this->xpos() - source->xpos(), this->ypos() - source->ypos()), health_bar, m_good, message, gmtSCTcolor); if (this->get_hp() > 0) { get_HP_Bar(this->get_hp(), this->get_hp_max(), color, health_bar, true); SCT.add(this->xpos(), this->ypos(), direction_from(0, 0, this->xpos() - source->xpos(), this->ypos() - source->ypos()), health_bar, m_good, "hp", m_neutral, "hp"); } else { SCT.removeCreatureHP(); } add_msg(m_good, _("You hit the %s for %d damage."), disp_name().c_str(), dealt_dam.total_damage()); } else if(this->is_player()) { //monster hits player ranged add_msg_if_player( m_bad, _( "You were hit in the %s for %d damage." ), body_part_name( bp_hit, side ).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()); } } } return 0; }
void classPlayer::move() { if (input.p1_input[BTN_DOWN] == 1) { moveCommands.down = 1; } else { moveCommands.down = 0; } if (input.p1_input[BTN_UP] == 1) { moveCommands.up = 1; } else { moveCommands.up = 0; } if (input.p1_input[BTN_LEFT] == 1) { moveCommands.left = 1; } else { moveCommands.left = 0; } if (input.p1_input[BTN_RIGHT] == 1) { moveCommands.right = 1; } else { moveCommands.right = 0; } if (input.p1_input[BTN_JUMP] == 1) { moveCommands.jump = 1; } else { moveCommands.jump = 0; } if (input.p1_input[BTN_ATTACK] == 1) { moveCommands.attack = 1; } else { moveCommands.attack = 0; } if (input.p1_input[BTN_SHIELD] == 1) { moveCommands.shield = 1; } else { moveCommands.shield = 0; } if (input.p1_input[BTN_DASH] == 1) { moveCommands.dash = 1; } else { moveCommands.dash = 0; } if (input.p1_input[BTN_L] != 1 && l_key_released == false) { l_key_released = true; } int wpn_max = WEAPON_COUNT; //wpn_max--; if (input.p1_input[BTN_L] == 1 && l_key_released == true) { int selected_weapon_c = selected_weapon; selected_weapon_c = find_next_weapon(selected_weapon, -1); if (selected_weapon_c != -1) { set_weapon((WEAPON_ICONS_ENUM)selected_weapon_c); } l_key_released = false; //std::cout << ">>> LBUTTON - selected_weapon: " << selected_weapon << ", selected_weapon_c: " << selected_weapon_c << ", WEAPON_COUNT: " << WEAPON_COUNT << std::endl; } if (input.p1_input[BTN_R] != 1 && r_key_released == false) { r_key_released = true; } if (input.p1_input[BTN_R] == 1 && r_key_released == true) { int selected_weapon_c = selected_weapon; selected_weapon_c = find_next_weapon(selected_weapon, 1); if (selected_weapon_c >= wpn_max) { selected_weapon_c = WEAPON_DEFAULT; } if (selected_weapon_c != -1) { set_weapon((WEAPON_ICONS_ENUM)selected_weapon_c); } r_key_released = false; //std::cout << ">>> RBUTTON - selected_weapon: " << selected_weapon << ", selected_weapon_c: " << selected_weapon_c << ", WEAPON_COUNT: " << WEAPON_COUNT << std::endl; } // send commands to the platform in special cases if (_platform != NULL) { if (_platform->get_type() == OBJ_ITEM_FLY && timer.getTimer() > _platform->get_timer()) { game_save.items.weapons[selected_weapon]--; _platform->set_timer(timer.getTimer()+240); } //std::cout << ">>> PLAYER SEND COMMAND FOR " << _platform->get_name() << ", type: " << _platform->get_type() << std::endl; if (moveCommands.up == 1) { _platform->command_up(); } if (moveCommands.down == 1) { _platform->command_down(); } } if (game_data.players[_number].have_shield == true && moveCommands.up == 0 && moveCommands.down == 0 && moveCommands.left == 0 && moveCommands.right == 0 && moveCommands.jump == 0 && moveCommands.attack == 0 && moveCommands.shield == 1) { if (state.animation_type != ANIM_TYPE_SHIELD) { std::cout << "playerClass::initShield CHANGE anim_type: " << state.animation_type << " to " << ANIM_TYPE_SHIELD << std::endl; set_animation_type(ANIM_TYPE_SHIELD); state.animation_timer = 0; state.animation_state = 0; } return; } else if (state.animation_type == ANIM_TYPE_SHIELD) { //std::cout << "playerClass::initShield REMOVE shield" << std::endl; if (is_player()) std::cout << "********* reset to STAND #15 **********" << std::endl; set_animation_type(ANIM_TYPE_STAND); } execute_projectiles(); }
/** * 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 player::power_mutations() { if( !is_player() ) { // TODO: Implement NPCs activating muts return; } std::vector <std::string> passive; std::vector <std::string> active; for( auto &mut : my_mutations ) { if (!mutation_branch::get( mut.first ).activated) { passive.push_back(mut.first); } else { active.push_back(mut.first); } // New mutations are initialized with no key at all, so we have to do this here. if( mut.second.key == ' ' ) { for( const auto &letter : mutation_chars ) { if( trait_by_invlet( letter ).empty() ) { mut.second.key = letter; break; } } } } // maximal number of rows in both columns const int mutations_count = std::max(passive.size(), active.size()); int TITLE_HEIGHT = 2; int DESCRIPTION_HEIGHT = 5; // Main window /** Total required height is: * top frame line: + 1 * height of title window: + TITLE_HEIGHT * line after the title: + 1 * line with active/passive mutation captions: + 1 * height of the biggest list of active/passive mutations: + mutations_count * line before mutation description: + 1 * height of description window: + DESCRIPTION_HEIGHT * bottom frame line: + 1 * TOTAL: TITLE_HEIGHT + mutations_count + DESCRIPTION_HEIGHT + 5 */ int HEIGHT = std::min(TERMY, std::max(FULL_SCREEN_HEIGHT, TITLE_HEIGHT + mutations_count + DESCRIPTION_HEIGHT + 5)); int WIDTH = FULL_SCREEN_WIDTH + (TERMX - FULL_SCREEN_WIDTH) / 2; int START_X = (TERMX - WIDTH) / 2; int START_Y = (TERMY - HEIGHT) / 2; WINDOW *wBio = newwin(HEIGHT, WIDTH, START_Y, START_X); // Description window @ the bottom of the bio window int DESCRIPTION_START_Y = START_Y + HEIGHT - DESCRIPTION_HEIGHT - 1; int DESCRIPTION_LINE_Y = DESCRIPTION_START_Y - START_Y - 1; WINDOW *w_description = newwin(DESCRIPTION_HEIGHT, WIDTH - 2, DESCRIPTION_START_Y, START_X + 1); // Title window int TITLE_START_Y = START_Y + 1; int HEADER_LINE_Y = TITLE_HEIGHT + 1; // + lines with text in titlebar, local WINDOW *w_title = newwin(TITLE_HEIGHT, WIDTH - 2, TITLE_START_Y, START_X + 1); int scroll_position = 0; int second_column = 32 + (TERMX - FULL_SCREEN_WIDTH) / 4; // X-coordinate of the list of active mutations input_context ctxt("MUTATIONS"); ctxt.register_updown(); ctxt.register_action("ANY_INPUT"); ctxt.register_action("TOGGLE_EXAMINE"); ctxt.register_action("REASSIGN"); ctxt.register_action("HELP_KEYBINDINGS"); bool redraw = true; std::string menu_mode = "activating"; while(true) { // offset for display: mutation with index i is drawn at y=list_start_y+i // drawing the mutation starts with mutation[scroll_position] const int list_start_y = HEADER_LINE_Y + 2 - scroll_position; int max_scroll_position = HEADER_LINE_Y + 2 + mutations_count - ((menu_mode == "examining") ? DESCRIPTION_LINE_Y : (HEIGHT - 1)); if(redraw) { redraw = false; werase(wBio); draw_border(wBio); // Draw line under title mvwhline(wBio, HEADER_LINE_Y, 1, LINE_OXOX, WIDTH - 2); // Draw symbols to connect additional lines to border mvwputch(wBio, HEADER_LINE_Y, 0, BORDER_COLOR, LINE_XXXO); // |- mvwputch(wBio, HEADER_LINE_Y, WIDTH - 1, BORDER_COLOR, LINE_XOXX); // -| // Captions mvwprintz(wBio, HEADER_LINE_Y + 1, 2, c_ltblue, _("Passive:")); mvwprintz(wBio, HEADER_LINE_Y + 1, second_column, c_ltblue, _("Active:")); draw_exam_window(wBio, DESCRIPTION_LINE_Y, menu_mode == "examining"); nc_color type; if (passive.empty()) { mvwprintz(wBio, list_start_y, 2, c_ltgray, _("None")); } else { for (size_t i = scroll_position; i < passive.size(); i++) { const auto &md = mutation_branch::get( passive[i] ); const auto &td = my_mutations[passive[i]]; if (list_start_y + static_cast<int>(i) == (menu_mode == "examining" ? DESCRIPTION_LINE_Y : HEIGHT - 1)) { break; } type = c_cyan; mvwprintz(wBio, list_start_y + i, 2, type, "%c %s", td.key, md.name.c_str()); } } if (active.empty()) { mvwprintz(wBio, list_start_y, second_column, c_ltgray, _("None")); } else { for (size_t i = scroll_position; i < active.size(); i++) { const auto &md = mutation_branch::get( active[i] ); const auto &td = my_mutations[active[i]]; if (list_start_y + static_cast<int>(i) == (menu_mode == "examining" ? DESCRIPTION_LINE_Y : HEIGHT - 1)) { break; } if (!td.powered) { type = c_red; }else if (td.powered) { type = c_ltgreen; } else { type = c_ltred; } // TODO: track resource(s) used and specify mvwputch( wBio, list_start_y + i, second_column, type, td.key ); std::stringstream mut_desc; mut_desc << md.name; if ( md.cost > 0 && md.cooldown > 0 ) { mut_desc << string_format( _(" - %d RU / %d turns"), md.cost, md.cooldown ); } else if ( md.cost > 0 ) { mut_desc << string_format( _(" - %d RU"), md.cost ); } else if ( md.cooldown > 0 ) { mut_desc << string_format( _(" - %d turns"), md.cooldown ); } if ( td.powered ) { mut_desc << _(" - Active"); } mvwprintz( wBio, list_start_y + i, second_column + 2, type, mut_desc.str().c_str() ); } } // Scrollbar if(scroll_position > 0) { mvwputch(wBio, HEADER_LINE_Y + 2, 0, c_ltgreen, '^'); } if(scroll_position < max_scroll_position && max_scroll_position > 0) { mvwputch(wBio, (menu_mode == "examining" ? DESCRIPTION_LINE_Y : HEIGHT - 1) - 1, 0, c_ltgreen, 'v'); } } wrefresh(wBio); show_mutations_titlebar(w_title, this, menu_mode); const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); if (menu_mode == "reassigning") { menu_mode = "activating"; const auto mut_id = trait_by_invlet( ch ); if( mut_id.empty() ) { // Selected an non-existing mutation (or escape, or ...) continue; } redraw = true; const long newch = popup_getkey(_("%s; enter new letter."), mutation_branch::get_name( mut_id ).c_str()); wrefresh(wBio); if(newch == ch || newch == ' ' || newch == KEY_ESCAPE) { continue; } if( !mutation_chars.valid( newch ) ) { popup( _("Invalid mutation letter. Only those characters are valid:\n\n%s"), mutation_chars.get_allowed_chars().c_str() ); continue; } const auto other_mut_id = trait_by_invlet( newch ); if( !other_mut_id.empty() ) { std::swap(my_mutations[mut_id].key, my_mutations[other_mut_id].key); } else { my_mutations[mut_id].key = newch; } // TODO: show a message like when reassigning a key to an item? } else if (action == "DOWN") { if(scroll_position < max_scroll_position) { scroll_position++; redraw = true; } } else if (action == "UP") { if(scroll_position > 0) { scroll_position--; redraw = true; } } else if (action == "REASSIGN") { menu_mode = "reassigning"; } else if (action == "TOGGLE_EXAMINE") { // switches between activation and examination menu_mode = menu_mode == "activating" ? "examining" : "activating"; werase(w_description); draw_exam_window(wBio, DESCRIPTION_LINE_Y, false); redraw = true; }else if (action == "HELP_KEYBINDINGS") { redraw = true; } else { const auto mut_id = trait_by_invlet( ch ); if( mut_id.empty() ) { // entered a key that is not mapped to any mutation, // -> leave screen break; } const auto &mut_data = mutation_branch::get( mut_id ); if (menu_mode == "activating") { if (mut_data.activated) { if (my_mutations[mut_id].powered) { add_msg_if_player(m_neutral, _("You stop using your %s."), mut_data.name.c_str()); deactivate_mutation( mut_id ); delwin(w_title); delwin(w_description); delwin(wBio); // Action done, leave screen break; } else if( (!mut_data.hunger || get_hunger() <= 400) && (!mut_data.thirst || get_thirst() <= 400) && (!mut_data.fatigue || get_fatigue() <= 400) ) { // this will clear the mutations menu for targeting purposes werase(wBio); wrefresh(wBio); delwin(w_title); delwin(w_description); delwin(wBio); g->draw(); add_msg_if_player( m_neutral, _("You activate your %s."), mut_data.name.c_str() ); activate_mutation( mut_id ); // Action done, leave screen break; } else { popup( _( "You don't have enough in you to activate your %s!" ), mut_data.name.c_str() ); redraw = true; continue; } } else { popup(_("\ You cannot activate %s! To read a description of \ %s, press '!', then '%c'."), mut_data.name.c_str(), mut_data.name.c_str(), my_mutations[mut_id].key ); redraw = true; } } if (menu_mode == "examining") { // Describing mutations, not activating them! draw_exam_window(wBio, DESCRIPTION_LINE_Y, true); // Clear the lines first werase(w_description); fold_and_print(w_description, 0, 0, WIDTH - 2, c_ltblue, mut_data.description); wrefresh(w_description); } } } //if we activated a mutation, already killed the windows if(!(menu_mode == "activating")) { werase(wBio); wrefresh(wBio); delwin(w_title); delwin(w_description); delwin(wBio); } }
int Creature::deal_melee_attack(Creature *source, int hitroll, bool critical_hit, const damage_instance &dam, dealt_damage_instance &dealt_dam) { int dodgeroll = dodge_roll(); int hit_spread = hitroll - dodgeroll; bool missed = hit_spread <= 0; damage_instance d = dam; // copy, since we will mutate in block_hit if (missed) { return hit_spread; } //bool critical_hit = hit_spread > 30; //scored_crit(dodgeroll); body_part bp_hit; int side = rng(0, 1); int hit_value = hit_spread + dice(10, 6) - 35; if (hit_value >= 40) { bp_hit = bp_eyes; } else if (hit_value >= 30) { bp_hit = bp_head; } else if (hit_value >= 5) { bp_hit = bp_torso; } else if (one_in(4)) { bp_hit = bp_legs; } else { bp_hit = bp_arms; } // Bashing crit if (critical_hit) { int turns_stunned = (d.type_damage(DT_BASH) + hit_spread) / 20; if (turns_stunned > 6) { turns_stunned = 6; } if (turns_stunned > 0) { add_effect("stunned", turns_stunned); } } // Stabbing effects int stab_moves = rng(d.type_damage(DT_STAB) / 2, d.type_damage(DT_STAB) * 1.5); if (critical_hit) { stab_moves *= 1.5; } if (stab_moves >= 150) { if (is_player()) { // can the player force their self to the ground? probably not. g->add_msg_if_npc(source, _("<npcname> forces you to the ground!")); } else { g->add_msg_player_or_npc(source, _("You force %s to the ground!"), _("<npcname> forces %s to the ground!"), disp_name().c_str() ); } add_effect("downed", 1); mod_moves(-stab_moves / 2); } else { mod_moves(-stab_moves); } block_hit(bp_hit, side, d); on_gethit(source, bp_hit, d); // trigger on-gethit events dealt_dam = deal_damage(source, bp_hit, side, d); dealt_dam.bp_hit = bp_hit; /* TODO: add grabs n shit back in if (allow_special && technique.grabs) { // TODO: make this depend on skill (through grab_resist stat) again if (t.get_grab_resist() > 0 && dice(t.get_dex() , 12) > dice(get_dex(), 10)) { g->add_msg_player_or_npc(&t, _("You break the grab!"), _("<npcname> breaks the grab!")); } else if (!unarmed_attack()) { // Move our weapon to a temp slot, if it's not unarmed item tmpweap = remove_weapon(); melee_attack(t, false); // False means a second grab isn't allowed weapon = tmpweap; } else melee_attack(t, false); // False means a second grab isn't allowed } */ return hit_spread; }
int Creature::deal_projectile_attack(Creature *source, double missed_by, const projectile &proj, dealt_damage_instance &dealt_dam) { bool u_see_this = g->u_see(this); body_part bp_hit; int side = rng(0, 1); // do 10,speed because speed could potentially be > 10000 if (dodge_roll() >= dice(10, proj.speed)) { if (is_player()) g->add_msg(_("You dodge %s's projectile!"), skin_name().c_str()); else if (u_see_this) g->add_msg(_("%s dodges %s's projectile."), disp_name().c_str(), source->disp_name().c_str()); return 0; } 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)) { bp_hit = bp_legs; } else { bp_hit = bp_arms; } double monster_speed_penalty = std::max(double(get_speed()) / 80., 1.0); double goodhit = missed_by / monster_speed_penalty; double damage_mult = 1.0; if (goodhit <= .1) { g->add_msg_if_player(source, _("Headshot!")); damage_mult *= rng_float(5, 8); bp_hit = bp_head; // headshot hits the head, of course } else if (goodhit <= .2) { g->add_msg_if_player(source, _("Critical!")); damage_mult *= rng_float(2, 3); } else if (goodhit <= .4) { g->add_msg_if_player(source, _("Good hit!")); damage_mult *= rng_float(1, 2); } else if (goodhit <= .6) { damage_mult *= rng_float(0.5, 1); } else if (goodhit <= .8) { g->add_msg_if_player(source, _("Grazing hit.")); damage_mult *= rng_float(0, 1); } else { damage_mult *= 0; } // copy it, since we're mutating damage_instance impact = proj.impact; impact.mult_damage(damage_mult); dealt_dam = deal_damage(source, bp_hit, side, impact); dealt_dam.bp_hit = bp_hit; if(u_see_this) { if (damage_mult == 0) { if(source != NULL) { g->add_msg(source->is_player() ? _("You miss!") : _("The shot misses!")); } } else if (dealt_dam.total_damage() == 0) { g->add_msg(_("The shot reflects off the %s!"), skin_name().c_str()); } else if (source != NULL) { if (source->is_player()) { g->add_msg(_("You hit the %s for %d damage."), disp_name().c_str(), dealt_dam.total_damage()); } else if (u_see_this) { g->add_msg(_("%s shoots %s."), source->disp_name().c_str(), disp_name().c_str()); } } } return 0; }
void Creature::add_effect( efftype_id eff_id, int dur, body_part bp, bool permanent, int intensity, bool force ) { // Check our innate immunity if( !force && is_immune_effect( eff_id ) ) { return; } // Mutate to a main (HP'd) body_part if necessary. if (effect_types[eff_id].get_main_parts()) { bp = mutate_to_main_part(bp); } bool found = false; // Check if we already have it auto matching_map = effects.find(eff_id); if (matching_map != effects.end()) { auto found_effect = effects[eff_id].find(bp); if (found_effect != effects[eff_id].end()) { found = true; effect &e = found_effect->second; // If we do, mod the duration, factoring in the mod value e.mod_duration(dur * e.get_dur_add_perc() / 100); // Limit to max duration if (e.get_max_duration() > 0 && e.get_duration() > e.get_max_duration()) { e.set_duration(e.get_max_duration()); } // Adding a permanent effect makes it permanent if( e.is_permanent() ) { e.pause_effect(); } // Set intensity if value is given if (intensity > 0) { e.set_intensity(intensity); // Else intensity uses the type'd step size if it already exists } else if (e.get_int_add_val() != 0) { e.mod_intensity(e.get_int_add_val()); } // Bound intensity by [1, max intensity] if (e.get_intensity() < 1) { add_msg( m_debug, "Bad intensity, ID: %s", e.get_id().c_str() ); e.set_intensity(1); } else if (e.get_intensity() > e.get_max_intensity()) { e.set_intensity(e.get_max_intensity()); } } } if( found == false ) { // If we don't already have it then add a new one // First make sure it's a valid effect if (effect_types.find(eff_id) == effect_types.end()) { return; } // Then check if the effect is blocked by another for( auto &elem : effects ) { for( auto &_effect_it : elem.second ) { for( const auto blocked_effect : _effect_it.second.get_blocks_effects() ) { if (blocked_effect == eff_id) { // The effect is blocked by another, return return; } } } } // Now we can make the new effect for application effect new_eff(&effect_types[eff_id], dur, bp, permanent, intensity); effect &e = new_eff; // Bound to max duration if (e.get_max_duration() > 0 && e.get_duration() > e.get_max_duration()) { e.set_duration(e.get_max_duration()); } // Bound new effect intensity by [1, max intensity] if (new_eff.get_intensity() < 1) { add_msg( m_debug, "Bad intensity, ID: %s", new_eff.get_id().c_str() ); new_eff.set_intensity(1); } else if (new_eff.get_intensity() > new_eff.get_max_intensity()) { new_eff.set_intensity(new_eff.get_max_intensity()); } effects[eff_id][bp] = new_eff; if (is_player()) { // Only print the message if we didn't already have it if(effect_types[eff_id].get_apply_message() != "") { add_msg(effect_types[eff_id].gain_game_message_type(), _(effect_types[eff_id].get_apply_message().c_str())); } add_memorial_log(pgettext("memorial_male", effect_types[eff_id].get_apply_memorial_log().c_str()), pgettext("memorial_female", effect_types[eff_id].get_apply_memorial_log().c_str())); } // Perform any effect addition effects. bool reduced = has_effect(e.get_resist_effect()) || has_trait(e.get_resist_trait()); add_eff_effects(e, reduced); } }
bool player::eat( item &food, bool force ) { if( !food.is_food() ) { return false; } // Check if it's rotten before eating! food.calc_rot( global_square_location() ); const auto ret = force ? can_eat( food ) : will_eat( food, is_player() ); if( !ret.success() ) { return false; } if( food.type->has_use() ) { if( food.type->invoke( *this, food, pos() ) <= 0 ) { return false; } } // Note: the block below assumes we decided to eat it // No coming back from here const bool hibernate = has_active_mutation( trait_id( "HIBERNATE" ) ); const int nutr = nutrition_for( food ); const int quench = food.type->comestible->quench; const bool spoiled = food.rotten(); // The item is solid food const bool chew = food.type->comestible->comesttype == "FOOD" || food.has_flag( "USE_EAT_VERB" ); // This item is a drink and not a solid food (and not a thick soup) const bool drinkable = !chew && food.type->comestible->comesttype == "DRINK"; // If neither of the above is true then it's a drug and shouldn't get mealtime penalty/bonus if( hibernate && ( get_hunger() > -60 && get_thirst() > -60 ) && ( get_hunger() - nutr < -60 || get_thirst() - quench < -60 ) ) { add_memorial_log( pgettext( "memorial_male", "Began preparing for hibernation." ), pgettext( "memorial_female", "Began preparing for hibernation." ) ); add_msg_if_player( _( "You've begun stockpiling calories and liquid for hibernation. You get the feeling that you should prepare for bed, just in case, but...you're hungry again, and you could eat a whole week's worth of food RIGHT NOW." ) ); } const bool will_vomit = get_hunger() < 0 && nutr >= 5 && !has_trait( trait_id( "GOURMAND" ) ) && !hibernate && !has_trait( trait_id( "SLIMESPAWNER" ) ) && !has_trait( trait_id( "EATHEALTH" ) ) && rng( -200, 0 ) > get_hunger() - nutr; const bool saprophage = has_trait( trait_id( "SAPROPHAGE" ) ); if( spoiled && !saprophage ) { add_msg_if_player( m_bad, _( "Ick, this %s doesn't taste so good..." ), food.tname().c_str() ); if( !has_trait( trait_id( "SAPROVORE" ) ) && !has_trait( trait_id( "EATDEAD" ) ) && ( !has_bionic( bio_digestion ) || one_in( 3 ) ) ) { add_effect( effect_foodpoison, rng( 60, ( nutr + 1 ) * 60 ) ); } consume_effects( food ); } else if( spoiled && saprophage ) { add_msg_if_player( m_good, _( "Mmm, this %s tastes delicious..." ), food.tname().c_str() ); consume_effects( food ); } else { consume_effects( food ); } const bool amorphous = has_trait( trait_id( "AMORPHOUS" ) ); int mealtime = 250; if( drinkable || chew ) { // Those bonuses/penalties only apply to food // Not to smoking weed or applying bandages! if( has_trait( trait_id( "MOUTH_TENTACLES" ) ) || has_trait( trait_id( "MANDIBLES" ) ) ) { mealtime /= 2; } else if( has_trait( trait_id( "GOURMAND" ) ) ) { // Don't stack those two - that would be 25 moves per item mealtime -= 100; } if( has_trait( trait_id( "BEAK_HUM" ) ) && !drinkable ) { mealtime += 200; // Much better than PROBOSCIS but still optimized for fluids } else if( has_trait( trait_id( "SABER_TEETH" ) ) ) { mealtime += 250; // They get In The Way } if( amorphous ) { mealtime *= 1.1; // Minor speed penalty for having to flow around it // rather than just grab & munch } } moves -= mealtime; // If it's poisonous... poison us. // TODO: Move this to a flag if( food.poison > 0 && !has_trait( trait_id( "EATPOISON" ) ) && !has_trait( trait_id( "EATDEAD" ) ) ) { if( food.poison >= rng( 2, 4 ) ) { add_effect( effect_poison, food.poison * 100 ); } add_effect( effect_foodpoison, food.poison * 300 ); } if( amorphous ) { add_msg_player_or_npc( _( "You assimilate your %s." ), _( "<npcname> assimilates a %s." ), food.tname().c_str() ); } else if( drinkable ) { add_msg_player_or_npc( _( "You drink your %s." ), _( "<npcname> drinks a %s." ), food.tname().c_str() ); } else if( chew ) { add_msg_player_or_npc( _( "You eat your %s." ), _( "<npcname> eats a %s." ), food.tname().c_str() ); } if( item::find_type( food.type->comestible->tool )->tool ) { // Tools like lighters get used use_charges( food.type->comestible->tool, 1 ); } if( has_bionic( bio_ethanol ) && food.type->can_use( "ALCOHOL" ) ) { charge_power( rng( 50, 200 ) ); } if( has_bionic( bio_ethanol ) && food.type->can_use( "ALCOHOL_WEAK" ) ) { charge_power( rng( 25, 100 ) ); } if( has_bionic( bio_ethanol ) && food.type->can_use( "ALCOHOL_STRONG" ) ) { charge_power( rng( 75, 300 ) ); } if( food.has_flag( "CANNIBALISM" ) ) { // Sapiovores don't recognize humans as the same species. // But let them possibly feel cool about eating sapient stuff - treat like psycho const bool cannibal = has_trait( trait_id( "CANNIBAL" ) ); const bool psycho = has_trait( trait_id( "PSYCHOPATH" ) ) || has_trait( trait_id( "SAPIOVORE" ) ); const bool spiritual = has_trait( trait_id( "SPIRITUAL" ) ); if( cannibal && psycho && spiritual ) { add_msg_if_player( m_good, _( "You feast upon the human flesh, and in doing so, devour their spirit." ) ); // You're not really consuming anything special; you just think you are. add_morale( MORALE_CANNIBAL, 25, 300 ); } else if( cannibal && psycho ) { add_msg_if_player( m_good, _( "You feast upon the human flesh." ) ); add_morale( MORALE_CANNIBAL, 15, 200 ); } else if( cannibal && spiritual ) { add_msg_if_player( m_good, _( "You consume the sacred human flesh." ) ); // Boosted because you understand the philosophical implications of your actions, and YOU LIKE THEM. add_morale( MORALE_CANNIBAL, 15, 200 ); } else if( cannibal ) { add_msg_if_player( m_good, _( "You indulge your shameful hunger." ) ); add_morale( MORALE_CANNIBAL, 10, 50 ); } else if( psycho && spiritual ) { add_msg_if_player( _( "You greedily devour the taboo meat." ) ); // Small bonus for violating a taboo. add_morale( MORALE_CANNIBAL, 5, 50 ); } else if( psycho ) { add_msg_if_player( _( "Meh. You've eaten worse." ) ); } else if( spiritual ) { add_msg_if_player( m_bad, _( "This is probably going to count against you if there's still an afterlife." ) ); add_morale( MORALE_CANNIBAL, -60, -400, 600, 300 ); } else { add_msg_if_player( m_bad, _( "You feel horrible for eating a person." ) ); add_morale( MORALE_CANNIBAL, -60, -400, 600, 300 ); } } // Allergy check const auto allergy = allergy_type( food ); if( allergy != MORALE_NULL ) { add_msg_if_player( m_bad, _( "Yuck! How can anybody eat this stuff?" ) ); add_morale( allergy, -75, -400, 300, 240 ); } // Carnivores CAN eat junk food, but they won't like it much. // Pizza-scraping happens in consume_effects. if( has_trait( trait_id( "CARNIVORE" ) ) && food.has_flag( "ALLERGEN_JUNK" ) && !food.has_flag( "CARNIVORE_OK" ) ) { add_msg_if_player( m_bad, _( "Your stomach begins gurgling and you feel bloated and ill." ) ); add_morale( MORALE_NO_DIGEST, -25, -125, 300, 240 ); } if( !spoiled && chew && has_trait( trait_id( "SAPROPHAGE" ) ) ) { // It's OK to *drink* things that haven't rotted. Alternative is to ban water. D: add_msg_if_player( m_bad, _( "Your stomach begins gurgling and you feel bloated and ill." ) ); add_morale( MORALE_NO_DIGEST, -75, -400, 300, 240 ); } if( food.has_flag( "URSINE_HONEY" ) && ( !crossed_threshold() || has_trait( trait_id( "THRESH_URSINE" ) ) ) && mutation_category_level["MUTCAT_URSINE"] > 40 ) { //Need at least 5 bear mutations for effect to show, to filter out mutations in common with other mutcats int honey_fun = has_trait( trait_id( "THRESH_URSINE" ) ) ? std::min( mutation_category_level["MUTCAT_URSINE"] / 8, 20 ) : mutation_category_level["MUTCAT_URSINE"] / 12; if( honey_fun < 10 ) { add_msg_if_player( m_good, _( "You find the sweet taste of honey surprisingly palatable." ) ); } else { add_msg_if_player( m_good, _( "You feast upon the sweet honey." ) ); } add_morale( MORALE_HONEY, honey_fun, 100 ); } if( will_vomit ) { vomit(); } // chance to become parasitised if( !( has_bionic( bio_digestion ) || has_trait( trait_id( "PARAIMMUNE" ) ) ) ) { if( food.type->comestible->parasites > 0 && one_in( food.type->comestible->parasites ) ) { switch( rng( 0, 3 ) ) { case 0: if( !has_trait( trait_id( "EATHEALTH" ) ) ) { add_effect( effect_tapeworm, 1, num_bp, true ); } break; case 1: if( !has_trait( trait_id( "ACIDBLOOD" ) ) ) { add_effect( effect_bloodworms, 1, num_bp, true ); } break; case 2: add_effect( effect_brainworms, 1, num_bp, true ); break; case 3: add_effect( effect_paincysts, 1, num_bp, true ); } } } for( const auto &v : this->vitamins_from( food ) ) { auto qty = has_effect( effect_tapeworm ) ? v.second / 2 : v.second; // can never develop hypervitaminosis from consuming food vitamin_mod( v.first, qty ); } food.mod_charges( -1 ); return true; }
int main() { ALLEGRO_DISPLAY *display = NULL; ALLEGRO_EVENT_QUEUE *event_queue=NULL; ALLEGRO_TIMER *timer=NULL; ALLEGRO_FONT *font=NULL; bool keys[4]={false, false, false, false}; bool redraw; enum tile map[50][30]; struct player player; struct enemy enemies[100]; int next; int selected_enemy=100; int level=1; int best=1; player.power=5; player.health=30; player.max_health=30; player.speed=2; player.x=0; player.y=0; player.turns_missed=0; player.kills=0; player.upgrades=4; if(!init(&display, &event_queue, &timer)) { return 1; } init_map(map); init_enemies(enemies, map, 5); font=al_load_font("Xolonium-Regular.otf", 30, 0); while(42) { ALLEGRO_EVENT ev; al_wait_for_event(event_queue, &ev); if(ev.type == ALLEGRO_EVENT_TIMER) { redraw=true; next=select_mover(player, enemies); if(next==100) { if(move_player(&player, keys, map, enemies)) { player.turns_missed=0; inc_turns(&player, enemies); } } else { int ret_x, ret_y; search(enemies[next].x, enemies[next].y, map, player.x, player.y, &ret_x, &ret_y); if(!is_player(ret_x, ret_y, player) && is_enemy(ret_x, ret_y, enemies)==100) { enemies[next].x=ret_x; enemies[next].y=ret_y; } if(is_player(ret_x, ret_y, player)) { fight(&player, enemies, next); } enemies[next].turns_missed=0; inc_turns(&player, enemies); if(!(rand()%(150/level))) { breed(enemies, map); } } if(enemies[selected_enemy].health<=0) { selected_enemy=100; } if(all_enemies_dead(enemies)) { level++; init_map(map); init_enemies(enemies, map, level*5); player.x=0; player.y=0; if(level>best) { best=level; } } if(player.health<=0) { level=1; init_map(map); init_enemies(enemies, map, level*5); player.power=5; player.health=30; player.max_health=30; player.speed=2; player.x=0; player.y=0; player.turns_missed=0; player.kills=0; player.upgrades=0; } } else if(ev.type==ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) { switch(ev.keyboard.keycode) { case ALLEGRO_KEY_UP: keys[KEY_UP]=true; break; case ALLEGRO_KEY_DOWN: keys[KEY_DOWN]=true; break; case ALLEGRO_KEY_RIGHT: keys[KEY_RIGHT]=true; break; case ALLEGRO_KEY_LEFT: keys[KEY_LEFT]=true; break; } } else if(ev.type == ALLEGRO_EVENT_KEY_UP) { switch(ev.keyboard.keycode) { case ALLEGRO_KEY_UP: keys[KEY_UP]=false; break; case ALLEGRO_KEY_DOWN: keys[KEY_DOWN]=false; break; case ALLEGRO_KEY_RIGHT: keys[KEY_RIGHT]=false; break; case ALLEGRO_KEY_LEFT: keys[KEY_LEFT]=false; break; } } else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { int old_selected=selected_enemy; selected_enemy=is_enemy(ev.mouse.x/18, ev.mouse.y/18, enemies); if(selected_enemy==100) selected_enemy=old_selected; if(ev.mouse.x>900 && player.kills >= (player.upgrades * player.upgrades)/10) { bool change=false; if(ev.mouse.y>10 && ev.mouse.y<40) { player.max_health+=5; player.health=player.max_health; change=true; } else if(ev.mouse.y>50 && ev.mouse.y<80) { player.power+=2; change=true; } else if(ev.mouse.y>90 && ev.mouse.y<120) { player.speed+=1; change=true; } if(change) { player.upgrades+=1; } } } if(redraw && al_is_event_queue_empty(event_queue)) { redraw=false; al_clear_to_color(al_map_rgb(255, 255, 255)); draw_map(map); draw_enemies(enemies); al_draw_bitmap(player_img, player.x*18, player.y*18, 0); al_draw_textf(font, al_map_rgb(0, 255, 0), 950, 10, ALLEGRO_ALIGN_CENTRE, "%d", player.health); al_draw_textf(font, al_map_rgb(0, 255, 0), 950, 50, ALLEGRO_ALIGN_CENTRE, "%d", player.power); al_draw_textf(font, al_map_rgb(0, 255, 0), 950, 90, ALLEGRO_ALIGN_CENTRE, "%d", player.speed); al_draw_textf(font, al_map_rgb(0, 0, 255), 950, 150, ALLEGRO_ALIGN_CENTRE, "%d", player.kills); al_draw_textf(font, al_map_rgb(0, 0, 255), 950, 190, ALLEGRO_ALIGN_CENTRE, "%d", (player.upgrades*player.upgrades)/10); if(selected_enemy!=100) { al_draw_textf(font, al_map_rgb(255, 0, 0), 950, 250, ALLEGRO_ALIGN_CENTRE, "%d", enemies[selected_enemy].health); al_draw_textf(font, al_map_rgb(255, 0, 0), 950, 290, ALLEGRO_ALIGN_CENTRE, "%d", enemies[selected_enemy].power); al_draw_textf(font, al_map_rgb(255, 0, 0), 950, 330, ALLEGRO_ALIGN_CENTRE, "%d", enemies[selected_enemy].speed); } al_draw_textf(font, al_map_rgb(0, 0, 0), 950, 390, ALLEGRO_ALIGN_CENTRE, "%d", level); al_draw_textf(font, al_map_rgb(0, 0, 0), 950, 430, ALLEGRO_ALIGN_CENTRE, "%d", best); al_flip_display(); } } return 0; }
void Creature::add_effect( const efftype_id &eff_id, const time_duration dur, body_part bp, bool permanent, int intensity, bool force, bool deferred ) { // Check our innate immunity if( !force && is_immune_effect( eff_id ) ) { return; } if( !eff_id.is_valid() ) { debugmsg( "Invalid effect, ID: %s", eff_id.c_str() ); return; } const effect_type &type = eff_id.obj(); // Mutate to a main (HP'd) body_part if necessary. if (type.get_main_parts()) { bp = mutate_to_main_part(bp); } bool found = false; // Check if we already have it auto matching_map = effects->find(eff_id); if (matching_map != effects->end()) { auto &bodyparts = matching_map->second; auto found_effect = bodyparts.find(bp); if (found_effect != bodyparts.end()) { found = true; effect &e = found_effect->second; const int prev_int = e.get_intensity(); // If we do, mod the duration, factoring in the mod value e.mod_duration( dur * e.get_dur_add_perc() / 100); // Limit to max duration if( e.get_max_duration() > 0_turns && e.get_duration() > e.get_max_duration() ) { e.set_duration( e.get_max_duration() ); } // Adding a permanent effect makes it permanent if( e.is_permanent() ) { e.pause_effect(); } // int_dur_factor overrides all other intensity settings // ...but it's handled in set_duration, so explicitly do nothing here if( e.get_int_dur_factor() > 0_turns ) { // Set intensity if value is given } else if (intensity > 0) { e.set_intensity(intensity); // Else intensity uses the type'd step size if it already exists } else if (e.get_int_add_val() != 0) { e.mod_intensity(e.get_int_add_val()); } // Bound intensity by [1, max intensity] if (e.get_intensity() < 1) { add_msg( m_debug, "Bad intensity, ID: %s", e.get_id().c_str() ); e.set_intensity(1); } else if (e.get_intensity() > e.get_max_intensity()) { e.set_intensity(e.get_max_intensity()); } if( e.get_intensity() != prev_int ) { on_effect_int_change( eff_id, e.get_intensity(), bp ); } } } if( !found ) { // If we don't already have it then add a new one // Then check if the effect is blocked by another for( auto &elem : *effects ) { for( auto &_effect_it : elem.second ) { for( const auto& blocked_effect : _effect_it.second.get_blocks_effects() ) { if (blocked_effect == eff_id) { // The effect is blocked by another, return return; } } } } // Now we can make the new effect for application effect e( &type, dur, bp, permanent, intensity, calendar::turn ); // Bound to max duration if( e.get_max_duration() > 0_turns && e.get_duration() > e.get_max_duration() ) { e.set_duration( e.get_max_duration() ); } // Force intensity if it is duration based if( e.get_int_dur_factor() != 0_turns ) { // + 1 here so that the lowest is intensity 1, not 0 e.set_intensity( e.get_duration() / e.get_int_dur_factor() + 1 ); } // Bound new effect intensity by [1, max intensity] if (e.get_intensity() < 1) { add_msg( m_debug, "Bad intensity, ID: %s", e.get_id().c_str() ); e.set_intensity(1); } else if (e.get_intensity() > e.get_max_intensity()) { e.set_intensity(e.get_max_intensity()); } ( *effects )[eff_id][bp] = e; if (is_player()) { // Only print the message if we didn't already have it if( !type.get_apply_message().empty() ) { add_msg(type.gain_game_message_type(), _(type.get_apply_message().c_str())); } add_memorial_log(pgettext("memorial_male", type.get_apply_memorial_log().c_str()), pgettext("memorial_female", type.get_apply_memorial_log().c_str())); } on_effect_int_change( eff_id, e.get_intensity(), bp ); // Perform any effect addition effects. // only when not deferred if( !deferred ) { process_one_effect( e, true ); } } }
bool is_member(const network::connection player) const { return is_player(player) || is_observer(player); }
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; }
void classPlayer::attack(bool dont_update_colors) { UNUSED(dont_update_colors); st_position proj_pos; if (selected_weapon == WEAPON_DEFAULT) { character::attack(); return; } else if (game_save.items.weapons[selected_weapon] <= 0) { std::cout << "invalid weapon" << std::endl; return; } if (moveCommands.attack == 0 && attack_button_released == false) { attack_button_released = true; return; } int effect_type = is_executing_effect_weapon(); int used_weapon = selected_weapon; if (effect_type == TRAJECTORY_FREEZE) { // freeze can shoot normal projectiles if (max_projectiles > get_projectile_count()) { //std::cout << "TRAJECTORY_FREEZE weapon detected!" << std::endl; character::attack(true); } return; } else if (effect_type != -1) { return; } if (max_projectiles <= get_projectile_count()) { std::cout << "attack - projectile limit reached - max_projectiles: " << max_projectiles << ", projectile_list.size(): " << projectile_list.size() << ", get_projectile_count(): " << get_projectile_count() << std::endl; return; } if (moveCommands.attack != 0 && (timer.getTimer()-state.attack_timer) > 100 && attack_button_released == true) { attack_button_released = false; if (state.direction == ANIM_DIRECTION_LEFT) { proj_pos = st_position(position.x, position.y+frameSize.height/2); } else { proj_pos = st_position(position.x+frameSize.width-TILESIZE*2, position.y+frameSize.height/2); } short int weapon_id = 0; if (used_weapon == WEAPON_ITEM_COIL) { add_coil_object(); } else if (used_weapon == WEAPON_ITEM_JET) { add_jet_object(); } else { weapon_id = used_weapon; } if (weapon_id == 0) { /// @TODO - this is a temporary exit to handle incomplete weapons return; } projectile_list.push_back(projectile(game_data.weapons[weapon_id].id_projectile, state.direction, proj_pos, map, is_player())); projectile &temp_proj = projectile_list.back(); temp_proj.set_is_permanent(); temp_proj.set_weapon_id(weapon_id); //std::cout << "weapon_id: " << weapon_id << ", projectile_id: " << game_data.weapons[weapon_id].id_projectile << std::endl; int weapon_trajectory = game_data.projectiles[game_data.weapons[weapon_id].id_projectile].trajectory; if (weapon_trajectory == TRAJECTORY_CENTERED) { temp_proj.set_owner_direction(&state.direction); temp_proj.set_owner_position(&position); } else if (weapon_trajectory == TRAJECTORY_FOLLOW) { classnpc* temp = find_nearest_npc(); if (temp != NULL) { //std::cout << "PLAYER::attack - could not find target" << std::endl; temp_proj.set_target_position(temp->get_position_ref()); } } //std::cout << "Added projectile - id: " << game_data.weapons[weapon_id].id_projectile << std::endl; if (selected_weapon != WEAPON_DEFAULT) { if (weapon_trajectory == TRAJECTORY_QUAKE) { game_save.items.weapons[selected_weapon] -= 4; } else if (weapon_trajectory == TRAJECTORY_FREEZE) { game_save.items.weapons[selected_weapon] -= 2; } else { game_save.items.weapons[selected_weapon]--; } } attack_state = ATTACK_START; state.attack_timer = timer.getTimer(); if (state.animation_type == ANIM_TYPE_STAND) { set_animation_type(ANIM_TYPE_ATTACK); } else if (state.animation_type == ANIM_TYPE_JUMP) { set_animation_type(ANIM_TYPE_JUMP_ATTACK); } else if (state.animation_type == ANIM_TYPE_STAIRS || state.animation_type == ANIM_TYPE_STAIRS_SEMI || state.animation_type == ANIM_TYPE_STAIRS_MOVE) { set_animation_type(ANIM_TYPE_STAIRS_ATTACK); } else if (state.animation_type == ANIM_TYPE_WALK) { set_animation_type(ANIM_TYPE_WALK_ATTACK); } } }