wood can now be chopped into firewood

This commit is contained in:
Crypto City 2020-10-15 23:42:02 +00:00
parent 8941170106
commit 29fa6c7222
24 changed files with 470 additions and 1 deletions

View File

@ -58,6 +58,7 @@ TBLayout: axis: y, distribution-position: "left top", distribution: "available"
TBButton: skin: "TBButton.column", text: "Mint", id: "actions-mint"
TBButton: skin: "TBButton.column", text: "Smelt", id: "actions-smelt"
TBButton: skin: "TBButton.column", text: "Hunt", id: "actions-hunt"
TBButton: skin: "TBButton.column", text: "Chop wood", id: "actions-chop-wood"
TBButton: skin: "TBButton.column", text: "Fight fire", id: "actions-fight-fire"
TBButton: skin: "TBButton.column", text: "Scripts", id: "actions-scripts"
TBButton: skin: "TBButton.column", text: "Ignore" id: "actions-ignore"

View File

@ -275,9 +275,18 @@
</ul>
Agricultural land produces vegetables from early summer, grain from midsummer, and meat in autumn.
<br>
When consuming food, the game uses the most perishable food type first: vegetables,
then meat, then grain.
<br>
Similarly, buildings need heating. Heating is obtained by consuming burnable material,
currently only wood. The amount of heating a building needs per surface depends on the
current temperature, which fluctuates along seasonal variations.
<br>
When burning wood, the game prefers firewood, then the cheapest wood first: pine, then
oak, then teak.
<br>
Any wood type may be chopped into firewood, for a cost of 5 labour per 100 wood. This
allows a player to override the priority in which wood types are used for heating.
</p>
<h3> Farming </h3>

View File

@ -36,6 +36,7 @@ set(cc_sources
cc_command_handler_buy_land.cpp
cc_command_handler_cancel_nonce.cpp
cc_command_handler_chat.cpp
cc_command_handler_chop_wood.cpp
cc_command_handler_create_account.cpp
cc_command_handler_create_mortgage.cpp
cc_command_handler_create_script.cpp
@ -106,6 +107,7 @@ set(cc_headers
cc_command_handler_buy_items.h
cc_command_handler_buy_land.h
cc_command_handler_chat.h
cc_command_handler_chop_wood.h
cc_command_handler_cancel_nonce.h
cc_command_handler_create_account.h
cc_command_handler_create_mortgage.h

View File

@ -45,6 +45,7 @@
#include "cc_command_handler_buy_land.h"
#include "cc_command_handler_cancel_nonce.h"
#include "cc_command_handler_chat.h"
#include "cc_command_handler_chop_wood.h"
#include "cc_command_handler_create_account.h"
#include "cc_command_handler_create_script.h"
#include "cc_command_handler_create_mortgage.h"
@ -213,6 +214,7 @@ std::string get_predefined_item_name(uint32_t idx)
switch (idx)
{
case ITEM_LABOUR: return "labour";
case ITEM_FIREWOOD: return "firewood";
case ITEM_AMETHYST: return "amethyst";
case ITEM_SAPPHIRE: return "sapphire";
case ITEM_EMERALD: return "emerald";
@ -977,6 +979,11 @@ uint32_t get_removal_labour_cost_for_height(uint16_t h)
return 1;
}
uint32_t get_labour_cost_to_chop_wood(uint32_t wood)
{
return (wood * (uint64_t)CHOP_WOOD_LABOUR_PER_100_WOOD + 99) / 100;
}
uint64_t get_shares(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint8_t role, uint32_t economic_power, uint32_t repair, uint64_t age, uint32_t influence_bonus, uint32_t elevation_bonus)
{
uint64_t shares = (x1-x0+1) * (y1-y0+1) * economic_power * influence_bonus / 100;
@ -1128,6 +1135,7 @@ bool is_item_enabled(uint32_t item, uint64_t height)
case ITEM_FOOD_SALTED_MEAT:
case ITEM_LABOUR:
case ITEM_FIREWOOD:
case ITEM_VEGETATION:
return true;
default:
@ -2132,6 +2140,7 @@ static cc_command_handler &get_cc_command_handler(const cryptonote::cc_command_t
cc_command_handler &operator()(const cryptonote::cc_command_buy_land_t &cmd) const { return cc_command_handler_buy_land::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_cancel_nonce_t &cmd) const { return cc_command_handler_cancel_nonce::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_chat_t &cmd) const { return cc_command_handler_chat::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_chop_wood_t &cmd) const { return cc_command_handler_chop_wood::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_create_account_t &cmd) const { return cc_command_handler_create_account::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_create_script_t &cmd) const { return cc_command_handler_create_script::instance; }
cc_command_handler &operator()(const cryptonote::cc_command_create_mortgage_t &cmd) const { return cc_command_handler_create_mortgage::instance; }

View File

@ -70,6 +70,7 @@ uint32_t get_build_labour_cost_for_height(uint16_t h, uint32_t bonus = 0);
uint32_t get_build_labour_cost_for_height(const cryptonote::BlockchainDB &db, uint32_t account, uint16_t h);
uint32_t get_average_build_labour_cost_for_height(uint32_t height, uint32_t num_blocks);
uint32_t get_removal_labour_cost_for_height(uint16_t h);
uint32_t get_labour_cost_to_chop_wood(uint32_t wood);
uint64_t get_shares(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint8_t role, uint32_t economic_power, uint32_t repair, uint64_t age, uint32_t influence_bonus, uint32_t elevation_bonus);
uint64_t get_game_subsidy(const cryptonote::BlockchainDB &db, uint64_t block_height);
uint64_t get_game_subsidy_for_next_block(const cryptonote::BlockchainDB &db);

View File

@ -0,0 +1,157 @@
// Copyright (c) 2019, Crypto City
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "blockchain_db/blockchain_db.h"
#include "cc/cc.h"
#include "cc_command_handler_helpers.h"
#include "cc_command_handler_chop_wood.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "verify"
namespace cc
{
cc_command_handler_chop_wood cc_command_handler_chop_wood::instance;
void cc_command_handler_chop_wood::get_in_out(const cryptonote::cc_command_t &cmd, uint64_t &cc_in, uint64_t &cc_out) const
{
cc_in = 0;
cc_out = 0;
}
uint64_t cc_command_handler_chop_wood::get_cost(const cryptonote::cc_command_t &cmd) const
{
return 0;
}
bool cc_command_handler_chop_wood::check_changed_accounts(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, std::set<uint32_t> &accounts) const
{
const cryptonote::cc_command_chop_wood_t &chop_wood = boost::get<cryptonote::cc_command_chop_wood_t>(cmd);
const auto res = accounts.insert(chop_wood.cc_account);
return res.second;
}
bool cc_command_handler_chop_wood::check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, cryptonote::tx_verification_context &tvc) const
{
const cryptonote::cc_command_chop_wood_t &chop_wood = boost::get<cryptonote::cc_command_chop_wood_t>(cmd);
CHECK_COMMAND_SET(db.does_cc_account_exist(chop_wood.cc_account), tvc.m_cc_invalid_account, "chop_wood command refers to non existent owner " << chop_wood.cc_account);
CHECK_AND_ASSERT_MES(!chop_wood.items.empty(), false, "chop_wood has empty item list");
std::map<uint32_t, uint32_t> item_balances;
CHECK_AND_ASSERT_MES(db.get_cc_account_item_balances(chop_wood.cc_account, item_balances), false, "Failed to get owner item balances");
const uint64_t blockchain_height = db.height();
for (const auto &e: chop_wood.items)
{
CHECK_COMMAND_SET(e.type >= ITEM_FIRST_WOOD && e.type <= ITEM_LAST_WOOD, tvc.m_cc_bad_item, "chop_wood refers to invalid or non wood item type");
CHECK_COMMAND_SET(cc::is_item_enabled(e.type, blockchain_height), tvc.m_cc_bad_item, "chop_wood refers to disabled item type");
CHECK_COMMAND_SET(e.amount > 0, tvc.m_cc_bad_amount, "chop_wood refers to 0 amount");
CHECK_COMMAND_SET(item_balances[e.type] >= e.amount, tvc.m_cc_balance, "Assigning more items of type " << (unsigned)e.type << " than owned");
CHECK_COMMAND_SET(item_balances[ITEM_FIRST_WOOD] <= std::numeric_limits<uint32_t>::max() - e.amount, tvc.m_cc_overflow, "Firewood balance would overflow");
}
std::set<uint32_t> present;
uint32_t n_wood = 0;
for (const auto &e: chop_wood.items)
{
CHECK_COMMAND_SET(e.type > 0 && e.type < NUM_ITEMS, tvc.m_cc_bad_item, "Item type out of range");
CHECK_COMMAND_SET(present.find(e.type) == present.end(), tvc.m_cc_bad_item, "chop_wood refers to the same item more than once");
present.insert(e.type);
n_wood += e.amount;
}
const uint32_t labour = cc::get_labour_cost_to_chop_wood(n_wood);
CHECK_COMMAND_SET(item_balances[ITEM_LABOUR] >= labour, tvc.m_cc_balance, "Not enough labour to chop wood");
return true;
}
bool cc_command_handler_chop_wood::execute(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, game_events_t &events) const
{
const cryptonote::cc_command_chop_wood_t &chop_wood = boost::get<cryptonote::cc_command_chop_wood_t>(cmd);
std::map<uint32_t, uint32_t> item_balances;
CHECK_AND_ASSERT_MES(db.get_cc_account_item_balances(chop_wood.cc_account, item_balances), false, "Failed to get owner item balances");
uint32_t n_wood = 0;
for (const auto &e: chop_wood.items)
{
CHECK_AND_ASSERT_MES(item_balances[e.type] >= e.amount, false, "Not enough balance for item " << (unsigned)e.type);
item_balances[e.type] -= e.amount;
CHECK_AND_ASSERT_MES(decrease_item_count(db, e.type, e.amount), false, "Item count anomaly");
CHECK_AND_ASSERT_MES(item_balances[ITEM_FIREWOOD] <= std::numeric_limits<uint32_t>::max() - e.amount, false, "Firewood balance overflow");
item_balances[ITEM_FIREWOOD] += e.amount;
CHECK_AND_ASSERT_MES(increase_item_count(db, ITEM_FIREWOOD, e.amount), false, "Item count anomaly");
n_wood += e.amount;
events.add_full(cmd, chop_wood.cc_account, 0, e.type, e.amount, 0) << "Chops " << e.amount << " " << cc::get_item_name(db, e.type) << " into firewood";
}
const uint32_t labour = cc::get_labour_cost_to_chop_wood(n_wood);
CHECK_AND_ASSERT_MES(item_balances[ITEM_LABOUR] >= labour, false, "Not enough labour to chop wood");
item_balances[ITEM_LABOUR] -= labour;
CHECK_AND_ASSERT_MES(decrease_item_count(db, ITEM_LABOUR, labour), false, "Item count anomaly");
db.set_cc_account_item_balances(chop_wood.cc_account, item_balances);
return true;
}
bool cc_command_handler_chop_wood::revert(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd) const
{
const cryptonote::cc_command_chop_wood_t &chop_wood = boost::get<cryptonote::cc_command_chop_wood_t>(cmd);
std::map<uint32_t, uint32_t> item_balances;
CHECK_AND_ASSERT_MES(db.get_cc_account_item_balances(chop_wood.cc_account, item_balances), false, "Failed to get owner item balances");
uint32_t n_wood = 0;
for (const auto &e: chop_wood.items)
{
CHECK_AND_ASSERT_MES(item_balances[e.type] <= std::numeric_limits<uint32_t>::max() - e.amount, false, "Item " << (unsigned)e.type << " balance would overflow");
item_balances[e.type] += e.amount;
CHECK_AND_ASSERT_MES(increase_item_count(db, e.type, e.amount), false, "Item count anomaly");
CHECK_AND_ASSERT_MES(item_balances[ITEM_FIREWOOD] >= e.amount, false, "Not enough firewood");
item_balances[ITEM_FIREWOOD] -= e.amount;
CHECK_AND_ASSERT_MES(decrease_item_count(db, ITEM_FIREWOOD, e.amount), false, "Item count anomaly");
n_wood += e.amount;
}
const uint32_t labour = cc::get_labour_cost_to_chop_wood(n_wood);
CHECK_AND_ASSERT_MES(labour <= std::numeric_limits<uint32_t>::max() - item_balances[ITEM_LABOUR], false, "Labour overflow");
item_balances[ITEM_LABOUR] += labour;
CHECK_AND_ASSERT_MES(increase_item_count(db, ITEM_LABOUR, labour), false, "Item count anomaly");
db.set_cc_account_item_balances(chop_wood.cc_account, item_balances);
return true;
}
}

View File

@ -0,0 +1,49 @@
// Copyright (c) 2019, Crypto City
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include "cc_command_handler.h"
namespace cc
{
class cc_command_handler_chop_wood: public cc_command_handler
{
public:
virtual void get_in_out(const cryptonote::cc_command_t &cmd, uint64_t &cc_in, uint64_t &cc_out) const;
virtual uint64_t get_cost(const cryptonote::cc_command_t &cmd) const;
virtual bool check_changed_accounts(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, std::set<uint32_t> &accounts) const;
virtual bool check(const cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, cryptonote::tx_verification_context &tvc) const;
virtual bool execute(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd, game_events_t &events) const;
virtual bool revert(cryptonote::BlockchainDB &db, const cryptonote::cc_command_t &cmd) const;
static cc_command_handler_chop_wood instance;
};
}

View File

@ -151,6 +151,7 @@
#define STONECUTTER_CLIFF_BONUS_POTENTIAL_LOOPS 3
#define NONCE_CANCELLATION_FEE 10000000
#define NUM_CUSTOM_ITEM_USER_DATA 4
#define CHOP_WOOD_LABOUR_PER_100_WOOD 5
#define NAME_TYPE_PLAYER 1
#define NAME_TYPE_CUSTOM_ITEM 2
@ -240,6 +241,7 @@ enum Item
ITEM_LAST_BLOCK = 255,
ITEM_LABOUR,
ITEM_FIREWOOD,
ITEM_FIRST_GEMSTONE,
ITEM_AMETHYST = ITEM_FIRST_GEMSTONE,

View File

@ -671,6 +671,7 @@ static void add_cities(const BlockchainDB &db, cc_command_game_update_t &cg, gam
if (heating_needs > 0)
{
static const uint32_t heating_priority[] = {
ITEM_FIREWOOD,
ITEM_BASIC_WOOD,
ITEM_MEDIUM_WOOD,
ITEM_HIGH_WOOD,

View File

@ -82,6 +82,8 @@ uint32_t get_heating_needs_average(uint32_t x0, uint32_t y0, uint32_t x1, uint32
uint32_t get_heating_points(uint32_t item)
{
if (item == ITEM_FIREWOOD)
return 5;
if (item >= ITEM_FIRST_WOOD && item <= ITEM_LAST_WOOD)
return 5;
return 0;

View File

@ -60,6 +60,7 @@ const cc_command_basenonce_t *get_cc_command_basenonce(const cc_command_t &cmd)
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_buy_land_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_cancel_nonce_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_chat_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_chop_wood_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_create_account_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_create_script_t &cmd) const { return &cmd; }
const cc_command_basenonce_t *operator()(const cryptonote::cc_command_create_mortgage_t &cmd) const { return &cmd; }
@ -113,6 +114,7 @@ cc_command_basenonce_t *get_cc_command_basenonce(cc_command_t &cmd)
cc_command_basenonce_t *operator()(cryptonote::cc_command_buy_land_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_cancel_nonce_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_chat_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_chop_wood_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_create_account_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_create_script_t &cmd) const { return &cmd; }
cc_command_basenonce_t *operator()(cryptonote::cc_command_create_mortgage_t &cmd) const { return &cmd; }
@ -166,6 +168,7 @@ const cc_command_base_t *get_cc_command_base(const cc_command_t &cmd)
const cc_command_base_t *operator()(const cryptonote::cc_command_buy_land_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_cancel_nonce_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_chat_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_chop_wood_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_create_account_t &cmd) const { return NULL; }
const cc_command_base_t *operator()(const cryptonote::cc_command_create_script_t &cmd) const { return &cmd; }
const cc_command_base_t *operator()(const cryptonote::cc_command_create_mortgage_t &cmd) const { return &cmd; }
@ -219,6 +222,7 @@ cc_command_base_t *get_cc_command_base(cc_command_t &cmd)
cc_command_base_t *operator()(cryptonote::cc_command_buy_land_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_cancel_nonce_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_chat_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_chop_wood_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_create_account_t &cmd) const { return NULL; }
cc_command_base_t *operator()(cryptonote::cc_command_create_script_t &cmd) const { return &cmd; }
cc_command_base_t *operator()(cryptonote::cc_command_create_mortgage_t &cmd) const { return &cmd; }

View File

@ -943,6 +943,27 @@ namespace cryptonote
END_SERIALIZE()
};
struct cc_command_chop_wood_t: public cc_command_base_t
{
struct item_t
{
uint32_t type;
uint32_t amount;
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(type)
VARINT_FIELD(amount)
END_SERIALIZE()
};
std::vector<item_t> items;
BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<cc_command_base_t*>(this))
FIELD(items)
END_SERIALIZE()
};
struct cc_command_game_update_t: public cc_command_basenonce_t
{
struct flag_t
@ -1211,7 +1232,8 @@ namespace cryptonote
cc_command_start_script_t,
cc_command_script_choice_t,
cc_command_set_script_variable_t,
cc_command_create_mortgage_t
cc_command_create_mortgage_t,
cc_command_chop_wood_t
> cc_command_t;
cc_command_basenonce_t *get_cc_command_basenonce(cc_command_t &cmd);
@ -1364,6 +1386,7 @@ CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_start_script_t, (uint8_t)0
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_script_choice_t, (uint8_t)0x2a);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_set_script_variable_t, (uint8_t)0x2b);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_create_mortgage_t, (uint8_t)0x2c);
CC_VARIANT_TAG(binary_archive, cryptonote::cc_command_chop_wood_t, (uint8_t)0x2d);
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_none_t, (const char*)"none");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_create_account_t, (const char*)"create_account");
@ -1410,6 +1433,7 @@ CC_VARIANT_TAG(json_archive, cryptonote::cc_command_start_script_t, (const char*
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_script_choice_t, (const char*)"script_choice");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_set_script_variable_t, (const char*)"set_script_variable");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_create_mortgage_t, (const char*)"create_mortgage");
CC_VARIANT_TAG(json_archive, cryptonote::cc_command_chop_wood_t, (const char*)"chop_wood");
VARIANT_TAG(debug_archive, cryptonote::cc_command_none_t, "none");
VARIANT_TAG(debug_archive, cryptonote::cc_command_create_account_t, "create_account");
@ -1456,3 +1480,4 @@ VARIANT_TAG(debug_archive, cryptonote::cc_command_start_script_t, "start_script"
VARIANT_TAG(debug_archive, cryptonote::cc_command_script_choice_t, "script_choice");
VARIANT_TAG(debug_archive, cryptonote::cc_command_set_script_variable_t, "set_script_variable");
VARIANT_TAG(debug_archive, cryptonote::cc_command_create_mortgage_t, "create_mortgage");
VARIANT_TAG(debug_archive, cryptonote::cc_command_chop_wood_t, "chop_wood");

View File

@ -408,6 +408,11 @@ bool GameState::process_chat(const cryptonote::cc_command_chat_t &cmd, const std
return true;
}
bool GameState::process_chop_wood(const cryptonote::cc_command_chop_wood_t &cmd, const std::shared_ptr<GameWallet> &w)
{
return true;
}
bool GameState::process_define_attribute(const cryptonote::cc_command_define_attribute_t &cmd, const std::shared_ptr<GameWallet> &w)
{
return true;
@ -741,6 +746,7 @@ bool GameState::process_command(const cryptonote::cc_command_t &cmd, const std::
bool operator()(const cryptonote::cc_command_buy_land_t &cmd) const { return self.process_buy_land(cmd, w); }
bool operator()(const cryptonote::cc_command_cancel_nonce_t &cmd) const { return self.process_cancel_nonce(cmd, w); }
bool operator()(const cryptonote::cc_command_chat_t &cmd) const { return self.process_chat(cmd, w); }
bool operator()(const cryptonote::cc_command_chop_wood_t &cmd) const { return self.process_chop_wood(cmd, w); }
bool operator()(const cryptonote::cc_command_create_account_t &cmd) const { return self.process_create_account(cmd, w); }
bool operator()(const cryptonote::cc_command_create_script_t &cmd) const { return self.process_create_script(cmd, w); }
bool operator()(const cryptonote::cc_command_create_mortgage_t &cmd) const { return self.process_create_mortgage(cmd, w); }

View File

@ -163,6 +163,7 @@ private:
bool process_buy_land(const cryptonote::cc_command_buy_land_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_cancel_nonce(const cryptonote::cc_command_cancel_nonce_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_chat(const cryptonote::cc_command_chat_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_chop_wood(const cryptonote::cc_command_chop_wood_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_create_account(const cryptonote::cc_command_create_account_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_create_script(const cryptonote::cc_command_create_script_t &cmd, const std::shared_ptr<GameWallet> &w);
bool process_create_mortgage(const cryptonote::cc_command_create_mortgage_t &cmd, const std::shared_ptr<GameWallet> &w);

View File

@ -86,6 +86,7 @@ std::string get_command_string(const GameState *game, const cryptonote::cc_comma
std::string operator()(const cryptonote::cc_command_buy_land_t &cmd) const { return "Land purchase (" + std::to_string(cmd.wm1+1) + " x " + std::to_string(cmd.hm1+1) + ")"; }
std::string operator()(const cryptonote::cc_command_cancel_nonce_t &cmd) const { return "Cancelling command"; }
std::string operator()(const cryptonote::cc_command_chat_t &cmd) const { return ""; } // do not show
std::string operator()(const cryptonote::cc_command_chop_wood_t &cmd) const { return "Chopping wood into firewood"; }
std::string operator()(const cryptonote::cc_command_create_account_t &cmd) const { return "Account creation"; }
std::string operator()(const cryptonote::cc_command_create_script_t &cmd) const { return "'" + cc::script::get_script_name(cmd.blob) + "' script creation"; }
std::string operator()(const cryptonote::cc_command_create_mortgage_t &cmd) const { return "Mortgaging " + game_util::get_building_name(game, cmd.flag); }

View File

@ -305,6 +305,7 @@ public:
void HandleScriptChoice(StringHash eventType, VariantMap& eventData);
void HandleSetGlobalVariable(StringHash eventType, VariantMap& eventData);
void HandleGetGlobalVariable(StringHash eventType, VariantMap& eventData);
void HandleChopWood(StringHash eventType, VariantMap& eventData);
void HandleLoadingWallet(StringHash eventType, VariantMap& eventData);
void HandleNewWallet(StringHash eventType, VariantMap& eventData);
@ -1074,6 +1075,7 @@ void CryptoCityUrho3D::SetupUI()
SubscribeToEvent(ui, E_CRYPTOCITY_SCRIPT_CHOICE, URHO3D_HANDLER(CryptoCityUrho3D, HandleScriptChoice));
SubscribeToEvent(ui, E_CRYPTOCITY_SET_GLOBAL_VARIABLE, URHO3D_HANDLER(CryptoCityUrho3D, HandleSetGlobalVariable));
SubscribeToEvent(ui, E_CRYPTOCITY_GET_GLOBAL_VARIABLE, URHO3D_HANDLER(CryptoCityUrho3D, HandleGetGlobalVariable));
SubscribeToEvent(ui, E_CRYPTOCITY_CHOP_WOOD, URHO3D_HANDLER(CryptoCityUrho3D, HandleChopWood));
SubscribeToEvent(&gameState, E_CRYPTOCITY_REQUEST_PLAYER_DATA, URHO3D_HANDLER(CryptoCityUrho3D, HandleRequestPlayerData));
SubscribeToEvent(&gameState, E_CRYPTOCITY_REQUEST_ITEM_DATA, URHO3D_HANDLER(CryptoCityUrho3D, HandleRequestItemData));
SubscribeToEvent(&gameState, E_CRYPTOCITY_REQUEST_BADGE_DATA, URHO3D_HANDLER(CryptoCityUrho3D, HandleRequestBadgeData));
@ -2839,6 +2841,26 @@ void CryptoCityUrho3D::HandleAssignItems(StringHash eventType, VariantMap& event
SendCommand(cmd);
}
void CryptoCityUrho3D::HandleChopWood(StringHash eventType, VariantMap& eventData)
{
if (!wallet || !wallet->wallet())
{
new MessageBox(context_, "No wallet loaded - load a wallet to be able to chop wood");
return;
}
cryptonote::cc_command_chop_wood_t cmd;
cmd.cc_account = wallet->get_cc_account();
const std::vector<std::pair<uint32_t, uint32_t>> *v = (const std::vector<std::pair<uint32_t, uint32_t>>*)eventData[ChopWood::P_QUANTITIES].GetVoidPtr();
for (const auto &q: *v)
{
cryptonote::cc_command_chop_wood_t::item_t e;
e.type = q.first;
e.amount = q.second;
cmd.items.push_back(e);
}
SendCommand(cmd);
}
void CryptoCityUrho3D::HandleDestroyItems(StringHash eventType, VariantMap& eventData)
{
if (!wallet || !wallet->wallet())

View File

@ -807,6 +807,7 @@ void UIUrho3D::Update(float timeStep, uint32_t mouse_x, uint32_t mouse_y, uint32
EnableWidget("actions-assign-items", hasAccount && hasFlagSelected);
EnableWidget("actions-destroy-items", hasAccount);
EnableWidget("actions-hunt", hasAccount);
EnableWidget("actions-chop-wood", hasAccount);
EnableWidget("actions-fight-fire", hasAccount && gameState->cityState.special_event == cc::SPECIAL_EVENT_FIRE);
EnableWidget("actions-approve-build", hasFlagSelected && building);
@ -2292,6 +2293,14 @@ void UIUrho3D::HandleHunt(StringHash eventType, VariantMap& eventData)
});
}
void UIUrho3D::HandleChopWood(StringHash eventType, VariantMap& eventData)
{
auto *d = new UISelectItemsDialog(context_, gameState, "Select items to chop into firewood", [](uint32_t item) { return item >= ITEM_FIRST_WOOD && item <= ITEM_LAST_WOOD; });
SubscribeToEvent(d, E_SELECT_ITEMS_OKAYED, [this](StringHash eventType, VariantMap& eventData) {
SendEvent(E_CRYPTOCITY_CHOP_WOOD, eventData);
});
}
void UIUrho3D::HandleFightFire(StringHash eventType, VariantMap& eventData)
{
if (fightFireDialog)
@ -2501,6 +2510,7 @@ void UIUrho3D::HandleTBMessage(StringHash eventType, VariantMap& eventData)
CONNECT("actions-new-item", HandleNewItem);
CONNECT("actions-dividend", HandleDividend);
CONNECT("actions-hunt", HandleHunt);
CONNECT("actions-chop-wood", HandleChopWood);
CONNECT("actions-fight-fire", HandleFightFire);
CONNECT("actions-resize-flag", HandleResizeFlag);
CONNECT("actions-flag-palette", HandlePalette);

View File

@ -190,6 +190,7 @@ URHO3D_EVENT(E_CRYPTOCITY_SET_MAX_ACTIVE_FPS, SetMaxActiveFPS) { URHO3D_PARAM(P_
URHO3D_EVENT(E_CRYPTOCITY_SET_MAX_INACTIVE_FPS, SetMaxInactiveFPS) { URHO3D_PARAM(P_FPS, FPS); }
URHO3D_EVENT(E_CRYPTOCITY_SET_FONT_SIZE, SetFontSize) { URHO3D_PARAM(P_SIZE, Size); }
URHO3D_EVENT(E_CRYPTOCITY_NEW_MORTGAGE, NewMortgage) { URHO3D_PARAM(P_NAME, Name); URHO3D_PARAM(P_DESCRIPTION, Description); URHO3D_PARAM(P_ITEM, Item); URHO3D_PARAM(P_TICK_PAYMENT, TickPayment); URHO3D_PARAM(P_MATURITY_PAYMENT, MaturityPayment); URHO3D_PARAM(P_NUM_TICKS_DELAY, NumTicksDelay); URHO3D_PARAM(P_NUM_TICK_PAYMENTS, NumTickPayments); URHO3D_PARAM(P_SHARES, Shares); }
URHO3D_EVENT(E_CRYPTOCITY_CHOP_WOOD, ChopWood) { URHO3D_PARAM(P_QUANTITIES, Quantities); /* vector */ }
class UIUrho3D: public Urho3D::UIElement
{

View File

@ -6244,6 +6244,46 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_cc_chop_wood(const wallet_rpc::COMMAND_RPC_CC_CHOP_WOOD::request& req, wallet_rpc::COMMAND_RPC_CC_CHOP_WOOD::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
LOG_PRINT_L3("on_cc_chop_wood starts");
if (!m_wallet) return not_open(er);
if (m_restricted)
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
try
{
cryptonote::cc_command_chop_wood_t cmd;
cmd.cc_account = m_wallet->get_cc_account();
for (const auto &e: req.items)
cmd.items.push_back({e.type, e.amount});
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_cc_transactions(cmd, priority);
if (ptx_vector.empty())
{
er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE;
er.message = "No transaction created";
return false;
}
std::string dummy_tx_key;
uint64_t dummy_amount;
return fill_response(ptx_vector, false, dummy_tx_key, dummy_amount, res.fee, res.weight, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
}
catch (const std::exception& e)
{
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR);
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
}
class t_daemon

View File

@ -201,6 +201,7 @@ namespace tools
MAP_JON_RPC_WE("cc_script_choice", on_cc_script_choice, wallet_rpc::COMMAND_RPC_CC_SCRIPT_CHOICE)
MAP_JON_RPC_WE("cc_set_script_variable", on_cc_set_script_variable, wallet_rpc::COMMAND_RPC_CC_SET_SCRIPT_VARIABLE)
MAP_JON_RPC_WE("cc_create_mortgage", on_cc_create_mortgage, wallet_rpc::COMMAND_RPC_CC_CREATE_MORTGAGE)
MAP_JON_RPC_WE("cc_chop_wood", on_cc_chop_wood, wallet_rpc::COMMAND_RPC_CC_CHOP_WOOD)
END_JSON_RPC_MAP()
END_URI_MAP2()
@ -332,6 +333,7 @@ namespace tools
bool on_cc_script_choice(const wallet_rpc::COMMAND_RPC_CC_SCRIPT_CHOICE::request& req, wallet_rpc::COMMAND_RPC_CC_SCRIPT_CHOICE::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_cc_set_script_variable(const wallet_rpc::COMMAND_RPC_CC_SET_SCRIPT_VARIABLE::request& req, wallet_rpc::COMMAND_RPC_CC_SET_SCRIPT_VARIABLE::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_cc_create_mortgage(const wallet_rpc::COMMAND_RPC_CC_CREATE_MORTGAGE::request& req, wallet_rpc::COMMAND_RPC_CC_CREATE_MORTGAGE::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_cc_chop_wood(const wallet_rpc::COMMAND_RPC_CC_CHOP_WOOD::request& req, wallet_rpc::COMMAND_RPC_CC_CHOP_WOOD::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
//json rpc v2
bool on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);

View File

@ -5032,5 +5032,59 @@ namespace wallet_rpc
typedef epee::misc_utils::struct_init<response_t> response;
};
struct COMMAND_RPC_CC_CHOP_WOOD
{
struct item_t
{
uint32_t type;
uint32_t amount;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(type)
KV_SERIALIZE(amount)
END_KV_SERIALIZE_MAP()
};
struct request_t
{
std::vector<item_t> items;
uint32_t priority;
bool do_not_relay;
bool get_tx_hex;
bool get_tx_metadata;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(items)
KV_SERIALIZE(priority)
KV_SERIALIZE_OPT(do_not_relay, false)
KV_SERIALIZE_OPT(get_tx_hex, false)
KV_SERIALIZE_OPT(get_tx_metadata, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct response_t
{
std::string tx_hash;
uint64_t fee;
uint64_t weight;
std::string tx_blob;
std::string tx_metadata;
std::string multisig_txset;
std::string unsigned_txset;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(fee)
KV_SERIALIZE(weight)
KV_SERIALIZE(tx_blob)
KV_SERIALIZE(tx_metadata)
KV_SERIALIZE(multisig_txset)
KV_SERIALIZE(unsigned_txset)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
}
}

View File

@ -49,6 +49,7 @@ ITEM_WOOD = 4
MATERIAL_VARIANT_PLOUGHED_FIELD = 32
MATERIAL_LOCKED_PINE = 26
ITEM_LABOUR = 256
ITEM_FIREWOOD = 257
ITEM_FIRST_PATENT = 1024
ITEM_FIRST_FOOD = ITEM_FIRST_PATENT + 4096
ITEM_FOOD_VEGETABLES = ITEM_FIRST_FOOD
@ -105,6 +106,7 @@ collectible_coin_type_city = 2
collectible_coin_type_yearly = 3
collectible_coin_type_event = 4
NUM_CUSTOM_ITEM_USER_DATA = 4
CHOP_WOOD_LABOUR_PER_100_WOOD = 5
def assert_exception(f):
ok = False
@ -172,6 +174,7 @@ class CCTest():
self.test_cc_transfers()
self.test_buy_land()
self.test_buy_items()
self.test_firewood()
self.test_build()
self.test_trading()
self.test_interacting_trades()
@ -658,6 +661,51 @@ class CCTest():
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
assert res.counts == item_counts
def test_firewood(self):
daemon = self.daemon
print("Testing firewood")
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_WOOD, 'amount': 40}])
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': (CHOP_WOOD_LABOUR_PER_100_WOOD * 40 + 99) / 100}])
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
assert_exception(lambda self: self.wallet[2].cc_chop_wood([{'type': ITEM_STONE, 'amount': 1}]))
assert_exception(lambda self: self.wallet[2].cc_chop_wood([{'type': ITEM_LABOUR, 'amount': 1}]))
assert_exception(lambda self: self.wallet[2].cc_chop_wood([{'type': ITEM_WOOD, 'amount': 100000000}]))
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
item_counts = res.counts
res = self.wallet[2].refresh()
res = self.wallet[2].cc_get_info()
cc_balance = res.cc_balance
account_id = res.account_id
res = daemon.cc_get_account(account_id)
assert len(res.item_balances) > 0
item_balances = []
if 'item_balances' in res:
for e in res.item_balances:
item_balances = self.add_item(item_balances, e.type, e.amount)
res = self.wallet[2].cc_chop_wood([{'type': ITEM_WOOD, 'amount': 40}])
item_balances = self.add_item(item_balances, ITEM_WOOD, -40)
item_counts[ITEM_WOOD] -= 40
item_balances = self.add_item(item_balances, ITEM_FIREWOOD, 40)
item_counts[ITEM_FIREWOOD] += 40
item_balances = self.add_item(item_balances, ITEM_LABOUR, -((40 * CHOP_WOOD_LABOUR_PER_100_WOOD + 99) // 100))
item_counts[ITEM_LABOUR] -= (40 * CHOP_WOOD_LABOUR_PER_100_WOOD + 99) // 100
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = daemon.cc_get_account(account_id)
assert res.item_balances == item_balances
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
assert res.counts == item_counts
def test_build(self):
daemon = self.daemon

View File

@ -2752,6 +2752,8 @@ TEST(cc, type_tags)
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x2b);
cmd = cryptonote::cc_command_create_mortgage_t();
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x2c);
cmd = cryptonote::cc_command_chop_wood_t();
ASSERT_EQ(get_cc_tag<uint8_t>(cmd), 0x2d);
}
TEST(cc, staff)
@ -3687,3 +3689,8 @@ TEST(cc, mortgage)
for (int t = 0; t < 4; ++t)
check_mortgage_progression(8 * GAME_UPDATE_FREQUENCY + dch, d, t);
}
TEST(cc, firewood_labour_starts_at_1)
{
ASSERT_GT(cc::get_labour_cost_to_chop_wood(1), 0);
}

View File

@ -1866,3 +1866,18 @@ class Wallet(object):
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_create_mortgage)
def cc_chop_wood(self, items, priority = 0, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
cc_chop_wood = {
'method': 'cc_chop_wood',
'params': {
'items': items,
'priority': priority,
'do_not_relay': do_not_relay,
'get_tx_hex': get_tx_hex,
'get_tx_metadata': get_tx_metadata,
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(cc_chop_wood)