Exemple #1
0
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] );
    }
}
Exemple #3
0
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] );
    }
}
Exemple #4
0
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() );
}
Exemple #6
0
/*
 * 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()));
        }
    }
}
Exemple #7
0
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);
	}
}
Exemple #8
0
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 );
}
Exemple #9
0
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()));
        }
    }
}
Exemple #11
0
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;
    }
}
Exemple #12
0
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;
}
Exemple #15
0
/*
 * 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;
}
Exemple #16
0
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;
}
Exemple #19
0
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);
    }
}
Exemple #20
0
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;
}
Exemple #21
0
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;
}
Exemple #22
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);
    }
}
Exemple #23
0
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;
}
Exemple #24
0
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 );
        }
    }
}
Exemple #26
0
	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);
		}
	}
}