game: add controls to change smoothness in game

This commit is contained in:
Crypto City 2023-06-10 20:33:06 +00:00
parent 4d0f98cc5c
commit d4a5a85c4f
9 changed files with 211 additions and 14 deletions

View File

@ -357,6 +357,8 @@ TBLayout: axis: y, distribution-position: "center top", distribution: "available
TBButton: skin: "TBButton.column", text: "Add flat", id: "actions-add-block-flat"
TBButton: skin: "TBButton.column", text: "Remove", id: "actions-remove-block"
TBButton: skin: "TBButton.column", text: "Remove top level", id: "actions-remove-top-level"
TBButton: skin: "TBButton.column", text: "Rougher", id: "actions-decrease-smoothness"
TBButton: skin: "TBButton.column", text: "Smoother", id: "actions-increase-smoothness"
TBButton: skin: "TBButton.column", text: "Undo", id: "actions-undo"
TBButton: skin: "TBButton.column", text: "Redo", id: "actions-redo"
TBButton: skin: "TBButton.column", text: "Approve build", id: "actions-approve-build"

View File

@ -2458,7 +2458,7 @@ if (flagRenderMode != RenderSurfaceNets)
if (offset >= sndata.size())
printf("OFFSET OUT OF BOUNDS!!! %u %u %u -> %u %u %u, lens %u %u %u %u/%zu, from %u %u to %u %u, shift %u\n",
x, y, h, snx, sny, snz, x_len, y_len, z_len, offset, sndata.size(), fx0, fy0, fx1, fy1, shift);
const uint16_t smoothness = 7 * cm_sns;
const uint16_t smoothness = tiles[tile_idx].get_smoothness(h);
sndata[offset] = 0x8000 | (smoothness << 10) | (mv << 8) | material_type;
}
}

View File

@ -192,6 +192,8 @@ Controls::Controls():
actions[ACTION_TOGGLE_FULLSCREEN] = "Toggle fullscreen";
actions[ACTION_TOGGLE_PANEL] = "Toggle panel";
actions[ACTION_HAIL] = "Hail";
actions[ACTION_DECREASE_SMOOTHNESS] = "Decrease smoothness";
actions[ACTION_INCREASE_SMOOTHNESS] = "Increase smoothness";
Set(ACTION_FORWARD, INPUT_KEY_W);
Set(ACTION_BACKWARD, INPUT_KEY_S);
@ -232,6 +234,8 @@ Controls::Controls():
Set(ACTION_TOGGLE_FULLSCREEN, INPUT_KEY_F11);
Set(ACTION_TOGGLE_PANEL, INPUT_KEY_F12);
Set(ACTION_HAIL, INPUT_KEY_H);
Set(ACTION_DECREASE_SMOOTHNESS, INPUT_KEY_QUOTE);
Set(ACTION_INCREASE_SMOOTHNESS, INPUT_KEY_BACKSLASH);
}
void Controls::RegisterKey(Input input, Urho3D::Key key, const char *name)

View File

@ -51,6 +51,8 @@ public:
ACTION_TOGGLE_FULLSCREEN,
ACTION_TOGGLE_PANEL,
ACTION_HAIL,
ACTION_DECREASE_SMOOTHNESS,
ACTION_INCREASE_SMOOTHNESS,
NUM_ACTIONS
};

View File

@ -420,6 +420,7 @@ public:
void HandleUpdateItem(StringHash eventType, VariantMap& eventData);
void HandleAddBlock(StringHash eventType, VariantMap& eventData);
void HandleRemoveBlock(StringHash eventType, VariantMap& eventData);
void HandleChangeSmoothness(StringHash eventType, VariantMap& eventData);
void HandleRemoveHiddenBlocks(StringHash eventType, VariantMap& eventData);
void HandleRemovePlaceholderBlocks(StringHash eventType, VariantMap& eventData);
void HandleDemolish(StringHash eventType, VariantMap& eventData);
@ -682,6 +683,7 @@ private:
void SelectNextMaterial(bool next);
void AddBlock(bool use_selection, bool flat);
void RemoveBlock(bool use_selection, bool top_level);
void ChangeSmoothness(bool use_selection, int32_t delta);
void RemoveHiddenBlocks();
void RemovePlaceholderBlocks();
std::vector<std::pair<std::shared_ptr<tb::TBBitmap>, unsigned int>> LoadImage(const String &filename);
@ -976,6 +978,16 @@ private:
}
};
struct ChangeSmoothnessCommand: public QueuedCommand
{
ChangeSmoothnessCommand(bool use_selection, int32_t delta): use_selection(use_selection), delta(delta) {}
virtual void execute(CryptoCityUrho3D &e) {
e.ChangeSmoothness(use_selection, delta);
}
bool use_selection;
int32_t delta;
};
};
CryptoCityUrho3D::CryptoCityUrho3D(Context *ctx):
@ -1639,6 +1651,7 @@ void CryptoCityUrho3D::SetupUI()
SubscribeToEvent(ui, E_CRYPTOCITY_UPDATE_ITEM, URHO3D_HANDLER(CryptoCityUrho3D, HandleUpdateItem));
SubscribeToEvent(ui, E_CRYPTOCITY_ADD_BLOCK, URHO3D_HANDLER(CryptoCityUrho3D, HandleAddBlock));
SubscribeToEvent(ui, E_CRYPTOCITY_REMOVE_BLOCK, URHO3D_HANDLER(CryptoCityUrho3D, HandleRemoveBlock));
SubscribeToEvent(ui, E_CRYPTOCITY_CHANGE_SMOOTHNESS, URHO3D_HANDLER(CryptoCityUrho3D, HandleChangeSmoothness));
SubscribeToEvent(ui, E_CRYPTOCITY_REMOVE_HIDDEN_BLOCKS, URHO3D_HANDLER(CryptoCityUrho3D, HandleRemoveHiddenBlocks));
SubscribeToEvent(ui, E_CRYPTOCITY_REMOVE_PLACEHOLDER_BLOCKS, URHO3D_HANDLER(CryptoCityUrho3D, HandleRemovePlaceholderBlocks));
SubscribeToEvent(ui, E_CRYPTOCITY_DEMOLISH_FLAG, URHO3D_HANDLER(CryptoCityUrho3D, HandleDemolish));
@ -6457,6 +6470,117 @@ void CryptoCityUrho3D::HandleAddBlock(StringHash eventType, VariantMap& eventDat
AddBlock(true, flat);
}
void CryptoCityUrho3D::ChangeSmoothness(bool use_selection, int32_t delta)
{
UnsetFocus();
if (use_selection && !hasSelection_)
return;
if (!use_selection && (!mouse_x || !mouse_y))
return;
uint32_t selection_x0 = use_selection ? selection.x0 : top_x;
uint32_t selection_y0 = use_selection ? selection.y0 : top_y;
uint32_t selection_x1 = use_selection ? selection.x1 : top_x;
uint32_t selection_y1 = use_selection ? selection.y1 : top_y;
std::shared_ptr<Flag> flag = map.get_flag(gameState.cityState.id, selection_x0, selection_y0);
if (!flag)
{
if (use_selection)
new MessageBox(context_, "There is no flag there");
return;
}
if (flag->role == ROLE_EMPTY)
{
new MessageBox(context_, "Select building settings first");
return;
}
if (flagUnderConstruction && std::get<0>(*flagUnderConstruction) != flag->id)
{
new MessageBox(context_, "You can only build on a single lot at once: either commit or cancel the one you're buildng on now first");
return;
}
const auto i = flags_with_pending_build_commands.find(flag->id);
if (i != flags_with_pending_build_commands.end() && i->second > 0)
{
new MessageBox(context_, "There are pending build commands on this flag, modifying it now would create conflict");
return;
}
Flag::unpacker unpacker(flag);
EndModelPlacement();
if (!flagUnderConstruction)
{
auto tiles = flag->get_tiles();
flagUnderConstruction = std::make_tuple(flag->id, flag->palette, tiles, std::shared_ptr<Flag::unpacker>(new Flag::unpacker(flag)));
undo.Push(std::make_pair(std::move(tiles), flag->palette));
SaveBackup();
if (flag->owner != gameState.playerState.id)
new MessageBox(context_, "You do not own this flag:\nyou will not be able to submit any change to the blockchain", "Info");
ui->AddToastNotification("New build started. When done, either approve or abandon it\nPress/hold X to select block type to build with");
}
selection_x0 = std::max(selection_x0, flag->x0);
selection_y0 = std::max(selection_y0, flag->y0);
selection_x1 = std::min(selection_x1, flag->x1);
selection_y1 = std::min(selection_y1, flag->y1);
bool done = false;
if (use_selection)
{
for (uint32_t y = selection_y0; y <= selection_y1; ++y)
{
for (uint32_t x = selection_x0; x <= selection_x1; ++x)
{
const uint16_t th = flag->get_tile_height(x, y);
if (top_h >= th)
continue;
uint8_t smoothness = flag->get_tile_smoothness(x, y, top_h);
if (delta == -1 && smoothness == 0)
continue;
if (delta == 1 && smoothness == 7)
continue;
flag->set_tile_smoothness(x, y, top_h, smoothness + delta);
done = true;
}
}
}
else
{
const uint16_t local_mouse_h = mouse_h >= flag->base_height ? mouse_h - flag->base_height : 0;
for (int i = 0; i < 1; ++i)
{
const uint16_t th = flag->get_tile_height(mouse_x, mouse_y);
if (local_mouse_h >= th)
break;
uint8_t smoothness = flag->get_tile_smoothness(mouse_x, mouse_y, local_mouse_h);
if (delta == -1 && smoothness == 0)
break;
if (delta == 1 && smoothness == 7)
break;
flag->set_tile_smoothness(mouse_x, mouse_y, local_mouse_h, smoothness + delta);
done = true;
}
}
if (done)
{
undo.Push(std::make_pair(map.get_flag_tiles(flag->id), map.get_flag_palette(flag->id)));
SaveBackup();
std::deque<std::shared_ptr<Flag>> flags;
flags.push_back(flag);
cityMesh->RebuildFlags(flags, GetEffectiveSelection(), false);
}
}
void CryptoCityUrho3D::HandleChangeSmoothness(StringHash eventType, VariantMap& eventData)
{
const int32_t delta = eventData[ChangeSmoothness::P_DELTA].GetInt();
ChangeSmoothness(true, delta);
}
void CryptoCityUrho3D::SetNoFlagUnderConstruction()
{
undo.Clear();
@ -10459,6 +10583,14 @@ void CryptoCityUrho3D::HandleKeyDown(StringHash /*eventType*/, VariantMap& event
if (cameraLight)
cameraLight->Remove();
}
else if (action == Controls::ACTION_DECREASE_SMOOTHNESS)
{
queued_commands.push_back(std::shared_ptr<ChangeSmoothnessCommand>(new ChangeSmoothnessCommand(false, -1)));
}
else if (action == Controls::ACTION_INCREASE_SMOOTHNESS)
{
queued_commands.push_back(std::shared_ptr<ChangeSmoothnessCommand>(new ChangeSmoothnessCommand(false, 1)));
}
// console
else if (action == Controls::ACTION_TOGGLE_CONSOLE)

View File

@ -16,24 +16,30 @@ void Tile::push(uint8_t type)
throw std::runtime_error("Height overflow");
if (height < small_tile_threshold)
{
local_blocks[height++] = type;
local_blocks[height * 2] = type;
local_blocks[height * 2 + 1] = 0;
++height;
}
else if (height == small_tile_threshold)
{
uint8_t local_blocks_copy[small_tile_threshold];
memcpy(local_blocks_copy, local_blocks, small_tile_threshold);
uint8_t local_blocks_copy[small_tile_threshold * 2];
memcpy(local_blocks_copy, local_blocks, small_tile_threshold * 2);
remote_blocks = (uint8_t*)malloc(128);
if (!remote_blocks)
throw std::bad_alloc();
memcpy(remote_blocks, local_blocks_copy, small_tile_threshold);
remote_blocks[height++] = type;
memcpy(remote_blocks, local_blocks_copy, small_tile_threshold * 2);
remote_blocks[height * 2] = type;
remote_blocks[height * 2 + 1] = 0;
++height;
}
else
{
remote_blocks = (uint8_t*)realloc(remote_blocks, std::max<size_t>(128, height + 1));
remote_blocks = (uint8_t*)realloc(remote_blocks, std::max<size_t>(128, (height + 1) * 2));
if (!remote_blocks)
throw std::bad_alloc();
remote_blocks[height++] = type;
remote_blocks[height * 2] = type;
remote_blocks[height * 2 + 1] = 0;
++height;
}
}
@ -44,7 +50,7 @@ void Tile::pop()
if (height == small_tile_threshold + 1)
{
void *ptr = remote_blocks;
memcpy(local_blocks, remote_blocks, small_tile_threshold);
memcpy(local_blocks, remote_blocks, small_tile_threshold * 2);
free(ptr);
}
--height;
@ -55,9 +61,19 @@ void Tile::set_type(uint16_t h, uint8_t type)
if (h >= height)
throw std::runtime_error("Height overflow");
if (height <= small_tile_threshold)
local_blocks[h] = type;
local_blocks[h * 2] = type;
else
remote_blocks[h] = type;
remote_blocks[h * 2] = type;
}
void Tile::set_smoothness(uint16_t h, uint8_t s)
{
if (h >= height)
throw std::runtime_error("Height overflow");
if (height <= small_tile_threshold)
local_blocks[h * 2 + 1] = s;
else
remote_blocks[h * 2 + 1] = s;
}
Flag::Flag(uint32_t id, uint32_t owner, uint32_t city, uint8_t role, uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t repair, uint32_t economic_power, const uint8_t potential[NUM_POTENTIALS], uint16_t base_height, uint32_t elevation_bonus, uint32_t average_slope, int32_t average_slope_modifier, uint32_t south_facing, uint32_t bridge_score, const uint32_t underwater_area[2], uint64_t construction_height, uint8_t fire_state, uint64_t last_service_height, uint64_t service_price, uint8_t crop, uint64_t sow_height, uint8_t vegetables_nutrients, uint8_t grain_nutrients, uint32_t mortgage, uint32_t num_missed_ticks, uint8_t fishing_distance, uint32_t fishing_city, uint8_t num_fishing_ticks, uint32_t fish, const std::vector<cc::lightsource_t> &lightsources): id(id), owner(owner), city(city), role(role), x0(x0), y0(y0), x1(x1), y1(y1), repair(repair), economic_power(economic_power), base_height(base_height), elevation_bonus(elevation_bonus), average_slope(average_slope), average_slope_modifier(average_slope_modifier), south_facing(south_facing), bridge_score(bridge_score), construction_height(construction_height), fire_state(fire_state), last_service_height(last_service_height), service_price(service_price), active(false), ignore(false), dirty(0), unpackers(0), crop(crop), sow_height(sow_height), vegetables_nutrients(vegetables_nutrients), grain_nutrients(grain_nutrients), mortgage(mortgage), num_missed_ticks(num_missed_ticks), fishing_distance(fishing_distance), fishing_city(fishing_city), num_fishing_ticks(num_fishing_ticks), fish(fish), lightsources(lightsources)
@ -94,6 +110,24 @@ void Flag::resize(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, const uint
cc::get_empty_packed_tiles(packed);
}
uint8_t Flag::get_tile_smoothness(uint32_t x, uint32_t y, uint16_t h) const
{
ASSERT_UNPACKED();
if (y < y0 || y > y1 || x < x0 || x > x1)
throw std::runtime_error("Bad coordinates");
const Tile &t = tiles[(y-y0)*(x1-x0+1)+x-x0];
return t.get_smoothness(h);
}
void Flag::set_tile_smoothness(uint32_t x, uint32_t y, uint16_t h, uint8_t smoothness)
{
ASSERT_UNPACKED();
if (y < y0 || y > y1 || x < x0 || x > x1)
throw std::runtime_error("Bad coordinates");
Tile &t = tiles[(y-y0)*(x1-x0+1)+x-x0];
return t.set_smoothness(h, smoothness);
}
uint8_t Flag::get_tile_type(uint32_t x, uint32_t y, uint16_t h) const
{
ASSERT_UNPACKED();

View File

@ -28,7 +28,7 @@
class Tile
{
public:
static constexpr const size_t small_tile_threshold = 14;
static constexpr const size_t small_tile_threshold = 7;
Tile(): height(0) {}
~Tile() { if (height > small_tile_threshold) free(remote_blocks); }
@ -36,13 +36,15 @@ public:
uint16_t get_height() const { return height; }
void push(uint8_t type);
void pop();
uint8_t get_type(uint16_t h) const { return height <= small_tile_threshold ? local_blocks[h] : remote_blocks[h]; }
uint8_t get_type(uint16_t h) const { return height <= small_tile_threshold ? local_blocks[h * 2] : remote_blocks[h * 2]; }
void set_type(uint16_t h, uint8_t type);
uint8_t get_smoothness(uint16_t h) const { return height <= small_tile_threshold ? local_blocks[h * 2 + 1] : remote_blocks[h * 2 + 1]; }
void set_smoothness(uint16_t h, uint8_t s);
private:
union
{
uint8_t local_blocks[small_tile_threshold];
uint8_t local_blocks[small_tile_threshold * 2];
uint8_t *remote_blocks;
};
uint16_t height;
@ -108,6 +110,8 @@ public:
Tile &tile(uint32_t x, uint32_t y) { ASSERT_UNPACKED(); return tiles[(y - y0) * (x1 - x0 + 1) + x - x0]; }
const Tile* get_raw_tiles() const { ASSERT_UNPACKED(); return tiles; }
uint8_t get_tile_type(uint32_t x, uint32_t y, uint16_t h) const;
uint8_t get_tile_smoothness(uint32_t x, uint32_t y, uint16_t h) const;
void set_tile_smoothness(uint32_t x, uint32_t y, uint16_t h, uint8_t smoothness);
uint16_t get_tile_height(uint32_t x, uint32_t y) const;
uint16_t get_max_height() const;
std::shared_ptr<TileData> get_tiles() const;

View File

@ -2241,6 +2241,20 @@ void UIUrho3D::HandleAddBlockFlat(StringHash eventType, VariantMap& eventData)
SendEvent(E_CRYPTOCITY_ADD_BLOCK, newEventData);
}
void UIUrho3D::HandleDecreaseSmoothness(StringHash eventType, VariantMap& eventData)
{
VariantMap newEventData;
newEventData[ChangeSmoothness::P_DELTA] = -1;
SendEvent(E_CRYPTOCITY_CHANGE_SMOOTHNESS, newEventData);
}
void UIUrho3D::HandleIncreaseSmoothness(StringHash eventType, VariantMap& eventData)
{
VariantMap newEventData;
newEventData[ChangeSmoothness::P_DELTA] = 1;
SendEvent(E_CRYPTOCITY_CHANGE_SMOOTHNESS, newEventData);
}
void UIUrho3D::HandleRemoveBlock(StringHash eventType, VariantMap& eventData)
{
VariantMap newEventData;
@ -4223,6 +4237,8 @@ void UIUrho3D::HandleTBMessage(StringHash eventType, VariantMap& eventData)
CONNECT("actions-repair", HandleRepair);
CONNECT("actions-add-block", HandleAddBlock);
CONNECT("actions-add-block-flat", HandleAddBlockFlat);
CONNECT("actions-decrease-smoothness", HandleDecreaseSmoothness);
CONNECT("actions-increase-smoothness", HandleIncreaseSmoothness);
CONNECT("actions-remove-block", HandleRemoveBlock);
CONNECT("actions-remove-hidden-blocks", HandleRemoveHiddenBlocks);
CONNECT("actions-remove-placeholder-blocks", HandleRemovePlaceholderBlocks);

View File

@ -141,6 +141,7 @@ URHO3D_EVENT(E_CRYPTOCITY_RETRIEVE_ITEMS, RetrieveItems) { URHO3D_PARAM(P_FLAG,
URHO3D_EVENT(E_CRYPTOCITY_DESTROY_ITEMS, DestroyItems) { URHO3D_PARAM(P_QUANTITIES, Quantities); /* vector */ }
URHO3D_EVENT(E_CRYPTOCITY_ADD_BLOCK, AddBlock) { URHO3D_PARAM(P_FLAT, Flat); }
URHO3D_EVENT(E_CRYPTOCITY_REMOVE_BLOCK, RemoveBlock) { URHO3D_PARAM(P_TOP_LEVEL, TopLevel); }
URHO3D_EVENT(E_CRYPTOCITY_CHANGE_SMOOTHNESS, ChangeSmoothness) { URHO3D_PARAM(P_DELTA, Delta); }
URHO3D_EVENT(E_CRYPTOCITY_REMOVE_HIDDEN_BLOCKS, RemoveHiddenBlocks) {}
URHO3D_EVENT(E_CRYPTOCITY_REMOVE_PLACEHOLDER_BLOCKS, RemovePlaceholderBlocks) {}
URHO3D_EVENT(E_CRYPTOCITY_APPROVE_BUILD, ApproveBuild) {}
@ -421,6 +422,8 @@ private:
void HandleRepair(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleAddBlock(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleAddBlockFlat(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleIncreaseSmoothness(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleDecreaseSmoothness(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleRemoveBlock(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleRemoveHiddenBlocks(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);
void HandleRemovePlaceholderBlocks(Urho3D::StringHash eventType, Urho3D::VariantMap& eventData);