VerticalFacing Player::vertical_facing() const { if (is_on_ground() && intended_vertical_facing_ == VerticalFacing::DOWN) { return VerticalFacing::HORIZONTAL; } else { return intended_vertical_facing_; } }
void Player::startJump() { is_interacting_ = false; is_jump_active_ = true; if (is_on_ground()) { velocity_.y = -kJumpSpeed; } }
void Player::startMovingRight() { if (is_on_ground() && acceleration_x_direction_ == 0) { walking_animation_.reset(); } horizontal_facing_ = HorizontalFacing::RIGHT; acceleration_x_direction_ = 1; is_interacting_ = false; }
MotionType Player::getMotionType() const { MotionType motion; if (is_interacting_) { motion = MotionType::INTERACTING; } else if (is_on_ground()) { motion = acceleration_x_direction_ == 0 ? MotionType::STANDING : MotionType::WALKING; } else { motion = velocity_.y < 0.0 ? MotionType::JUMPING : MotionType::FALLING; } return motion; }
body_part Creature::select_body_part(Creature *source, int hit_roll) const { // 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, "hit roll = %d", hit_roll); 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]; // 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] += 1; hit_weights[bp_head] += 5; } //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. // pow() is unstable at 0, so don't apply any changes. if( hit_roll != 0 ) { hit_weights[bp_eyes] *= std::pow(hit_roll, 1.15); hit_weights[bp_head] *= std::pow(hit_roll, 1.35); hit_weights[bp_torso] *= std::pow(hit_roll, 1); hit_weights[bp_arm_l] *= std::pow(hit_roll, 0.95); hit_weights[bp_arm_r] *= std::pow(hit_roll, 0.95); hit_weights[bp_leg_l] *= std::pow(hit_roll, 0.975); hit_weights[bp_leg_r] *= std::pow(hit_roll, 0.975); } // 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; for( const auto &hit_weight : hit_weights ) { totalWeight += hit_weight.second; } double roll = rng_float(0, totalWeight); body_part selected_part = bp_torso; for( const auto &hit_candidate : hit_weights) { roll -= hit_candidate.second; if(roll <= 0) { selected_part = hit_candidate.first; break; } } add_msg( m_debug, "selected part: %s", body_part_name(selected_part).c_str() ); return selected_part; }
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; } if(g->debugmon) { g->add_msg("source size = %d", source->get_size()); g->add_msg("target size = %d", get_size()); g->add_msg("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] * pow(hit_roll, 1.15) * 10); hit_weights[bp_head] = floor(hit_weights[bp_head] * pow(hit_roll, 1.15) * 10); hit_weights[bp_torso] = floor(hit_weights[bp_torso] * pow(hit_roll, 1) * 10); hit_weights[bp_arms] = floor(hit_weights[bp_arms] * pow(hit_roll, 0.95) * 10); hit_weights[bp_legs] = floor(hit_weights[bp_legs] * pow(hit_roll, 0.975) * 10); // Debug for seeing weights. if(g->debugmon) { g->add_msg("eyes = %f", hit_weights.at(bp_eyes)); g->add_msg("head = %f", hit_weights.at(bp_head)); g->add_msg("torso = %f", hit_weights.at(bp_torso)); g->add_msg("arms = %f", hit_weights.at(bp_arms)); g->add_msg("legs = %f", hit_weights.at(bp_legs)); } double totalWeight = 0; std::set<weight_pair, weight_compare> adjusted_weights; for(iter = hit_weights.begin(); iter != hit_weights.end(); ++iter) { totalWeight += iter->second; adjusted_weights.insert(*iter); } double roll = rng_float(1, totalWeight); body_part selected_part = bp_torso; std::set<weight_pair, 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; } } return selected_part; }
Player::AnimationState Player::get_animation_state(int &frames) { frames = 1; if (is_ducking()) { /* Is ducking. */ if (velocity_.x < 0) { /* Is moving left. */ return DUCK_LEFT; } if (velocity_.x > 0) { /* Is moving right. */ return DUCK_RIGHT; } return isLastMovementLeft_ ? DUCK_LEFT : DUCK_RIGHT; } else if (state() == GameScene::PLAYER_DEAD){ return DEAD_; } else if (is_splashing()){ /*SPLASH ATTACK*/ frames = 2; return SPLASHING_; } else if (velocity_.is_zero()){ /* Not moving at all. */ return isLastMovementLeft_ ? IDLE_LEFT : IDLE_RIGHT; } else if (is_on_ground()) {/* Is on ground. */ if (velocity_.x > 0) { /* Is moving right. */ if (keys_ & KEY_LEFT) { return SLIDE_RIGHT; } frames = 3; return RUN_RIGHT; } if (velocity_.x < 0) { /* Is moving left. */ if (keys_ & KEY_RIGHT) { return SLIDE_LEFT; } frames = 3; return RUN_LEFT; } return isLastMovementLeft_ ? IDLE_LEFT : IDLE_RIGHT; } else { if (velocity_.y < -0.1f) { /* Jumping. */ if (velocity_.x > 0) { /* Is moving right or straight up. */ return JUMP_RIGHT; } if (velocity_.x < 0) { /* Is moving left. */ return JUMP_LEFT; } return isLastMovementLeft_ ? JUMP_LEFT : JUMP_RIGHT; } else { /* Falling */ if (velocity_.x > 0) { /* Is moving right or straight up. */ return FALL_RIGHT; } if (velocity_.x < 0) { /* Is moving left. */ return FALL_LEFT; } return isLastMovementLeft_ ? FALL_LEFT : FALL_RIGHT; } } }
void Player::updateX(const std::chrono::milliseconds elapsed_time, const Map& map, ParticleTools&) { // Update velocity units::Acceleration acceleration_x{0.0}; if (acceleration_x_direction_ < 0) { acceleration_x = is_on_ground() ? -kWalkingAcceleration : -kAirAcceleration; } else if (acceleration_x_direction_ > 0) { acceleration_x = is_on_ground() ? kWalkingAcceleration : kAirAcceleration; } velocity_.x += acceleration_x * elapsed_time.count(); if (acceleration_x_direction_ < 0) { velocity_.x = std::max(velocity_.x, -kMaxSpeedX); } else if (acceleration_x_direction_ > 0) { velocity_.x = std::min(velocity_.x, kMaxSpeedX); } else if (is_on_ground()) { velocity_.x = velocity_.x > 0.0 ? std::max(0.0, velocity_.x - kFriction * elapsed_time.count()) : std::min(0.0, velocity_.x + kFriction * elapsed_time.count()); } // Calculate delta const units::Game delta = velocity_.x * elapsed_time.count(); if (delta > 0.0) { // Check collision in the direction of delta CollisionInfo info = getWallCollisionInfo(map, rightCollision(delta)); // React to collision if (info.collided) { pos_.x = units::tileToGame(info.col) - kCollisionX.getRight(); velocity_.x = 0.0; } else { pos_.x += delta; } // Check collision in the direction opposite to delta info = getWallCollisionInfo(map, leftCollision(0)); if (info.collided) { pos_.x = units::tileToGame(info.col) + kCollisionX.getRight(); } } else { // Check collision in the direction of delta CollisionInfo info = getWallCollisionInfo(map, leftCollision(delta)); // React to collision if (info.collided) { pos_.x = units::tileToGame(info.col) + kCollisionX.getRight(); velocity_.x = 0.0; } else { pos_.x += delta; } // Check collision in the direction opposite to delta info = getWallCollisionInfo(map, rightCollision(0)); if (info.collided) { pos_.x = units::tileToGame(info.col) - kCollisionX.getRight(); } } }
void Player::lookDown() { if (intended_vertical_facing_ == VerticalFacing::DOWN) return; intended_vertical_facing_ = VerticalFacing::DOWN; is_interacting_ = is_on_ground(); }
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; }