forked from townforge/townforge
storyline event and log can now take a format string
This commit is contained in:
parent
a1eebef592
commit
981a6098e8
@ -241,7 +241,10 @@ static void print_action_string(const Action &a, std::string &source, const std:
|
||||
break;
|
||||
case action_storyline_event:
|
||||
CHECK_AND_ASSERT_THROW_MES(!a.str.empty(), "Expected a string for action_storyline_event");
|
||||
source += I + "storyline event \"" + escape(a.str) + "\"\n";
|
||||
source += I + "storyline event \"" + escape(a.str) + "\"";
|
||||
for (const auto &op: a.ops)
|
||||
source += " " + get_operand_string(op, op_unsigned);
|
||||
source += "\n";
|
||||
break;
|
||||
case action_if:
|
||||
{
|
||||
@ -284,10 +287,9 @@ static void print_action_string(const Action &a, std::string &source, const std:
|
||||
source += I + "start script " + get_operand_string(a.ops[0], op_unsigned) + "\n";
|
||||
break;
|
||||
case action_log:
|
||||
CHECK_AND_ASSERT_THROW_MES(a.ops.size() <= 1, "Expected one operand at most for action_log, got " << a.ops.size());
|
||||
source += I + "log \"" + escape(a.str) + "\"";
|
||||
if (a.ops.size() == 1)
|
||||
source += " " + get_operand_string(a.ops[0], op_unsigned);
|
||||
for (const auto &op: a.ops)
|
||||
source += " " + get_operand_string(op, op_unsigned);
|
||||
source += "\n";
|
||||
break;
|
||||
}
|
||||
@ -1257,6 +1259,47 @@ static uint32_t get_random_number(const crypto::hash &seed, uint64_t &salt)
|
||||
return (SWAP32LE((uint32_t&)hash.data));
|
||||
}
|
||||
|
||||
static std::string process_format_string(BlockchainStateProxy &proxy, uint32_t account, uint32_t owner, uint32_t city, const crypto::hash &seed, uint64_t &salt, const std::string &src, const std::vector<Operand> &ops)
|
||||
{
|
||||
size_t opidx = 0;
|
||||
std::string str;
|
||||
str.reserve(src.size() * 2 + 64);
|
||||
for (size_t i = 0; i < src.size(); ++i)
|
||||
{
|
||||
if (src[i] != '%' || !strchr("uGT", src[i + 1]))
|
||||
{
|
||||
str.push_back(src[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (opidx >= ops.size())
|
||||
printf("Format string '%s' does not have enough operands\n", src.c_str());
|
||||
|
||||
const auto value_signed = opidx >= ops.size() || ops[opidx].type == op_none ? std::make_pair<uint64_t, bool>(0, false) : get_attribute(proxy, ops[opidx], account, owner, city, seed, salt);
|
||||
const uint64_t value = value_signed.first;
|
||||
|
||||
switch (src[i + 1])
|
||||
{
|
||||
case 'u':
|
||||
str += std::to_string(value);
|
||||
break;
|
||||
case 'G':
|
||||
str += cryptonote::print_money(value);
|
||||
break;
|
||||
case 'T':
|
||||
str += cc::print_temperature(value);
|
||||
break;
|
||||
default:
|
||||
printf("This should not be reached\n");
|
||||
break;
|
||||
}
|
||||
|
||||
++i;
|
||||
++opidx;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static bool execute(cryptonote::cc_command_t cmd, BlockchainStateProxy &proxy, game_events_t &events, const Script &script, uint32_t account, uint32_t owner, uint32_t city, const Action &action, const crypto::hash &seed, uint64_t &salt)
|
||||
{
|
||||
if (action.type == action_none)
|
||||
@ -1398,7 +1441,7 @@ static bool execute(cryptonote::cc_command_t cmd, BlockchainStateProxy &proxy, g
|
||||
proxy.set_local_variable(account, action.str, value);
|
||||
break;
|
||||
case action_storyline_event:
|
||||
events.add(cmd, account) << "Storyline event: " << action.str;
|
||||
events.add(cmd, account) << "Storyline event: " << process_format_string(proxy, account, owner, city, seed, salt, action.str, action.ops);
|
||||
break;
|
||||
case action_if:
|
||||
{
|
||||
@ -1417,7 +1460,7 @@ static bool execute(cryptonote::cc_command_t cmd, BlockchainStateProxy &proxy, g
|
||||
proxy.start_background_script(value);
|
||||
break;
|
||||
case action_log:
|
||||
MINFO("Script log: " << action.str << (action.ops.empty() ? std::string() : std::to_string(value)));
|
||||
MINFO("Script log: " << process_format_string(proxy, account, owner, city, seed, salt, action.str, action.ops));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
|
@ -435,6 +435,8 @@ void set_partial_state_action_set_weight(script_partial_state_t *state);
|
||||
void set_partial_state_action_pick(script_partial_state_t *state);
|
||||
void set_partial_state_action_if(script_partial_state_t *state);
|
||||
void set_partial_state_action_else(script_partial_state_t *state);
|
||||
void set_partial_state_action_storyline_event(script_partial_state_t *state, const char *s);
|
||||
void set_partial_state_action_log(script_partial_state_t *state, const char *s);
|
||||
void set_partial_state_action_percent(script_partial_state_t *state);
|
||||
void set_partial_state_state_init_actions(script_partial_state_t *state);
|
||||
void set_partial_state_state_text(script_partial_state_t *state, const char *str);
|
||||
|
@ -497,6 +497,57 @@ void set_partial_state_action_else(script_partial_state_t *state)
|
||||
state->expressions.pop_back();
|
||||
}
|
||||
|
||||
static size_t get_format_string_expected_operands(const char *s)
|
||||
{
|
||||
size_t found = 0;
|
||||
for (const char *ptr = s; *ptr; ++ptr)
|
||||
{
|
||||
if (*ptr == '%' && strchr("uGT", ptr[1]))
|
||||
++found;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void set_partial_state_action_storyline_event(script_partial_state_t *state, const char *str)
|
||||
{
|
||||
MDEBUG("soryline_event");
|
||||
|
||||
const size_t expect = get_format_string_expected_operands(str);
|
||||
if (expect != state->operands.size())
|
||||
{
|
||||
tfscript_error("Storyline event action format string expects " + std::to_string(expect) + " operands but has " + std::to_string(state->operands.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
WeightedAction a;
|
||||
a.action.type = action_storyline_event;
|
||||
a.action.str = str;
|
||||
a.action.ops = std::move(state->operands);
|
||||
state->operands.clear();
|
||||
|
||||
state->actions.push_back(std::move(a));
|
||||
}
|
||||
|
||||
void set_partial_state_action_log(script_partial_state_t *state, const char *str)
|
||||
{
|
||||
MDEBUG("log");
|
||||
|
||||
const size_t expect = get_format_string_expected_operands(str);
|
||||
if (expect != state->operands.size())
|
||||
{
|
||||
tfscript_error("log action format string expects " + std::to_string(expect) + " operands but has " + std::to_string(state->operands.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
WeightedAction a;
|
||||
a.action.type = action_log;
|
||||
a.action.str = str;
|
||||
a.action.ops = std::move(state->operands);
|
||||
state->operands.clear();
|
||||
|
||||
state->actions.push_back(std::move(a));
|
||||
}
|
||||
|
||||
void set_partial_state_action_percent(script_partial_state_t *state)
|
||||
{
|
||||
MDEBUG("percent");
|
||||
|
@ -166,7 +166,7 @@ pick_actions: pick_actions pick_action { set_partial_state_action_inc_action_gro
|
||||
pick_action: WEIGHT operand action { set_partial_state_action_set_weight(state); }
|
||||
;
|
||||
|
||||
action_storyline_event: STORYLINE EVENT STRING { set_partial_state_action(state, action_storyline_event, $3, 0); }
|
||||
action_storyline_event: STORYLINE EVENT STRING operands { set_partial_state_action_storyline_event(state, $3); }
|
||||
;
|
||||
|
||||
action_if: IF { set_partial_state_action_add_action_group_count(state); } '(' expression ')' '{' if_actions '}' { set_partial_state_action_if(state); } optional_else
|
||||
@ -183,13 +183,16 @@ optional_else: ELSE { set_partial_state_action_add_action_group_count(state); }
|
||||
action_start_background_script: START BACKGROUND SCRIPT operand { set_partial_state_action(state, action_start_background_script, NULL, 1); }
|
||||
;
|
||||
|
||||
action_log: LOG STRING { set_partial_state_action(state, action_log, $2, 0); }
|
||||
action_log: LOG STRING operand { set_partial_state_action(state, action_log, $2, 1); }
|
||||
action_log: LOG STRING operands { set_partial_state_action_log(state, $2); }
|
||||
;
|
||||
|
||||
action_none: NONE { set_partial_state_action(state, action_none, NULL, 0); }
|
||||
;
|
||||
|
||||
operands:operands operand {}
|
||||
| {}
|
||||
;
|
||||
|
||||
reserves: RESERVES '{' reserves_contents '}'
|
||||
;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user