#pragma once // The entity/component part of Noita's Lua API, expressed as an interface the game world implements. // LuaHost forwards EntityGetFirstComponent, ComponentGetValue2, EntityLoad, EntityKill, ... to it. #include #include #include #include "entity/spawn_comp.h" namespace ng { // A Lua value crossing the boundary. struct LVal { enum class T { Nil, Bool, Num, Str } t = T::Nil; bool b = false; double n = 0; std::string s; static LVal nil() { return {}; } static LVal boolean(bool v) { LVal r; r.t = T::Bool; r.b = v; return r; } static LVal number(double v) { LVal r; r.t = T::Num; r.n = v; return r; } static LVal string(std::string v) { LVal r; r.t = T::Str; r.s = std::move(v); return r; } }; class IEntityWorld { public: virtual ~IEntityWorld() = default; // ---- entities ---- virtual int load(const std::string& path, double x, double y) = 0; // 0 on failure virtual int load_with(const std::string& path, double x, double y, const std::vector& extra) { (void)extra; return load(path, x, y); } // the same with components merged in at the spawn ("=Type" merges into the first of that type) virtual void load_to_entity(const std::string& path, int entity) = 0; // EntityLoadToEntity: the file's components are added to the entity (not its tags, not its children) virtual void kill(int id) = 0; virtual void physics_init(int /*id*/) {} // PhysicsBody2InitFromComponents virtual bool alive(int id) = 0; virtual bool get_transform(int id, double& x, double& y, double& rot, double& sx, double& sy) = 0; virtual void set_transform(int id, double x, double y, double rot, double sx, double sy) = 0; virtual std::string get_name(int id) = 0; virtual void set_name(int id, const std::string& name) = 0; virtual std::string get_filename(int id) = 0; virtual bool has_tag(int id, const std::string& tag) = 0; virtual void add_tag(int id, const std::string& tag) = 0; virtual void remove_tag(int id, const std::string& tag) = 0; virtual std::string get_tags(int id) = 0; // comma separated virtual std::vector with_tag(const std::string& tag) = 0; // empty tag = all virtual std::vector in_radius(double x, double y, double r, const std::string& tag) = 0; virtual void script_query(bool on) { (void)on; } // a Lua query follows (with_tag / in_radius): the GPU-only projectiles get their twins first virtual int parent(int id) = 0; virtual std::vector children(int id) = 0; virtual void add_child(int parent, int child) = 0; // A spell card inside a wand (AddGunAction / AddGunActionPermanent): a hidden child entity carrying the action id. virtual int add_gun_action(int wand, const std::string& action_id, bool permanent) = 0; // ---- components ---- virtual std::vector components(int entity, const std::string& type, const std::string& tag, bool include_disabled) = 0; virtual int add_component(int entity, const std::string& type, const std::map& attrs) = 0; virtual void remove_component(int comp) = 0; virtual void set_component_enabled(int comp, bool enabled) = 0; virtual bool component_enabled(int comp) = 0; virtual std::string component_type(int comp) = 0; virtual int component_entity(int comp) = 0; virtual bool comp_has_tag(int comp, const std::string& tag) = 0; virtual LVal get_value(int comp, const std::string& key, bool typed) = 0; // nil if the key is unknown virtual void set_value(int comp, const std::string& key, const LVal& v) = 0; // ---- context of the running script ---- virtual int updated_entity() = 0; virtual int updated_component() = 0; virtual int frame() = 0; virtual std::vector game_effect_components(int entity, const std::string& effect) { (void)entity; (void)effect; return {}; } // GameEffectComponents of the entity and its children (empty name = all) virtual int load_game_effect(int entity, const std::string& effect, bool always_new, int& effect_entity) { (void)entity; (void)effect; (void)always_new; effect_entity = 0; return 0; } // GetGameEffectLoadTo: the component (and entity) of the effect on the entity, loaded when missing virtual int load_game_effect_file(int entity, const std::string& file) { (void)entity; (void)file; return 0; } // LoadGameEffectEntityTo virtual void shoot_projectile(int shooter, double x, double y, double tx, double ty, int entity, bool send_message = true) { (void)shooter; (void)x; (void)y; (void)tx; (void)ty; (void)entity; (void)send_message; } // GameShootProjectile virtual void play_sound(const std::string& bank, const std::string& event, double x, double y) { (void)bank; (void)event; (void)x; (void)y; } // GamePlaySound virtual void physics_remove_joints(double x0, double y0, double x1, double y1) { (void)x0; (void)y0; (void)x1; (void)y1; } // PhysicsRemoveJoints virtual void screenshake(double amount, double x, double y) { (void)amount; (void)x; (void)y; } // GameScreenshake virtual void convert_material_everywhere(int from, int to) { (void)from; (void)to; } // ConvertMaterialEverywhere (fungal shifts) virtual void entity_play_sound(int entity, const std::string& name) { (void)entity; (void)name; } // GameEntityPlaySound: through every AudioComponent of the entity virtual void entity_play_sound_loop(int entity, const std::string& tag, double intensity, double intensity2) { (void)entity; (void)tag; (void)intensity; (void)intensity2; } // GameEntityPlaySoundLoop // EntityInflictDamage (007b4030 -> 00ab9740 -> TakeDamage_Impl 00ab9a90): damage of a type (a DAMAGE_* name) through the entity's enabled DamageModelComponent; the world position defaults to the entity's virtual void inflict_damage(int entity, double amount, const std::string& type, const std::string& description, const std::string& ragdoll_fx, double impulse_x, double impulse_y, int responsible, double world_x, double world_y, double knockback) { (void)entity; (void)amount; (void)type; (void)description; (void)ragdoll_fx; (void)impulse_x; (void)impulse_y; (void)responsible; (void)world_x; (void)world_y; (void)knockback; } virtual std::string biome_name(double x, double y) { (void)x; (void)y; return "_EMPTY_"; } // BiomeMapGetName: "$biome_coalmine"... virtual int world_state_entity() = 0; virtual void remove_from_parent(int id) { (void)id; } // EntityRemoveFromParent virtual bool camera_bounds(double& x, double& y, double& w, double& h) { (void)x; (void)y; (void)w; (void)h; return false; } // GameGetCameraBounds / GameGetCameraPos virtual void regen_item_actions(int player) { (void)player; } // GameRegenItemActionsInPlayer: every spell the player carries has its uses back virtual int create_entity(const std::string& name) { (void)name; return 0; } // EntityCreateNew: an entity without components virtual void comp_add_tag(int comp, const std::string& tag) { (void)comp; (void)tag; } // ComponentAddTag virtual int herd_relation(int a, int b) { (void)a; (void)b; return 0; } // EntityGetHerdRelation virtual int wand_capacity(int wand) { (void)wand; return 0; } // EntityGetWandCapacity: the slots without the always-cast spells virtual void print(const std::string& title, const std::string& text, bool important) = 0; virtual void physics_force(int entity, double fx, double fy) { (void)entity; (void)fx; (void)fy; } // PhysicsApplyForce struct BodyInfo { int entity = 0; double mass = 1, x = 0, y = 0, vx = 0, vy = 0, angular = 0; }; // a rigid body: mass (kg), position (pixels), velocity (pixels per second) virtual std::vector bodies_in_area(double x0, double y0, double x1, double y1) { (void)x0; (void)y0; (void)x1; (void)y1; return {}; } // PhysicsApplyForceOnArea virtual void physics_area_force(int entity, double fx, double fy) { (void)entity; (void)fx; (void)fy; } // the force of PhysicsApplyForceOnArea's callback (newtons on the body) }; } // namespace ng