static bool handle_spell_slot_io(GameState* gs, PlayerInst* p, const BBox& bbox, ActionQueue& queued_actions) { int mx = gs->mouse_x(), my = gs->mouse_y(); bool leftdown = gs->mouse_left_down(), rightdown = gs->mouse_right_down(); /* Check if a spell is selected */ int spell_slot = get_selected_slot(bbox, mx, my); if (leftdown && spell_slot > -1) { if (spell_slot < p->spells_known().amount()) { queued_actions.push_back( game_action(gs, p, GameAction::CHOSE_SPELL, spell_slot)); } return true; // Ensures mouse actions are filtered when clicking on action bar } if (rightdown && spell_slot > -1) { if (spell_slot < p->spells_known().amount()) { queued_actions.push_back( game_action(gs, p, GameAction::CHOSE_SPELL, -1)); } return true; // Ensures mouse actions are filtered when clicking on action bar } return false; }
static bool handle_equip_slot_io(GameState* gs, PlayerInst* p, const BBox& bbox, ActionQueue& queued_actions) { int mx = gs->mouse_x(), my = gs->mouse_y(); bool leftdown = gs->mouse_left_down(), rightdown = gs->mouse_right_down(); /* Check whether to de-equip weapon */ if (rightdown && is_within_equipped_weapon(bbox, mx, my)) { queued_actions.push_back( game_action(gs, p, GameAction::DEEQUIP_ITEM, EquipmentEntry::WEAPON)); return true; } /* Check whether to de-equip projectile */ if (rightdown && is_within_equipped_projectile(bbox, mx, my)) { if (!p->projectile().empty()) { queued_actions.push_back( game_action(gs, p, GameAction::DEEQUIP_ITEM, EquipmentEntry::AMMO)); return true; } } /* Check whether to select weapon as active action */ bool selects_projectile = !p->projectile().empty() && is_within_equipped_projectile(bbox, mx, my); if (leftdown && (is_within_equipped_weapon(bbox, mx, my) || selects_projectile)) { queued_actions.push_back( game_action(gs, p, GameAction::CHOSE_SPELL, -1)); return true; } return false; }
static bool queue_portal_use(GameState* gs, PlayerInst* player, ActionQueue& queue) { FeatureInst* portal = find_usable_portal(gs, player); if (portal != NULL) { queue.push_back( game_action(gs, player, GameAction::USE_PORTAL)); return true; } return false; }
bool InventoryContent::handle_io(GameState* gs, ActionQueue& queued_actions) { PlayerInst* p = gs->local_player(); Inventory& inv = p->inventory(); int mx = gs->mouse_x(), my = gs->mouse_y(); bool within_inventory = bbox.contains(mx, my); /* Use an item */ if (gs->mouse_left_click() && within_inventory) { int slot = get_itemslotn(inv, bbox, mx, my); if (slot >= 0 && slot < INVENTORY_SIZE && inv.get(slot).amount > 0) { queued_actions.push_back( game_action(gs, p, GameAction::USE_ITEM, slot, p->x, p->y)); return true; } } /* Start dragging an item */ if (gs->mouse_right_click() && within_inventory) { int slot = get_itemslotn(inv, bbox, mx, my); if (slot != -1 && inv.slot_filled(slot)) { slot_selected = slot; return true; } } /* Drop a dragged item */ if (slot_selected > -1 && gs->mouse_right_release()) { int slot = get_itemslotn(inv, bbox, mx, my); if (slot == -1 || slot == slot_selected) { queued_actions.push_back( game_action(gs, p, GameAction::DROP_ITEM, slot_selected)); } else { queued_actions.push_back( game_action(gs, p, GameAction::REPOSITION_ITEM, slot_selected, 0, 0, slot)); } return true; } return false; }
void PlayerInst::enqueue_not_enough_mana_actions(GameState* gs) { const int AUTOUSE_MANA_POTION_CNT = 2; int item_slot = inventory().find_slot(get_item_by_name("Mana Potion")); if (gs->game_settings().autouse_mana_potions && autouse_mana_potion_try_count >= AUTOUSE_MANA_POTION_CNT && item_slot != -1) { queued_actions.push_back( game_action(gs, this, GameAction::USE_ITEM, item_slot)); autouse_mana_potion_try_count = 0; } else { autouse_mana_potion_try_count++; } }
static bool handle_io_spells_known(GameState* gs, ActionQueue& queued_actions, const BBox& bbox, SpellsKnown& spells, int ind_low, int ind_high) { const int spell_n = spells.amount(); int mx = gs->mouse_x(), my = gs->mouse_y(); int spellidx = ind_low; int x = bbox.x1, ex = bbox.x2; for (int y = bbox.y1; y < bbox.y2; y += TILE_SIZE) { if (spellidx >= spell_n) break; BBox entry_box(x, y, ex - 2, y + TILE_SIZE); if (entry_box.contains(mx, my) && gs->mouse_left_click()) { queued_actions.push_back( game_action(gs, gs->local_player(), GameAction::CHOSE_SPELL, spellidx)); return true; } spellidx++; } return false; }
void PlayerInst::enqueue_io_movement_actions(GameState* gs, int& dx, int& dy) { //Arrow/wasd movement if (gs->key_down_state(SDLK_UP) || gs->key_down_state(SDLK_w)) { dy -= 1; } if (gs->key_down_state(SDLK_RIGHT) || gs->key_down_state(SDLK_d)) { dx += 1; } if (gs->key_down_state(SDLK_DOWN) || gs->key_down_state(SDLK_s)) { dy += 1; } if (gs->key_down_state(SDLK_LEFT) || gs->key_down_state(SDLK_a)) { dx -= 1; } if (dx != 0 || dy != 0) { queued_actions.push_back( game_action(gs, this, GameAction::MOVE, 0, dx, dy)); moving = true; } else { moving = false; } }
bool StoreContent::handle_io(GameState* gs, ActionQueue& queued_actions) { PlayerInst* p = gs->local_player(); StoreInventory& inv = store_inventory(); int mx = gs->mouse_x(), my = gs->mouse_y(); bool within_inventory = bbox.contains(mx, my); /* Buy an item (left click) */ if (gs->mouse_left_click() && within_inventory) { int slot = get_itemslotn(inv, bbox, mx, my); if (slot >= 0 && slot < INVENTORY_SIZE && inv.get(slot).amount > 0) { if (p->gold() >= inv.get(slot).cost) { queued_actions.push_back( game_action(gs, p, GameAction::PURCHASE_FROM_STORE, store_object->id, NONE, NONE, slot)); } else { gs->game_chat().add_message("You cannot afford it!", COL_PALE_RED); } return true; } } return false; }
// 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; }
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; }
void PlayerInst::enqueue_io_actions(GameState* gs) { LANARTS_ASSERT(is_local_player() && gs->local_player() == this); if (actions_set_for_turn) { return; } bool single_player = (gs->player_data().all_players().size() <= 1); actions_set_for_turn = true; GameSettings& settings = gs->game_settings(); GameView& view = gs->view(); PlayerDataEntry& pde = gs->player_data().local_player_data(); if (pde.action_queue.has_actions_for_frame(gs->frame())) { pde.action_queue.extract_actions_for_frame(queued_actions, gs->frame()); event_log("Player %d has %d actions", player_entry(gs).net_id, (int) queued_actions.size()); return; } if (!single_player) { gs->set_repeat_actions_counter(settings.frame_action_repeat); } int dx = 0, dy = 0; bool mouse_within = gs->mouse_x() < gs->view().width; int rmx = view.x + gs->mouse_x(), rmy = view.y + gs->mouse_y(); bool was_moving = moving, do_stopaction = false; IOController& io = gs->io_controller(); if (!settings.loadreplay_file.empty()) { load_actions(gs, queued_actions); } enqueue_io_movement_actions(gs, dx, dy); if (was_moving && !moving && cooldowns().can_do_stopaction()) { do_stopaction = true; } //Shifting target if (gs->key_press_state(SDLK_k)) { shift_autotarget(gs); } if (gs->key_press_state(SDLK_m)) spellselect = -1; bool attack_used = false; if (!gs->game_hud().handle_io(gs, queued_actions)) { attack_used = enqueue_io_spell_and_attack_actions(gs, dx, dy); enqueue_io_equipment_actions(gs, do_stopaction); } bool action_usage = io.query_event(IOEvent::ACTIVATE_SPELL_N) || io.query_event(IOEvent::USE_WEAPON) || io.query_event(IOEvent::AUTOTARGET_CURRENT_ACTION) || io.query_event(IOEvent::MOUSETARGET_CURRENT_ACTION); if ((do_stopaction && !action_usage) || gs->key_down_state(SDLK_PERIOD) || gs->mouse_downwheel()) { queue_portal_use(gs, this, queued_actions); } // If we haven't done anything, rest if (queued_actions.empty()) { queued_actions.push_back(game_action(gs, this, GameAction::USE_REST)); } ActionQueue only_passive_actions; for (int i = 0; i < queued_actions.size(); i++) { GameAction::action_t act = queued_actions[i].act; if (act == GameAction::MOVE || act == GameAction::USE_REST) { only_passive_actions.push_back(queued_actions[i]); } } GameNetConnection& net = gs->net_connection(); if (net.is_connected()) { net_send_player_actions(net, gs->frame(), player_get_playernumber(gs, this), queued_actions); } int repeat = single_player ? 0 : settings.frame_action_repeat; for (int i = 1; i <= repeat; i++) { for (int j = 0; j < only_passive_actions.size(); j++) { only_passive_actions[j].frame = gs->frame() + i; } pde.action_queue.queue_actions_for_frame(only_passive_actions, gs->frame() + i); if (net.is_connected()) { net_send_player_actions(net, gs->frame() + i, player_get_playernumber(gs, this), only_passive_actions); } } }
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)); } }