Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support adventure mode look cursor #5230

Merged
merged 8 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ Template for new versions:
## API

## Lua
- ``dfhack.units.setAutomaticProfessions``: sets unit labors according to current work detail settings

## Removed

Expand All @@ -60,6 +59,8 @@ Template for new versions:
- `spectate`: new global keybinding for toggling spectate mode: Ctrl-Shift-S

## Fixes
- `gui/launcher`: ensure commandline is fully visible when searching through history and switching from a very long command to a short command
- `createitem`: output items will now end up at look cursor if active
- `spectate`: don't allow temporarily modified announcement settings to be written to disk when "auto-unpause" mode is enabled
- `changevein`: fix a crash that could occur when attempting to change a vein into itself

Expand All @@ -72,6 +73,7 @@ Template for new versions:
## API

## Lua
- ``dfhack.units.setAutomaticProfessions``: sets unit labors according to current work detail settings

## Removed

Expand Down
25 changes: 22 additions & 3 deletions library/lua/gui/dwarfmode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ local utils = require('utils')

local dscreen = dfhack.screen

local a_look = df.global.game.main_interface.adventure.look
local g_cursor = df.global.cursor
local g_sel_rect = df.global.selection_rect
local world_map = df.global.world.map
Expand Down Expand Up @@ -38,17 +39,35 @@ end

---@return df.coord|nil
function getCursorPos()
if g_cursor.x >= 0 then
if dfhack.world.isAdventureMode() then
if a_look.open then
return copyall(a_look.cursor)
end
elseif g_cursor.x >= 0 then
return copyall(g_cursor)
end
end

function setCursorPos(cursor)
df.global.cursor = copyall(cursor)
if dfhack.world.isAdventureMode() then
a_look.cursor = copyall(cursor)
else
df.global.cursor = copyall(cursor)
end
end

function clearCursorPos()
df.global.cursor = xyz2pos(nil)
if dfhack.world.isAdventureMode() then
if not a_look.open then
return
end
local u = dfhack.world.getAdventurer()
if u and u.pos:isValid() then
a_look.cursor = copyall(u.pos)
end
else
df.global.cursor = xyz2pos(nil)
end
end

function getSelection()
Expand Down
69 changes: 51 additions & 18 deletions library/modules/Gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,9 @@ static void add_main_interface_focus_strings(const string &baseFocus, vector<str
if (game->main_interface.adventure.jump.open) {
focusStrings.push_back(baseFocus + "/Jump");
}
if (game->main_interface.adventure.look.open) {
focusStrings.push_back(baseFocus + "/Look");
}
if (game->main_interface.adventure.movement_options.open) {
focusStrings.push_back(baseFocus + "/MovementOptions");
}
Expand Down Expand Up @@ -2745,9 +2748,18 @@ df::coord Gui::getViewportPos()
df::coord Gui::getCursorPos()
{
using df::global::cursor;
if (World::isAdventureMode())
{
if (!game)
return df::coord();
auto &look = game->main_interface.adventure.look;
if (!look.open)
return df::coord();
return look.cursor;
}

if (!cursor)
return df::coord();

return df::coord(cursor->x, cursor->y, cursor->z);
}

Expand Down Expand Up @@ -2912,56 +2924,77 @@ bool Gui::inRenameBuilding()
return false;
}

bool Gui::getViewCoords (int32_t &x, int32_t &y, int32_t &z)
bool Gui::getViewCoords(int32_t &x, int32_t &y, int32_t &z)
{
x = *df::global::window_x;
y = *df::global::window_y;
z = *df::global::window_z;
return true;
}

bool Gui::setViewCoords (const int32_t x, const int32_t y, const int32_t z)
bool Gui::setViewCoords(const int32_t x, const int32_t y, const int32_t z)
{
(*df::global::window_x) = x;
(*df::global::window_y) = y;
(*df::global::window_z) = z;
return true;
}

bool Gui::getCursorCoords (int32_t &x, int32_t &y, int32_t &z)
bool Gui::getCursorCoords(int32_t &x, int32_t &y, int32_t &z)
{
x = df::global::cursor->x;
y = df::global::cursor->y;
z = df::global::cursor->z;
using df::global::cursor;
bool is_adv = World::isAdventureMode();
if (is_adv || !cursor)
{
df::coord p;
if (is_adv && game)
{
auto &look = game->main_interface.adventure.look;
if (look.open)
p = look.cursor;
}
x = p.x; y = p.y; z = p.z;
return p.isValid();
}

x = cursor->x; y = cursor->y; z = cursor->z;
return has_cursor();
}

bool Gui::getCursorCoords (df::coord &pos)
bool Gui::getCursorCoords(df::coord &pos)
{
pos.x = df::global::cursor->x;
pos.y = df::global::cursor->y;
pos.z = df::global::cursor->z;
return has_cursor();
pos = getCursorPos();
return pos.isValid();
}

//FIXME: confine writing of coords to map bounds?
bool Gui::setCursorCoords (const int32_t x, const int32_t y, const int32_t z)
bool Gui::setCursorCoords(const int32_t x, const int32_t y, const int32_t z)
{
df::global::cursor->x = x;
df::global::cursor->y = y;
df::global::cursor->z = z;
using df::global::cursor;
if (World::isAdventureMode())
{
if (!game)
return false;
auto &look = game->main_interface.adventure.look;
look.cursor = df::coord(x, y, z);
return true;
}
if (!cursor)
return false;

cursor->x = x; cursor->y = y; cursor->z = z;
return true;
}

bool Gui::getDesignationCoords (int32_t &x, int32_t &y, int32_t &z)
bool Gui::getDesignationCoords(int32_t &x, int32_t &y, int32_t &z)
{
x = selection_rect->start_x;
y = selection_rect->start_y;
z = selection_rect->start_z;
return (x >= 0) ? false : true;
}

bool Gui::setDesignationCoords (const int32_t x, const int32_t y, const int32_t z)
bool Gui::setDesignationCoords(const int32_t x, const int32_t y, const int32_t z)
{
selection_rect->start_x = x;
selection_rect->start_y = y;
Expand Down
13 changes: 7 additions & 6 deletions plugins/changevein.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// Allow changing the material of a mineral inclusion

#include "Console.h"
#include "DataDefs.h"
#include "Export.h"
#include "PluginManager.h"
#include "TileTypes.h"

#include "DataDefs.h"
#include "modules/Gui.h"
#include "modules/Maps.h"
#include "modules/Materials.h"
#include "TileTypes.h"

#include "df/block_square_event.h"
#include "df/block_square_event_mineralst.h"
Expand All @@ -21,7 +22,6 @@ using namespace df::enums;

DFHACK_PLUGIN("changevein");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor);

constexpr uint8_t NORTH = 0;
constexpr uint8_t EAST = 1;
Expand Down Expand Up @@ -212,7 +212,8 @@ command_result df_changevein (color_ostream &out, vector <string> & parameters)
out.printerr("Map is not available!\n");
return CR_FAILURE;
}
if (!cursor || cursor->x == -30000)
auto pos = Gui::getCursorPos();
if (!pos.isValid())
{
out.printerr("No cursor detected - please place the cursor over a mineral vein.\n");
return CR_FAILURE;
Expand All @@ -232,14 +233,14 @@ command_result df_changevein (color_ostream &out, vector <string> & parameters)
return CR_FAILURE;
}

df::map_block *block = Maps::getTileBlock(cursor->x, cursor->y, cursor->z);
auto block = Maps::getTileBlock(pos);
if (!block)
{
out.printerr("Invalid tile selected.\n");
return CR_FAILURE;
}
df::block_square_event_mineralst *mineral = NULL;
int tx = cursor->x % 16, ty = cursor->y % 16;
int tx = pos.x % 16, ty = pos.y % 16;
for (auto evt : block->block_events)
{
if (evt->getType() != block_square_event_type::mineral)
Expand Down
10 changes: 7 additions & 3 deletions plugins/createitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ using namespace DFHack;
using namespace df::enums;

DFHACK_PLUGIN("createitem");
REQUIRE_GLOBAL(cursor);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(gametype);
REQUIRE_GLOBAL(cur_year_tick);
Expand Down Expand Up @@ -84,7 +83,10 @@ bool makeItem(df::unit *unit, df::item_type type, int16_t subtype, int16_t mat_t
out_items[i]->moveToGround(building->centerx, building->centery, building->z);
}
else if (move_to_cursor)
out_items[i]->moveToGround(cursor->x, cursor->y, cursor->z);
{
auto pos = Gui::getCursorPos();
out_items[i]->moveToGround(pos.x, pos.y, pos.z);
}
// else createItem() already put it on the floor at the unit's feet, so we're good

// Special logic for creating proper gloves in pairs
Expand Down Expand Up @@ -395,11 +397,13 @@ command_result df_createitem (color_ostream &out, vector<string> &parameters) {

auto unit = Gui::getSelectedUnit(out, true);
if (!unit) {
auto pos = Gui::getCursorPos();
if (*gametype == game_type::ADVENTURE_ARENA || World::isAdventureMode())
{ // Use the adventurer unit
unit = World::getAdventurer();
move_to_cursor = pos.isValid();
}
else if (cursor->x >= 0)
else if (pos.isValid())
{ // Use the first possible citizen if possible, otherwise the first unit
for (auto u : Units::citizensRange(world->units.active)) {
unit = u;
Expand Down
7 changes: 3 additions & 4 deletions plugins/cursecheck.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// cursecheck plugin
//
// check single tile or whole map/world for cursed creatures by checking if a valid curse date (!=-1) is set
// if a cursor is active only the selected tile will be observed
// without cursor the whole map will be checked
// check unit or whole map/world for cursed creatures by checking if a valid curse date (!=-1) is set
// if a unit is selected only the selected unit will be observed
// otherwise the whole map will be checked
// by default cursed creatures will be only counted
//
// the tool was intended to help finding vampires but it will also list necromancers, werebeasts and zombies
Expand Down Expand Up @@ -38,7 +38,6 @@ using namespace df::enums;

DFHACK_PLUGIN("cursecheck");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor);

enum curses {
None = 0,
Expand Down
1 change: 0 additions & 1 deletion plugins/devel/stripcaged.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ using std::string;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::cursor;
using df::global::plotinfo;

using namespace DFHack::Gui;
Expand Down
15 changes: 8 additions & 7 deletions plugins/zone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ using std::vector;

DFHACK_PLUGIN_IS_ENABLED(is_enabled);

REQUIRE_GLOBAL(cursor);
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(plotinfo);
REQUIRE_GLOBAL(ui_building_item_cursor);
Expand Down Expand Up @@ -844,14 +843,15 @@ static void chainInfo(color_ostream & out, df::building* building, bool list_ref
static df::building* getAssignableBuildingAtCursor(color_ostream& out)
{
// set building at cursor position to be new target building
if (cursor->x == -30000)
auto pos = Gui::getCursorPos();
if (!pos.isValid())
{
out.printerr("No cursor; place cursor over activity zone, pen,"
" pasture, pit, pond, chain, or cage.\n");
return NULL;
}

auto building_at_tile = Buildings::findAtTile(Gui::getCursorPos());
auto building_at_tile = Buildings::findAtTile(pos);

// cagezone wants a pen/pit as starting point
if (isCage(building_at_tile))
Expand All @@ -861,7 +861,7 @@ static df::building* getAssignableBuildingAtCursor(color_ostream& out)
}
else
{
auto zone_at_tile = Buildings::findPenPitAt(Gui::getCursorPos());
auto zone_at_tile = Buildings::findPenPitAt(pos);
if(!zone_at_tile)
{
out << "No pen/pasture, pit, or cage under cursor!" << endl;
Expand Down Expand Up @@ -1069,7 +1069,8 @@ static command_result df_zone(color_ostream &out, vector <string> & parameters)
}
else if(p0 == "zinfo")
{
if (cursor->x == -30000) {
auto pos = Gui::getCursorPos();
if (!pos.isValid()) {
out.color(COLOR_RED);
out << "No cursor; place cursor over activity zone, chain, or cage." << endl;
out.reset_color();
Expand All @@ -1081,10 +1082,10 @@ static command_result df_zone(color_ostream &out, vector <string> & parameters)
// (doesn't use the findXyzAtCursor() methods because zones might
// overlap and contain a cage or chain)
vector<df::building_civzonest*> zones;
Buildings::findCivzonesAt(&zones, Gui::getCursorPos());
Buildings::findCivzonesAt(&zones, pos);
for (auto zone = zones.begin(); zone != zones.end(); ++zone)
zoneInfo(out, *zone, verbose);
df::building* building = Buildings::findAtTile(Gui::getCursorPos());
df::building* building = Buildings::findAtTile(pos);
chainInfo(out, building, verbose);
cageInfo(out, building, verbose);
return CR_OK;
Expand Down