Ejemplo n.º 1
0
bool CombatGameInst::damage(GameState* gs, int dmg) {
	if (core_stats().hurt(dmg)) {
		die(gs);
		return true;
	}
	signal_was_damaged();
	cooldowns().reset_hurt_cooldown(HURT_COOLDOWN);
	return false;
}
Ejemplo n.º 2
0
void PlayerInst::use_rest(GameState* gs, const GameAction& action) {
	if (!effective_stats().allowed_actions.can_use_rest) {
		return;
	}
	CoreStats& ecore = effective_stats().core;
	int emax_hp = ecore.max_hp, emax_mp = ecore.max_mp;
	bool atfull = core_stats().hp >= emax_hp && core_stats().mp >= emax_mp;
	if (cooldowns().can_rest() && !atfull && effects().can_rest()) {
		core_stats().heal_hp(ecore.hpregen * 8, emax_hp);
		core_stats().heal_mp(ecore.mpregen * 8, emax_mp);
		ecore.hp = core_stats().hp;
		ecore.mp = core_stats().mp;
		is_resting = true;
	}
}
Ejemplo n.º 3
0
void PlayerInst::use_spell(GameState* gs, const GameAction& action) {
    if (!effective_stats().allowed_actions.can_use_spells) {
        return;
    }
    MTwist& mt = gs->rng();
    EffectiveStats& estats = effective_stats();

    spell_id spell = spells_known().get(action.use_id);
    SpellEntry& spl_entry = game_spell_data.at(spell);

    if (spl_entry.mp_cost > core_stats().mp
            || (!spl_entry.can_cast_with_cooldown && !cooldowns().can_doaction())) {
        return;
    }

    Pos target = Pos(action.action_x, action.action_y);
    player_use_spell(gs, this, spl_entry, target);

    cooldowns().action_cooldown *= estats.cooldown_mult;
    cooldowns().reset_rest_cooldown(REST_COOLDOWN);
}
Ejemplo n.º 4
0
void PlayerInst::use_weapon(GameState* gs, const GameAction& action) {
    WeaponEntry& wentry = weapon().weapon_entry();
    MTwist& mt = gs->rng();
    const int MAX_MELEE_HITS = 10;
    EffectiveStats& estats = effective_stats();
    if (!cooldowns().can_doaction()) {
        return;
    }

    Pos start(x, y);
    Pos actpos(action.action_x, action.action_y);

    if (wentry.uses_projectile && !equipment().has_projectile()) {
        return;
    }

    int cooldown = 0;

    if (equipment().has_projectile()) {
        const Projectile& projectile = equipment().projectile;
        ProjectileEntry& pentry = projectile.projectile_entry();
        item_id item = get_item_by_name(pentry.name.c_str());
        int weaprange = std::max(wentry.range, pentry.range);

        AttackStats weaponattack(weapon());

        bool wallbounce = false;
        int nbounces = 0;
        float movespeed = pentry.speed;

        cooldown = std::max(wentry.cooldown, pentry.cooldown);

        //XXX: Horrible hack REMOVE THIS LATER
        if (class_stats().class_type().name == "Archer"
                && pentry.weapon_class == "bows") {
            int xplevel = class_stats().xplevel;
            float movebonus = class_stats().xplevel / 4.0f;
            if (movebonus > 2) {
                movebonus = 2;
            }
            float cooldown_mult = 1.0f - (class_stats().xplevel - 1) / 20.0f;
            if (cooldown_mult <= 0.85) {
                cooldown_mult = 0.85;
            }
            cooldown *= cooldown_mult;
            movespeed += movebonus;
            if (xplevel >= 3 && core_stats().mp >= 5) {
                nbounces = 2;
                core_stats().mp -= 5;
            }
        }

        GameInst* bullet = new ProjectileInst(projectile,
                                              effective_atk_stats(mt, weaponattack), id, start, actpos,
                                              movespeed, weaprange, NONE, wallbounce, nbounces);
        gs->add_instance(bullet);
        equipment().use_ammo();
    } else {
        int weaprange = wentry.range + this->radius + TILE_SIZE / 2;
        float mag = distance_between(actpos, Pos(x, y));
        if (mag > weaprange) {
            float dx = actpos.x - x, dy = actpos.y - y;
            actpos = Pos(x + dx / mag * weaprange, y + dy / mag * weaprange);
        }

        GameInst* enemies[MAX_MELEE_HITS];

        int max_targets = std::min(MAX_MELEE_HITS, wentry.max_targets);

        int numhit = get_targets(gs, this, actpos.x, actpos.y, wentry.dmgradius,
                                 enemies, max_targets);

        if (numhit == 0) {
            return;
        }

        for (int i = 0; i < numhit; i++) {
            EnemyInst* e = (EnemyInst*)enemies[i];
            lua_hit_callback(gs->get_luastate(), wentry.on_hit_func, this, e);
            if (attack(gs, e, AttackStats(equipment().weapon))) {
                PlayerData& pc = gs->player_data();
                signal_killed_enemy();

                char buffstr[32];
                int amnt = round(
                               double(e->xpworth()) / pc.all_players().size());
                players_gain_xp(gs, amnt);
                snprintf(buffstr, 32, "%d XP", amnt);
                gs->add_instance(
                    new AnimatedInst(Pos(e->x - 5, e->y - 5), -1, 25,
                                     Posf(), Posf(), AnimatedInst::DEPTH, buffstr,
                                     Colour(255, 215, 11)));
            }
        }
        cooldown = wentry.cooldown;
    }

    cooldowns().reset_action_cooldown(cooldown * estats.cooldown_mult);

    reset_rest_cooldown();
}
Ejemplo n.º 5
0
// dx & dy indicates moving direction, useful for choosing melee attack targets
bool PlayerInst::enqueue_io_spell_and_attack_actions(GameState* gs, float dx,
        float dy) {
    GameView& view = gs->view();
    WeaponEntry& wentry = weapon().weapon_entry();

    bool mouse_within = gs->mouse_x() < gs->view().width;
    int rmx = view.x + gs->mouse_x(), rmy = view.y + gs->mouse_y();

    int level = gs->get_level()->id(), frame = gs->frame();

    bool is_moving = (dx != 0.0f || dy != 0.0f);
    IOController& io = gs->io_controller();
    bool attack_used = enqueue_io_spell_actions(gs);

    bool autotarget = io.query_event(IOEvent::AUTOTARGET_CURRENT_ACTION)
                      || io.query_event(IOEvent::ACTIVATE_SPELL_N);
    bool mousetarget = io.query_event(IOEvent::MOUSETARGET_CURRENT_ACTION);

    bool weaponuse = spell_selected() == -1;

    // choose & use weapon
    if (io.query_event(IOEvent::USE_WEAPON)) {
        queued_actions.push_back(
            game_action(gs, this, GameAction::CHOSE_SPELL, -1));
        autotarget = true;
        weaponuse = true;
    }

    if (spell_selected() >= 0
            && spells_known().get_entry(spell_selected()).mp_cost
            > core_stats().mp) {
        weaponuse = true;
    }

    // weapon use
    if (!attack_used && weaponuse && (autotarget || mousetarget)) {

        bool is_projectile = wentry.uses_projectile
                             || equipment().has_projectile();

        MonsterController& mc = gs->monster_controller();
        GameInst* curr_target = gs->get_instance(current_target);
        GameInst* target = NULL;
        Pos targ_pos;

        if (is_projectile) {
            if (mousetarget) {
                targ_pos = Pos(rmx, rmy);
            } else if (autotarget && curr_target) {
                targ_pos = curr_target->pos();
            }
        } else {
            if (mousetarget) {
                dx = rmx - x, dy = rmy - y;
            }
            target = get_weapon_autotarget(gs, this, curr_target, dx, dy);
            if (target) {
                targ_pos = Pos(target->x, target->y);

            }
            if (!is_moving && !target && !mousetarget && spell_selected() == -1
                    && curr_target && !is_projectile) {
                int vx, vy;
                GameInst* closest = get_closest_monster(gs, this);

                if (closest
                        && decide_attack_movement(pos(), closest->pos(),
                                                  TILE_SIZE / 4, vx, vy)) {
                    queued_actions.push_back(
                        game_action(gs, this, GameAction::MOVE, spellselect,
                                    round(vx), round(vy)));
                }
            }
        }
        if (target || (is_projectile && (mousetarget || curr_target))) {
            queued_actions.push_back(
                game_action(gs, this, GameAction::USE_WEAPON, spellselect,
                            targ_pos.x, targ_pos.y));
            attack_used = true;
        }
    }
    return attack_used;
}
Ejemplo n.º 6
0
bool PlayerInst::enqueue_io_spell_actions(GameState* gs) {
    GameView& view = gs->view();
    IOController& io = gs->io_controller();
    SpellsKnown& spells = spells_known();

    bool perform_spell = false;
    bool chose_spell = false;
    bool triggered_already = false;

    int newspell = spell_selected();
    //Spell choice
    for (int i = 0; i < spells.amount(); i++) {
        IOEvent event(IOEvent::ACTIVATE_SPELL_N, i);
        if (io.query_event(event, &triggered_already)) {
            chose_spell = true;
            // Use the remembered choice to determine if its appropriate to cast this spell
            // This makes sure the key must be hit once to switch spell, and again to use it
            if (spell_selected() == i
                    && previous_spellselect == spell_selected()) {
                //Double hit a spell switch to quick-perform it
                perform_spell = true;
            } else if (!triggered_already) {
                newspell = i;
            }
            break;
        }
    }
    if (!chose_spell) {
        // If we did not switch a spell with one of the quick-select keys, remember our choice
        previous_spellselect = spell_selected();

        if (io.query_event(IOEvent::TOGGLE_ACTION_UP)) {
            if (spells.amount() > 0) {
                newspell = (spell_selected() + 1) % spells.amount();
            }
        } else if (io.query_event(IOEvent::TOGGLE_ACTION_DOWN)) {
            if (spell_selected() <= 0) {
                newspell = spells.amount() - 1;
            } else {
                newspell = spell_selected() - 1;
            }
        }
    }

    if (newspell != spell_selected()) {
        queued_actions.push_back(
            game_action(gs, this, GameAction::CHOSE_SPELL, newspell));
    }

    bool auto_target = true;
    // We don't auto-target unless a mouse is not used
    if (!perform_spell
            && io.query_event(IOEvent::MOUSETARGET_CURRENT_ACTION,
                              &triggered_already)) {
        perform_spell = true;
        auto_target = false;

    } else if (!perform_spell) {
        perform_spell = io.query_event(IOEvent::AUTOTARGET_CURRENT_ACTION,
                                       &triggered_already);
    }
    if (spell_selected() > -1 && perform_spell) {
        SpellEntry& spl_entry = spells.get_entry(spell_selected());

        Pos target;
        bool can_trigger = !triggered_already
                           || spl_entry.can_cast_with_held_key;
        bool can_target;
        if (auto_target) {
            can_target = lua_spell_get_target(gs, this,
                                              spl_entry.autotarget_func, target);
        } else {
            int rmx = view.x + gs->mouse_x(), rmy = view.y + gs->mouse_y();
            target = Pos(rmx, rmy);
            can_target = true;
        }

        if (spl_entry.mp_cost > core_stats().mp) {
            if (!triggered_already && can_target) {
                enqueue_not_enough_mana_actions(gs);
            }
            return false;
        } else {
            autouse_mana_potion_try_count = 0;
        }

        if (can_trigger && can_target) {
            bool can_use = lua_spell_check_prereq(gs, this, spl_entry,
                                                  spl_entry.prereq_func, target);
            if (can_use) {
                queued_actions.push_back(
                    game_action(gs, this, GameAction::USE_SPELL,
                                spell_selected(), target.x, target.y));
                return true;
            } else if (!auto_target) {
                gs->game_chat().add_message("Target location is not valid.");
            }
        } else if (!triggered_already && !can_target) {
            gs->game_chat().add_message(
                "Cannot currently auto-target spell. Use manual controls (with mouse).");
        }
    }
    return false;
}
Ejemplo n.º 7
0
void PlayerInst::enqueue_io_equipment_actions(GameState* gs,
		bool do_stopaction) {
	GameView& view = gs->view();
	bool mouse_within = gs->mouse_x() < gs->view().width;
	int rmx = view.x + gs->mouse_x(), rmy = view.y + gs->mouse_y();

	int level = gs->get_level()->id();
	int frame = gs->frame();
	bool item_used = false;
	IOController& io = gs->io_controller();

	Pos p(gs->mouse_x() + view.x, gs->mouse_y() + view.y);
	obj_id target = this->current_target;
	GameInst* targetted = gs->get_instance(target);
	if (targetted)
		p = Pos(targetted->x, targetted->y);

// We may have already used an item eg due to auto-use of items
	bool used_item = false;

//Item use
	for (int i = 0; i < 9 && !used_item; i++) {
		if (io.query_event(IOEvent(IOEvent::USE_ITEM_N, i))) {
			if (inventory().get(i).amount() > 0) {
				item_used = true;
				queued_actions.push_back(
						GameAction(id, GameAction::USE_ITEM, frame, level, i,
								p.x, p.y));
			}
		}
	}
	if (!used_item && gs->game_settings().autouse_health_potions
			&& core_stats().hp < AUTOUSE_HEALTH_POTION_THRESHOLD) {
		int item_slot = inventory().find_slot(
				get_item_by_name("Health Potion"));
		if (item_slot > -1) {
			queued_actions.push_back(
					game_action(gs, this, GameAction::USE_ITEM, item_slot));
			used_item = true;
		}
	}

//Item pickup
	GameInst* inst = NULL;
	if (cooldowns().can_pickup()
			&& gs->object_radius_test(this, &inst, 1, &item_colfilter)) {
		ItemInst* iteminst = (ItemInst*)inst;
		Item& item = iteminst->item_type();

		bool was_dropper = iteminst->last_held_by() == id;
		bool dropper_autopickup = iteminst->autopickup_held();

		bool autopickup = (item.is_normal_item() && !was_dropper
				&& !dropper_autopickup) || (was_dropper && dropper_autopickup);

		bool wieldable_projectile = projectile_should_autowield(equipment(),
				item, this->last_chosen_weaponclass);

		bool pickup_io = gs->key_down_state(SDLK_LSHIFT)
				|| gs->key_down_state(SDLK_RSHIFT);

		if (do_stopaction || wieldable_projectile || pickup_io || autopickup)
			queued_actions.push_back(
					GameAction(id, GameAction::PICKUP_ITEM, frame, level,
							iteminst->id));
	}
}