parent
39987cd1ca
commit
d3b3c8c07a
13 changed files with 232 additions and 3 deletions
|
@ -151,6 +151,11 @@
|
|||
key=k
|
||||
shift=yes
|
||||
[/hotkey]
|
||||
[hotkey]
|
||||
command=teleportunit
|
||||
key=t
|
||||
shift=yes
|
||||
[/hotkey]
|
||||
[hotkey]
|
||||
command=labelteamterrain
|
||||
key=l
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
# Zoom
|
||||
"zoomin,zoomout,zoomdefault," +
|
||||
# Debug commands
|
||||
"createunit,changeside,killunit," +
|
||||
"createunit,changeside,killunit,teleportunit," +
|
||||
# Labels
|
||||
"labelterrain,clearlabels," +
|
||||
# Shroud updates
|
||||
|
|
|
@ -207,6 +207,8 @@ namespace { // Private helpers for move_unit()
|
|||
void post_move(undo_list *undo_stack);
|
||||
/** Shows the various on-screen messages, for use after movement. */
|
||||
void feedback() const;
|
||||
/** Attempts to teleport the unit to a map_location. */
|
||||
void try_teleport(bool show);
|
||||
|
||||
/** After checking expected movement, this is the expected path. */
|
||||
std::vector<map_location> expected_path() const
|
||||
|
@ -273,6 +275,10 @@ namespace { // Private helpers for move_unit()
|
|||
inline bool do_move(const route_iterator & step_from,
|
||||
const route_iterator & step_to,
|
||||
unit_display::unit_mover & animator);
|
||||
|
||||
/** Teleports the unit. */
|
||||
inline bool do_teleport(unit_display::unit_mover& animator);
|
||||
|
||||
/** Clears fog/shroud and handles units being sighted. */
|
||||
inline void handle_fog(const map_location & hex, bool new_animation);
|
||||
inline bool is_reasonable_stop(const map_location & hex) const;
|
||||
|
@ -538,6 +544,40 @@ namespace { // Private helpers for move_unit()
|
|||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports the unit to begin_ + 1.
|
||||
* @a animator is the unit_display::unit_mover being used.
|
||||
* @return whether or not we started a new animation.
|
||||
*/
|
||||
inline bool unit_mover::do_teleport(unit_display::unit_mover& animator)
|
||||
{
|
||||
game_display& disp = *game_display::get_singleton();
|
||||
const route_iterator step_to = begin_ + 1;
|
||||
|
||||
// Invalidate before moving so we invalidate neighbor hexes if needed.
|
||||
move_it_->anim_comp().invalidate(disp);
|
||||
|
||||
// Attempt actually moving. Fails if *step_to is occupied.
|
||||
auto [unit_it, success] = resources::gameboard->units().move(*begin_, *step_to);
|
||||
|
||||
if(success) {
|
||||
// Update the moving unit.
|
||||
move_it_ = unit_it;
|
||||
move_it_->set_facing(begin_->get_relative_dir(*step_to));
|
||||
|
||||
move_it_->anim_comp().set_standing(false);
|
||||
disp.invalidate_unit_after_move(*begin_, *step_to);
|
||||
disp.invalidate(*step_to);
|
||||
move_loc_ = step_to;
|
||||
|
||||
// Show this move.
|
||||
animator.proceed_to(move_it_.get_shared_ptr(), step_to - begin_, move_it_->appearance_changed(), false);
|
||||
|
||||
move_it_->set_appearance_changed(false);
|
||||
disp.redraw_minimap();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears fog/shroud and raises events for units being sighted.
|
||||
|
@ -1012,6 +1052,50 @@ namespace { // Private helpers for move_unit()
|
|||
event_mutated_mid_move_ = wml_removed_unit_ || wml_move_aborted_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to teleport the unit to a map_location.
|
||||
*
|
||||
* @param[in] show Set to false to suppress animations.
|
||||
*/
|
||||
void unit_mover::try_teleport(bool show)
|
||||
{
|
||||
const route_iterator step_from = real_end_ - 1;
|
||||
|
||||
std::vector<int> not_seeing = get_sides_not_seeing(*move_it_);
|
||||
|
||||
// Prepare to animate.
|
||||
unit_display::unit_mover animator(route_, show);
|
||||
animator.start(move_it_.get_shared_ptr());
|
||||
fire_hex_event("exit hex", step_from, begin_);
|
||||
|
||||
bool new_animation = do_teleport(animator);
|
||||
|
||||
if(current_uses_fog_)
|
||||
handle_fog(*(begin_ + 1), new_animation);
|
||||
|
||||
animator.wait_for_anims();
|
||||
|
||||
fire_hex_event("enter hex", begin_, step_from);
|
||||
|
||||
if(is_reasonable_stop(*step_from)) {
|
||||
pump_sighted(step_from);
|
||||
}
|
||||
|
||||
pump_sighted(step_from);
|
||||
|
||||
if(move_it_.valid()) {
|
||||
// Finish animating.
|
||||
animator.finish(move_it_.get_shared_ptr());
|
||||
|
||||
// Check for the moving unit being seen.
|
||||
auto [wml_undo_blocked, wml_move_aborted] = actor_sighted(*move_it_, ¬_seeing);
|
||||
|
||||
wml_move_aborted_ |= wml_move_aborted;
|
||||
wml_undo_disabled_ |= wml_undo_blocked;
|
||||
}
|
||||
|
||||
post_move(resources::undo_stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does some bookkeeping and event firing, for use after movement.
|
||||
|
@ -1205,6 +1289,46 @@ static std::size_t move_unit_internal(undo_list* undo_stack,
|
|||
return mover.steps_travelled();
|
||||
}
|
||||
|
||||
void teleport_unit_and_record(const map_location& teleport_from,
|
||||
const map_location& teleport_to,
|
||||
bool show_move,
|
||||
move_unit_spectator* move_spectator)
|
||||
{
|
||||
const bool skip_ally_sighted = true;
|
||||
const bool continued_move = false;
|
||||
|
||||
const std::vector<map_location>& route{teleport_from, teleport_to};
|
||||
|
||||
unit_mover mover(route, move_spectator, continued_move, skip_ally_sighted);
|
||||
|
||||
if(synced_context::get_synced_state() != synced_context::SYNCED) {
|
||||
/*
|
||||
enter the synced mode and do the actual movement.
|
||||
*/
|
||||
resources::recorder->add_synced_command("debug_teleport",
|
||||
config{"teleport_from_x", teleport_from.wml_x(), "teleport_from_y", teleport_from.wml_y(), "teleport_to_x",
|
||||
teleport_to.wml_x(), "teleport_to_y", teleport_to.wml_y()});
|
||||
set_scontext_synced sync;
|
||||
mover.try_teleport(show_move);
|
||||
sync.do_final_checkup();
|
||||
} else {
|
||||
// we are already in synced mode and don't need to reenter it again.
|
||||
mover.try_teleport(show_move);
|
||||
}
|
||||
}
|
||||
|
||||
void teleport_unit_from_replay(const std::vector<map_location> &steps,
|
||||
bool continued_move, bool skip_ally_sighted, bool show_move)
|
||||
{
|
||||
unit_mover mover(steps, nullptr, continued_move, skip_ally_sighted);
|
||||
if ( !mover.check_expected_movement() )
|
||||
{
|
||||
replay::process_error("found corrupt movement in replay.");
|
||||
return;
|
||||
}
|
||||
mover.try_teleport(show_move);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a unit across the board.
|
||||
*
|
||||
|
|
|
@ -98,6 +98,24 @@ private:
|
|||
*/
|
||||
game_events::pump_result_t get_village(const map_location& loc, int side, bool *time_bonus = nullptr, bool fire_event = true);
|
||||
|
||||
/**
|
||||
* Teleports a unit across the board and enters the synced context.
|
||||
*/
|
||||
void teleport_unit_and_record(const map_location& teleport_from,
|
||||
const map_location& teleport_to,
|
||||
bool show_move = false,
|
||||
move_unit_spectator* move_spectator = nullptr);
|
||||
|
||||
/**
|
||||
* Teleports a unit across the board.
|
||||
* To be called from replay when we are already in the synced context.
|
||||
*/
|
||||
void teleport_unit_from_replay(
|
||||
const std::vector<map_location> &steps,
|
||||
bool continued_move,
|
||||
bool skip_ally_sighted,
|
||||
bool show_move);
|
||||
|
||||
/**
|
||||
* Moves a unit across the board.
|
||||
* And enters the synced context.
|
||||
|
|
|
@ -197,6 +197,9 @@ bool command_executor::do_execute_command(const hotkey::ui_command& cmd, bool pr
|
|||
case HOTKEY_KILL_UNIT:
|
||||
kill_unit();
|
||||
break;
|
||||
case HOTKEY_TELEPORT_UNIT:
|
||||
select_teleport();
|
||||
break;
|
||||
case HOTKEY_PREFERENCES:
|
||||
preferences();
|
||||
break;
|
||||
|
|
|
@ -136,6 +136,7 @@ public:
|
|||
virtual void deselect_hex() {}
|
||||
virtual void move_action() {}
|
||||
virtual void select_and_action() {}
|
||||
virtual void select_teleport() {}
|
||||
virtual void touch_hex() {}
|
||||
virtual void left_mouse_click() {}
|
||||
virtual void right_mouse_click() {}
|
||||
|
|
|
@ -122,6 +122,7 @@ constexpr std::array<hotkey_command_temp, HOTKEY_NULL - 1> master_hotkey_list {{
|
|||
{ HOTKEY_CREATE_UNIT, "createunit", N_("Create Unit (Debug!)"), false, scope_game, HKCAT_DEBUG, "" },
|
||||
{ HOTKEY_CHANGE_SIDE, "changeside", N_("Change Side (Debug!)"), false, scope_game, HKCAT_DEBUG, "" },
|
||||
{ HOTKEY_KILL_UNIT, "killunit", N_("Kill Unit (Debug!)"), false, scope_game, HKCAT_DEBUG, "" },
|
||||
{ HOTKEY_TELEPORT_UNIT, "teleportunit", N_("Teleport Unit (Debug!)"), false, scope_game, HKCAT_DEBUG, "" },
|
||||
{ HOTKEY_PREFERENCES, "preferences", N_("Preferences"), false, scope_game | scope_editor | scope_main, HKCAT_GENERAL, "" },
|
||||
{ HOTKEY_OBJECTIVES, "objectives", N_("Objectives"), false, scope_game, HKCAT_MAP, "" },
|
||||
{ HOTKEY_UNIT_LIST, "unitlist", N_("Unit List"), false, scope_game | scope_editor, HKCAT_UNITS, "" },
|
||||
|
|
|
@ -56,7 +56,7 @@ enum HOTKEY_COMMAND {
|
|||
HOTKEY_SAVE_GAME, HOTKEY_SAVE_REPLAY, HOTKEY_SAVE_MAP, HOTKEY_LOAD_GAME,
|
||||
HOTKEY_RECRUIT, HOTKEY_REPEAT_RECRUIT, HOTKEY_RECALL, HOTKEY_ENDTURN,
|
||||
HOTKEY_TOGGLE_ELLIPSES, HOTKEY_TOGGLE_GRID, HOTKEY_STATUS_TABLE, HOTKEY_MUTE, HOTKEY_MOUSE_SCROLL,
|
||||
HOTKEY_SPEAK, HOTKEY_CREATE_UNIT, HOTKEY_CHANGE_SIDE, HOTKEY_KILL_UNIT, HOTKEY_PREFERENCES,
|
||||
HOTKEY_SPEAK, HOTKEY_CREATE_UNIT, HOTKEY_CHANGE_SIDE, HOTKEY_KILL_UNIT, HOTKEY_PREFERENCES, HOTKEY_TELEPORT_UNIT,
|
||||
HOTKEY_OBJECTIVES, HOTKEY_UNIT_LIST, HOTKEY_STATISTICS, HOTKEY_STOP_NETWORK, HOTKEY_START_NETWORK, HOTKEY_SURRENDER, HOTKEY_QUIT_GAME, HOTKEY_QUIT_TO_DESKTOP,
|
||||
HOTKEY_LABEL_TEAM_TERRAIN, HOTKEY_LABEL_TERRAIN, HOTKEY_CLEAR_LABELS,HOTKEY_SHOW_ENEMY_MOVES, HOTKEY_BEST_ENEMY_MOVES,
|
||||
HOTKEY_DELAY_SHROUD, HOTKEY_UPDATE_SHROUD, HOTKEY_CONTINUE_MOVE,
|
||||
|
|
|
@ -98,6 +98,10 @@ void playsingle_controller::hotkey_handler::kill_unit(){
|
|||
menu_handler_.kill_unit(mouse_handler_);
|
||||
}
|
||||
|
||||
void playsingle_controller::hotkey_handler::select_teleport(){
|
||||
mouse_handler_.select_teleport();
|
||||
}
|
||||
|
||||
void playsingle_controller::hotkey_handler::label_terrain(bool team_only){
|
||||
menu_handler_.label_terrain(mouse_handler_, team_only);
|
||||
}
|
||||
|
@ -248,6 +252,7 @@ bool playsingle_controller::hotkey_handler::can_execute_command(const hotkey::ui
|
|||
case hotkey::HOTKEY_CREATE_UNIT:
|
||||
case hotkey::HOTKEY_CHANGE_SIDE:
|
||||
case hotkey::HOTKEY_KILL_UNIT:
|
||||
case hotkey::HOTKEY_TELEPORT_UNIT:
|
||||
return !events::commands_disabled && game_config::debug && play_controller_.get_map().on_board(mouse_handler_.get_last_hex()) && play_controller_.current_team().is_local();
|
||||
|
||||
case hotkey::HOTKEY_CLEAR_LABELS:
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
virtual void rename_unit() override;
|
||||
virtual void create_unit() override;
|
||||
virtual void change_side() override;
|
||||
virtual void select_teleport() override;
|
||||
virtual void kill_unit() override;
|
||||
virtual void label_terrain(bool) override;
|
||||
virtual void clear_labels() override;
|
||||
|
|
|
@ -73,6 +73,7 @@ mouse_handler::mouse_handler(game_display* gui, play_controller& pc)
|
|||
, over_route_(false)
|
||||
, reachmap_invalid_(false)
|
||||
, show_partial_move_(false)
|
||||
, teleport_selected_(false)
|
||||
, preventing_units_highlight_(false)
|
||||
{
|
||||
singleton_ = this;
|
||||
|
@ -821,6 +822,47 @@ bool mouse_handler::right_click_show_menu(int x, int y, const bool /*browse*/)
|
|||
return gui().map_area().contains(x, y);
|
||||
}
|
||||
|
||||
void mouse_handler::select_teleport()
|
||||
{
|
||||
// Load whiteboard partial moves
|
||||
//wb::future_map_if_active planned_unit_map;
|
||||
|
||||
if(game_lua_kernel* lk = pc_.gamestate().lua_kernel_.get()) {
|
||||
lk->select_hex_callback(last_hex_);
|
||||
}
|
||||
|
||||
unit_map::iterator clicked_u = find_unit(last_hex_);
|
||||
unit_map::iterator selected_u = find_unit(selected_hex_);
|
||||
|
||||
if(clicked_u && (!selected_u || selected_u->side() != side_num_ ||
|
||||
(clicked_u->side() == side_num_ && clicked_u->id() != selected_u->id()))
|
||||
) {
|
||||
selected_hex_ = last_hex_;
|
||||
teleport_selected_ = true;
|
||||
gui().select_hex(selected_hex_);
|
||||
gui().set_route(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void mouse_handler::teleport_action()
|
||||
{
|
||||
// Set the teleport to active so that we can use existing functions
|
||||
// for teleport
|
||||
teleport_selected_ = false;
|
||||
|
||||
actions::teleport_unit_and_record(selected_hex_, last_hex_);
|
||||
cursor::set(cursor::NORMAL);
|
||||
gui().invalidate_game_status();
|
||||
gui().invalidate_all();
|
||||
gui().clear_attack_indicator();
|
||||
gui().set_route(nullptr);
|
||||
|
||||
// Select and deselect the units hex to prompt updates for hover
|
||||
select_hex(last_hex_, false);
|
||||
deselect_hex();
|
||||
current_route_.steps.clear();
|
||||
}
|
||||
|
||||
void mouse_handler::select_or_action(bool browse)
|
||||
{
|
||||
if(!pc_.get_map().on_board(last_hex_)) {
|
||||
|
@ -845,6 +887,7 @@ void mouse_handler::select_or_action(bool browse)
|
|||
} else {
|
||||
move_action(browse);
|
||||
}
|
||||
teleport_selected_ = false;
|
||||
}
|
||||
|
||||
void mouse_handler::move_action(bool browse)
|
||||
|
@ -889,8 +932,12 @@ void mouse_handler::move_action(bool browse)
|
|||
attack_from = current_unit_attacks_from(hex);
|
||||
} // end planned unit map scope
|
||||
|
||||
// See if the teleport option is toggled
|
||||
if(teleport_selected_) {
|
||||
teleport_action();
|
||||
}
|
||||
// see if we're trying to do a attack or move-and-attack
|
||||
if((!browse || pc_.get_whiteboard()->is_active()) && attack_from.valid()) {
|
||||
else if((!browse || pc_.get_whiteboard()->is_active()) && attack_from.valid()) {
|
||||
// Ignore this command if commands are disabled.
|
||||
if(commands_disabled) {
|
||||
return;
|
||||
|
|
|
@ -83,10 +83,12 @@ public:
|
|||
const bool fire_event = true);
|
||||
|
||||
void move_action(bool browse) override;
|
||||
void teleport_action();
|
||||
|
||||
void touch_action(const map_location hex, bool browse) override;
|
||||
|
||||
void select_or_action(bool browse);
|
||||
void select_teleport();
|
||||
|
||||
/**
|
||||
* Uses SDL and @ref game_display::hex_clicked_on
|
||||
|
@ -192,6 +194,7 @@ private:
|
|||
bool over_route_;
|
||||
bool reachmap_invalid_;
|
||||
bool show_partial_move_;
|
||||
bool teleport_selected_;
|
||||
|
||||
static mouse_handler * singleton_;
|
||||
|
||||
|
|
|
@ -594,6 +594,27 @@ SYNCED_COMMAND_HANDLER_FUNCTION(debug_lua, child, use_undo, /*show*/, /*error_ha
|
|||
return true;
|
||||
}
|
||||
|
||||
SYNCED_COMMAND_HANDLER_FUNCTION(debug_teleport, child, use_undo, /*show*/, /*error_handler*/)
|
||||
{
|
||||
if(use_undo) {
|
||||
resources::undo_stack->clear();
|
||||
}
|
||||
debug_cmd_notification("teleport");
|
||||
|
||||
const map_location teleport_from(child["teleport_from_x"].to_int(), child["teleport_from_y"].to_int(), wml_loc());
|
||||
const map_location teleport_to(child["teleport_to_x"].to_int(), child["teleport_to_y"].to_int(), wml_loc());
|
||||
|
||||
const unit_map::iterator unit_iter = resources::gameboard->units().find(teleport_from);
|
||||
if(unit_iter != resources::gameboard->units().end()) {
|
||||
if(unit_iter.valid()) {
|
||||
actions::teleport_unit_from_replay({teleport_from, teleport_to}, false, false, false);
|
||||
}
|
||||
display::get_singleton()->redraw_minimap();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SYNCED_COMMAND_HANDLER_FUNCTION(debug_kill, child, use_undo, /*show*/, /*error_handler*/)
|
||||
{
|
||||
if (use_undo) {
|
||||
|
|
Loading…
Add table
Reference in a new issue