Fix blank animqueues, and add facing=math.auto to animate
This commit is contained in:
@@ -10,6 +10,12 @@
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
util::SharedStdString AnimQueue::blankqueue_;
|
||||
|
||||
void AnimQueue::initialize_module() {
|
||||
AnimQueue queue;
|
||||
blankqueue_ = queue.get_encoded_queue();
|
||||
}
|
||||
|
||||
static uint64_t hash_encstep(uint64_t prev, std::string_view s) {
|
||||
return util::hash_string(util::HashValue(123, prev), s).first;
|
||||
@@ -67,6 +73,10 @@ static AnimValue parse_anim_value(LuaCoreStack &LS, LuaSlot val, LuaSlot tmp) {
|
||||
if (!LS.isnumber(tmp)) return result;
|
||||
xyz.z = LS.cknumber(tmp);
|
||||
result.set_dxyz(xyz);
|
||||
} else if (LS.rawequal(val, LuaToken("auto"))) {
|
||||
result.set_auto();
|
||||
} else {
|
||||
result.set_uninitialized();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -111,6 +121,8 @@ void AnimState::print_debug_string(eng::ostringstream &oss) {
|
||||
oss << ":";
|
||||
}
|
||||
switch (value.type) {
|
||||
case SimpleDynamicTag::UNINITIALIZED: oss << "UNINITIALIZED"; break;
|
||||
case SimpleDynamicTag::AUTO: oss << "AUTO"; break;
|
||||
case SimpleDynamicTag::NUMBER: oss << value.x; break;
|
||||
case SimpleDynamicTag::BOOLEAN: oss << ((value.x == 1.0) ? "true":"false"); break;
|
||||
case SimpleDynamicTag::VECTOR: oss << value.x << "," << value.y << "," << value.z; break;
|
||||
@@ -205,46 +217,91 @@ eng::string AnimState::add_defaults(const AnimState *other) {
|
||||
err = add_default("facing", defval, other);
|
||||
if (!err.empty()) return err;
|
||||
|
||||
defval.set_string("stdbp");
|
||||
defval.set_string("unknown");
|
||||
err = add_default("bp", defval, other);
|
||||
if (!err.empty()) return err;
|
||||
|
||||
defval.set_string("stdmodel");
|
||||
err = add_default("model", defval, other);
|
||||
if (!err.empty()) return err;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
eng::string AnimState::apply_lua(LuaCoreStack &LS0, LuaSlot tab, bool setpersist) {
|
||||
eng::string AnimState::from_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent, bool allowauto) {
|
||||
LuaVar key, val, tmp;
|
||||
LuaExtStack LS(LS0.state(), key, val, tmp);
|
||||
util::DXYZ xyz;
|
||||
|
||||
clear();
|
||||
if (!LS.istable(tab)) {
|
||||
return "An animstate must be a table.";
|
||||
return "A lua animstate must be a table.";
|
||||
}
|
||||
LS.set(key, LuaNil);
|
||||
while (LS.next(tab, key, val)) {
|
||||
if (!LS.isstring(key)) {
|
||||
return "in animation key-value pairs, key must be a string.";
|
||||
}
|
||||
eng::string name = LS.ckstring(key);
|
||||
if (!LS.valididentifier(name)) {
|
||||
return "in animation key-value pairs, key must be a valid lua identifier.";
|
||||
}
|
||||
AnimValue parsedvalue = parse_anim_value(LS, val, tmp);
|
||||
if (parsedvalue.type == SimpleDynamicTag::UNINITIALIZED) {
|
||||
return "in animation key-value pairs, val must be number, string, boolean, or xyz";
|
||||
return "in animation key-value pairs, value must be number, string, boolean, or xyz";
|
||||
}
|
||||
if ((parsedvalue.type == SimpleDynamicTag::AUTO) && !allowauto) {
|
||||
return "in animation key-value pairs, value must not be AUTO here.";
|
||||
}
|
||||
eng::string name = LS.ckstring(key);
|
||||
AnimValue &mapentry = map_[name];
|
||||
if ((mapentry.type != SimpleDynamicTag::UNINITIALIZED) && (mapentry.type != parsedvalue.type)) {
|
||||
return util::ss("animation '", name, "' must be a ", mapentry.type_name());
|
||||
}
|
||||
mapentry.copy_value(parsedvalue);
|
||||
if (setpersist) mapentry.persistent = true;
|
||||
mapentry.persistent = persistent;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
eng::string AnimState::merge(const AnimState &previous, const AnimState &update) {
|
||||
// Copy everything over from the previous entry.
|
||||
map_ = previous.map_;
|
||||
|
||||
for (const auto &pair : update.map_) {
|
||||
const eng::string &name = pair.first;
|
||||
AnimValue &dst = map_[name];
|
||||
const AnimValue &src = pair.second;
|
||||
|
||||
// Handle autocalculation rules.
|
||||
if (src.type == SimpleDynamicTag::AUTO) {
|
||||
if (name == "facing") {
|
||||
if (!dst.persistent || dst.type != SimpleDynamicTag::NUMBER) {
|
||||
return "Cannot auto-calculate facing because facing has not been specified as a persistent number";
|
||||
}
|
||||
const auto xyz_previous = previous.map_.find("xyz");
|
||||
const auto xyz_update = update.map_.find("xyz");
|
||||
if ((xyz_previous == previous.map_.end()) ||
|
||||
(xyz_update == update.map_.end()) ||
|
||||
(xyz_previous->second.type != SimpleDynamicTag::VECTOR) ||
|
||||
(xyz_update->second.type != SimpleDynamicTag::VECTOR)) {
|
||||
return "Cannot auto-calculate facing because before/after xyz coordinates are not present";
|
||||
}
|
||||
double dx = xyz_update->second.x - xyz_previous->second.x;
|
||||
double dy = xyz_update->second.y - xyz_previous->second.y;
|
||||
// If dx and dy are both zero, leave the facing unmodified.
|
||||
if ((dx != 0.0) || (dy != 0.0)) {
|
||||
double facing = atan2(dy, dx) * 180.0 / M_PI;
|
||||
dst.set_number(facing);
|
||||
}
|
||||
} else {
|
||||
return util::ss("No rule to automatically calculate ", name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dst.persistent && (src.type != dst.type)) {
|
||||
return util::ss("Wrong data type for ", name, ", should be ", dst.type_name());
|
||||
}
|
||||
dst.copy_value(src);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
void AnimState::to_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent) {
|
||||
LuaVar name, val;
|
||||
LuaExtStack LS(LS0.state(), name, val);
|
||||
@@ -269,6 +326,7 @@ void AnimState::to_lua(LuaCoreStack &LS0, LuaSlot tab, bool persistent) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The syntax used by this parser is not general enough to represent all
|
||||
// possible strings. That's OK, though, since it's just for unit testing.
|
||||
void AnimState::parse(std::string_view config) {
|
||||
|
||||
Reference in New Issue
Block a user