Files
@ r28572:dd3e6f760743
Branch filter:
Location: cpp/openttd-patchpack/source/src/script/api/script_text.cpp - annotation
r28572:dd3e6f760743
7.4 KiB
text/x-c
Update: nlohmann/json to 3.11.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r20473:7d7140ae0710 r26937:a6f9bdfea7b6 r18777:cf24fc430b51 r27049:913f3ce60451 r26890:e661e1f3708a r18777:cf24fc430b51 r18777:cf24fc430b51 r20473:7d7140ae0710 r20473:7d7140ae0710 r21383:942c32fb8b0e r21383:942c32fb8b0e r27367:d55d6f0719f9 r21410:ae5961f02724 r21410:ae5961f02724 r21410:ae5961f02724 r21410:ae5961f02724 r18793:153ee1a0721f r18793:153ee1a0721f r18777:cf24fc430b51 r18793:153ee1a0721f r18793:153ee1a0721f r21642:d4ee019baf14 r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r21642:d4ee019baf14 r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r21642:d4ee019baf14 r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18793:153ee1a0721f r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r26935:8e24100a08c1 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r26935:8e24100a08c1 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r23607:36c15679007d r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r21642:d4ee019baf14 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r25705:db1afb7a7392 r23607:36c15679007d r18777:cf24fc430b51 r18777:cf24fc430b51 r26936:79d1aa0fc3c8 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r27737:728d55b97775 r18777:cf24fc430b51 r18777:cf24fc430b51 r21639:04805e592ebb r21639:04805e592ebb r18777:cf24fc430b51 r27551:ea0213f40bc7 r28497:706f2f6ea5ba r27551:ea0213f40bc7 r27551:ea0213f40bc7 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r27737:728d55b97775 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r18777:cf24fc430b51 r27687:9834f91f0c39 r18777:cf24fc430b51 r28506:4fd07c3f848d r28506:4fd07c3f848d r20025:983c2ed8d329 r27534:3b2933f53491 r27534:3b2933f53491 r28506:4fd07c3f848d r28506:4fd07c3f848d r26956:da97fd88fa9b r27534:3b2933f53491 r18777:cf24fc430b51 r18777:cf24fc430b51 r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r18777:cf24fc430b51 r26957:c018305aca7e r26957:c018305aca7e r26957:c018305aca7e r26957:c018305aca7e r26957:c018305aca7e r27534:3b2933f53491 r27534:3b2933f53491 r26937:a6f9bdfea7b6 r26937:a6f9bdfea7b6 r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r26937:a6f9bdfea7b6 r26937:a6f9bdfea7b6 r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r26937:a6f9bdfea7b6 r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r27049:913f3ce60451 r26937:a6f9bdfea7b6 r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r27049:913f3ce60451 r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r27049:913f3ce60451 r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r28506:4fd07c3f848d r18777:cf24fc430b51 r26937:a6f9bdfea7b6 r26937:a6f9bdfea7b6 r18777:cf24fc430b51 r18777:cf24fc430b51 r26957:c018305aca7e r18777:cf24fc430b51 r20473:7d7140ae0710 r26891:5a795b8188a7 r20473:7d7140ae0710 r27691:699637d670b6 r27413:b706f5407370 r20473:7d7140ae0710 | /*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file script_text.cpp Implementation of ScriptText. */
#include "../../stdafx.h"
#include "../../string_func.h"
#include "../../strings_func.h"
#include "../../game/game_text.hpp"
#include "script_text.hpp"
#include "script_log.hpp"
#include "../script_fatalerror.hpp"
#include "../../table/control_codes.h"
#include "table/strings.h"
#include "../../safeguards.h"
RawText::RawText(const std::string &text) : text(text)
{
}
ScriptText::ScriptText(HSQUIRRELVM vm) :
ZeroedMemoryAllocator()
{
int nparam = sq_gettop(vm) - 1;
if (nparam < 1) {
throw sq_throwerror(vm, "You need to pass at least a StringID to the constructor");
}
/* First resolve the StringID. */
SQInteger sqstring;
if (SQ_FAILED(sq_getinteger(vm, 2, &sqstring))) {
throw sq_throwerror(vm, "First argument must be a valid StringID");
}
this->string = sqstring;
/* The rest of the parameters must be arguments. */
for (int i = 0; i < nparam - 1; i++) {
/* Push the parameter to the top of the stack. */
sq_push(vm, i + 3);
if (SQ_FAILED(this->_SetParam(i, vm))) {
this->~ScriptText();
throw sq_throwerror(vm, "Invalid parameter");
}
/* Pop the parameter again. */
sq_pop(vm, 1);
}
}
SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
{
if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
switch (sq_gettype(vm, -1)) {
case OT_STRING: {
const SQChar *value;
sq_getstring(vm, -1, &value);
this->param[parameter] = StrMakeValid(value);
break;
}
case OT_INTEGER: {
SQInteger value;
sq_getinteger(vm, -1, &value);
this->param[parameter] = value;
break;
}
case OT_INSTANCE: {
SQUserPointer real_instance = nullptr;
HSQOBJECT instance;
sq_getstackobj(vm, -1, &instance);
/* Validate if it is a GSText instance */
sq_pushroottable(vm);
sq_pushstring(vm, "GSText", -1);
sq_get(vm, -2);
sq_pushobject(vm, instance);
if (sq_instanceof(vm) != SQTrue) return SQ_ERROR;
sq_pop(vm, 3);
/* Get the 'real' instance of this class */
sq_getinstanceup(vm, -1, &real_instance, nullptr);
if (real_instance == nullptr) return SQ_ERROR;
ScriptText *value = static_cast<ScriptText *>(real_instance);
this->param[parameter] = ScriptTextRef(value);
break;
}
default: return SQ_ERROR;
}
if (this->paramc <= parameter) this->paramc = parameter + 1;
return 0;
}
SQInteger ScriptText::SetParam(HSQUIRRELVM vm)
{
if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
SQInteger k;
sq_getinteger(vm, 2, &k);
if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
if (k < 1) return SQ_ERROR;
k--;
return this->_SetParam(k, vm);
}
SQInteger ScriptText::AddParam(HSQUIRRELVM vm)
{
SQInteger res;
res = this->_SetParam(this->paramc, vm);
if (res != 0) return res;
/* Push our own instance back on top of the stack */
sq_push(vm, 1);
return 1;
}
SQInteger ScriptText::_set(HSQUIRRELVM vm)
{
int32_t k;
if (sq_gettype(vm, 2) == OT_STRING) {
const SQChar *key_string;
sq_getstring(vm, 2, &key_string);
std::string str = StrMakeValid(key_string);
if (!str.starts_with("param_") || str.size() > 8) return SQ_ERROR;
k = stoi(str.substr(6));
} else if (sq_gettype(vm, 2) == OT_INTEGER) {
SQInteger key;
sq_getinteger(vm, 2, &key);
k = (int32_t)key;
} else {
return SQ_ERROR;
}
if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
if (k < 1) return SQ_ERROR;
k--;
return this->_SetParam(k, vm);
}
std::string ScriptText::GetEncodedText()
{
StringIDList seen_ids;
ParamList params;
int param_count = 0;
std::string result;
auto output = std::back_inserter(result);
this->_FillParamList(params);
this->_GetEncodedText(output, param_count, seen_ids, params);
if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string)));
return result;
}
void ScriptText::_FillParamList(ParamList ¶ms)
{
for (int i = 0; i < this->paramc; i++) {
Param *p = &this->param[i];
params.emplace_back(this->string, i, p);
if (!std::holds_alternative<ScriptTextRef>(*p)) continue;
std::get<ScriptTextRef>(*p)->_FillParamList(params);
}
}
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int ¶m_count, StringIDList &seen_ids, ParamSpan args)
{
const std::string &name = GetGameStringName(this->string);
if (std::find(seen_ids.begin(), seen_ids.end(), this->string) != seen_ids.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", name));
seen_ids.push_back(this->string);
Utf8Encode(output, SCC_ENCODED);
fmt::format_to(output, "{:X}", this->string);
const StringParams ¶ms = GetGameStringParams(this->string);
size_t idx = 0;
auto get_next_arg = [&]() {
if (idx >= args.size()) throw Script_FatalError(fmt::format("{}({}): Not enough parameters", name, param_count + 1));
ParamCheck &pc = args[idx++];
if (pc.owner != this->string) ScriptLog::Warning(fmt::format("{}({}): Consumes {}({})", name, param_count + 1, GetGameStringName(pc.owner), pc.idx + 1));
return pc.param;
};
auto skip_args = [&](size_t nb) { idx += nb; };
for (const StringParam &cur_param : params) {
switch (cur_param.type) {
case StringParam::UNUSED:
skip_args(cur_param.consumes);
break;
case StringParam::RAW_STRING: {
Param *p = get_next_arg();
if (!std::holds_alternative<std::string>(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd));
fmt::format_to(output, ":\"{}\"", std::get<std::string>(*p));
break;
}
case StringParam::STRING: {
Param *p = get_next_arg();
if (!std::holds_alternative<ScriptTextRef>(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd));
int count = 0;
fmt::format_to(output, ":");
ScriptTextRef &ref = std::get<ScriptTextRef>(*p);
ref->_GetEncodedText(output, count, seen_ids, args.subspan(idx));
if (++count != cur_param.consumes) {
ScriptLog::Error(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1));
/* Fill missing params if needed. */
for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0");
}
skip_args(cur_param.consumes - 1);
break;
}
default:
for (int i = 0; i < cur_param.consumes; i++) {
Param *p = get_next_arg();
if (!std::holds_alternative<SQInteger>(*p)) throw Script_FatalError(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(*p));
}
}
param_count += cur_param.consumes;
}
seen_ids.pop_back();
}
const std::string Text::GetDecodedText()
{
::SetDParamStr(0, this->GetEncodedText());
return ::GetString(STR_JUST_RAW_STRING);
}
|