Cleanups in entity source file

Code cleanups, convert comments into annotations consumable by Doxygen where applicable, renames and splits up the shape extruder object's class into a separate source files, etc...
This commit is contained in:
ROllerozxa 2026-05-16 17:31:48 +02:00
commit 8771027650
7 changed files with 954 additions and 1223 deletions

View file

@ -7,9 +7,7 @@
#include "rack.hh"
#include "game.hh"
void
connection::update(void)
{
void connection::update(void) {
this->layer = this->e->get_layer();
this->layer_mask = this->e->layer_mask;
@ -22,33 +20,23 @@ connection::update(void)
this->sublayer_dist = this->e->sublayer_dist(this->o);
}
/**
* Updates the relative angle between the bodies
**/
void
connection::update_relative_angle(bool force)
{
void connection::update_relative_angle(bool force) {
if (!force) {
b2Joint *j = this->j;
if (j) {
b2JointType t = j->GetType();
if (t != e_revoluteJoint && t != e_pivotJoint) {
if (t != e_revoluteJoint && t != e_pivotJoint)
return;
}
}
}
tms_infof("update relative angle for connection %p", this);
tms_infof("object 1: %p, object 2: %p", this->e, this->o);
this->relative_angle = -(this->o->get_angle(this->f[1]) - this->e->get_angle(this->f[0]));
}
/**
* Apply is called the first time the connection is created
**/
void
connection::apply(void)
{
//tms_infof("apply joint : %f %f, %p", this->p.x, this->p.y, this);
void connection::apply() {
this->update_relative_angle(true);
if (this->type != CONN_GEAR) {
@ -68,7 +56,6 @@ connection::apply(void)
this->sublayer_dist = this->e->sublayer_dist(this->o);
if (!this->fixed) {
//tms_infof("adding to bodies");
this->e->add_connection(this);
this->o->add_connection(this);
}
@ -76,88 +63,61 @@ connection::apply(void)
this->pending = false;
}
void
connection::destroy_joint()
{
void connection::destroy_joint() {
if (this->j) {
if (!this->owned || this->e->connection_destroy_joint(this) == false)
this->e->get_body(this->f[0])->GetWorld()->DestroyJoint(this->j);
this->j = 0;
}
this->remove_self_ent();
}
void
connection::remove_self_ent()
{
if (this->self_ent) {
if (this->self_ent->scene) {
G->remove_entity(this->self_ent);
}
delete this->self_ent;
this->self_ent = 0;
}
}
void
connection::create_self_ent(bool add)
{
if (this->render_type == CONN_RENDER_HIDE) {
void connection::remove_self_ent() {
if (!this->self_ent)
return;
}
switch (this->type) {
case CONN_PIVOT:
case CONN_WELD:
case CONN_PLATE:
this->self_ent = new connection_entity(this, this->type);
break;
}
if (this->self_ent->scene)
G->remove_entity(this->self_ent);
if (this->self_ent && add) {
if (this->self_ent->scene == 0) {
G->add_entity(this->self_ent);
}
}
delete this->self_ent;
this->self_ent = 0;
}
void
connection::update_render_type()
{
void connection::create_self_ent(bool add) {
if (this->render_type == CONN_RENDER_HIDE)
return;
if (this->type == CONN_PIVOT || this->type == CONN_WELD || this->type == CONN_PLATE)
this->self_ent = new connection_entity(this, this->type);
if (this->self_ent && add && this->self_ent->scene == 0)
G->add_entity(this->self_ent);
}
void connection::update_render_type() {
tms_debugf("Update render type. Self ent: %p", this->self_ent);
bool add = (this->self_ent && this->self_ent->scene);
this->remove_self_ent();
switch (this->render_type) {
case CONN_RENDER_HIDE:
break;
if (this->render_type == CONN_RENDER_HIDE)
return;
default:
if (!this->self_ent) {
this->create_self_ent(add);
}
break;
}
if (!this->self_ent)
this->create_self_ent(add);
}
void
connection::create_joint(bool add)
{
if (this->type == CONN_GROUP) {
void connection::create_joint(bool add) {
if (this->type == CONN_GROUP)
return;
}
if (!this->self_ent) {
this->create_self_ent(add);
} else {
if (this->self_ent->mesh == mesh_factory::get_mesh(MODEL_PLATEJOINT_DAMAGED)) {
if (this->self_ent->mesh == mesh_factory::get_mesh(MODEL_PLATEJOINT_DAMAGED))
this->self_ent->set_mesh(mesh_factory::get_mesh(MODEL_PLATEJOINT));
}
}
//tms_infof("group: %p, body: %p, %d", this->e->group, this->e->body, this->f[0]);
@ -181,7 +141,7 @@ connection::create_joint(bool add)
switch (this->type) {
case CONN_CUSTOM: this->e->connection_create_joint(this); break;
case CONN_RACK:{
case CONN_RACK: {
gear *g = static_cast<gear*>(this->e); /* always this order */
rack *r = static_cast<rack*>(this->o);
@ -193,10 +153,9 @@ connection::create_joint(bool add)
this->j = b2->CreateJoint(&gjd);
r->update_limits();
}
break;
} break;
case CONN_GEAR:{
case CONN_GEAR: {
gear *g0 = static_cast<gear*>(this->e);
gear *g1 = static_cast<gear*>(this->o);
float ratio = 1.f;
@ -207,13 +166,6 @@ connection::create_joint(bool add)
}
}
/*
if (((gear*)this->e)->get_num_gear_conns() < ((gear*)this->o)->get_num_gear_conns()) {
((gear*)this->e)->fix_position(this->o);
} else
((gear*)this->o)->fix_position(this->e);
*/
gjd.bodyA = this->e->get_body(this->f[0]);
gjd.bodyB = this->o->get_body(this->f[1]);
gjd.joint1 = ((gear*)this->e)->joint;
@ -223,8 +175,7 @@ connection::create_joint(bool add)
gjd.ratio = ratio;
gjd.collideConnected = true;
this->j = b2->CreateJoint(&gjd);
}
break;
} break;
case CONN_PIVOT:
if (this->e->is_wheel() && this->o->is_wheel() && this->e->get_layer() != this->o->get_layer()) {
@ -256,53 +207,47 @@ connection::create_joint(bool add)
break;
case CONN_PLATE:
case CONN_WELD:
{
if (this->e->is_wheel() && this->o->is_wheel() && this->e->get_layer() != this->o->get_layer()) {
wjd.localAnchorA = this->e->local_to_body(b2Vec2(0.f, 0.f), this->f[0]);
wjd.localAnchorB = this->o->local_to_body(b2Vec2(0.f, 0.f), this->f[1]);
} else {
wjd.localAnchorA = this->e->local_to_body(this->p, this->f[0]);
wjd.localAnchorB = this->o->local_to_body(this->p_s, this->f[1]);
}
wjd.bodyA = this->e->get_body(this->f[0]);
wjd.bodyB = this->o->get_body(this->f[1]);
if (wjd.bodyA->GetType() == b2_staticBody && wjd.bodyB->GetType() == b2_staticBody) {
this->j = 0;
tms_debugf("skipping joint between static bodies");
break;
}
wjd.referenceAngle = this->o->get_body(this->f[1])->GetAngle() - this->e->get_body(this->f[0])->GetAngle()
- (this->o->get_angle(this->f[1]) - this->e->get_angle(this->f[0])) - this->relative_angle;
//wjd.referenceAngle = this->o->get_angle(this->f[1]) - this->e->get_angle(this->f[0]);
wjd.collideConnected = false;
wjd.frequencyHz = 0.f;
if (false && this->tolerant && !W->is_paused())
wjd.frequencyHz = 40.f;
this->j = b2->CreateJoint(&wjd);
b2Vec2 pp = this->e->local_to_world(wjd.localAnchorA, this->f[0]);
tms_debugf("applied plate, to world = %f %f, f = %u, id <%u,%u>", pp.x, pp.y, this->f[0], this->e->id, this->o->id);
case CONN_WELD: {
if (this->e->is_wheel() && this->o->is_wheel() && this->e->get_layer() != this->o->get_layer()) {
wjd.localAnchorA = this->e->local_to_body(b2Vec2(0.f, 0.f), this->f[0]);
wjd.localAnchorB = this->o->local_to_body(b2Vec2(0.f, 0.f), this->f[1]);
} else {
wjd.localAnchorA = this->e->local_to_body(this->p, this->f[0]);
wjd.localAnchorB = this->o->local_to_body(this->p_s, this->f[1]);
}
break;
default:
{
tms_errorf("invalid joint type %d", this->type);
wjd.bodyA = this->e->get_body(this->f[0]);
wjd.bodyB = this->o->get_body(this->f[1]);
if (wjd.bodyA->GetType() == b2_staticBody && wjd.bodyB->GetType() == b2_staticBody) {
this->j = 0;
tms_debugf("skipping joint between static bodies");
break;
}
break;
wjd.referenceAngle = this->o->get_body(this->f[1])->GetAngle() - this->e->get_body(this->f[0])->GetAngle()
- (this->o->get_angle(this->f[1]) - this->e->get_angle(this->f[0])) - this->relative_angle;
//wjd.referenceAngle = this->o->get_angle(this->f[1]) - this->e->get_angle(this->f[0]);
wjd.collideConnected = false;
wjd.frequencyHz = 0.f;
if (false && this->tolerant && !W->is_paused())
wjd.frequencyHz = 40.f;
this->j = b2->CreateJoint(&wjd);
b2Vec2 pp = this->e->local_to_world(wjd.localAnchorA, this->f[0]);
tms_debugf("applied plate, to world = %f %f, f = %u, id <%u,%u>", pp.x, pp.y, this->f[0], this->e->id, this->o->id);
} break;
default: {
tms_errorf("invalid joint type %d", this->type);
} break;
}
if (this->max_force < INFINITY) {
//tms_infof("joint is destructable");
if (this->max_force < INFINITY) // joint is destructable
G->add_destructable_joint(this->j, this->max_force);
}
} else
this->j = 0;
@ -314,22 +259,18 @@ connection::create_joint(bool add)
}
}
b2Vec2 connection::get_position()
{
b2Vec2 connection::get_position() {
return this->e->local_to_world(this->p, this->f[0]);
}
connection_entity::connection_entity(connection *c, int type)
{
connection_entity::connection_entity(connection *c, int type) {
this->conn = c;
this->curr_update_method = this->update_method = ENTITY_UPDATE_JOINT;
//((struct tms_entity*)this)->update = 0;
//
this->conn->type = type;
if ((c->e->layer_mask & c->o->layer_mask) == 0 && c->o->get_layer() == c->e->get_layer()) {
/* breadboard, sublayer plank */
// special case for e.g. breadboard, sublayer plank
type = CONN_PIVOT;
}
@ -341,31 +282,18 @@ connection_entity::connection_entity(connection *c, int type)
tmat4_load_identity(this->M);
tmat3_load_identity(this->N);
switch (type) {
case CONN_WELD: case CONN_PLATE:
if (c->render_type == CONN_RENDER_NAIL || (c->multilayer)) {
case CONN_PLATE:
if (c->render_type == CONN_RENDER_NAIL || (c->multilayer))
this->set_mesh(mesh_factory::get_mesh(MODEL_PIVOTJOINT));
} else {
else
this->set_mesh(mesh_factory::get_mesh(MODEL_PLATEJOINT));
}
break;
/* case CONN_WELD:
if (c->multilayer)
this->set_mesh(tms_meshfactory_get_cylinder());
else
this->set_mesh(mesh_factory::weldjoint);
break;*/
case CONN_PIVOT:
this->set_mesh(mesh_factory::get_mesh(MODEL_PIVOTJOINT));
this->curr_update_method = this->update_method = ENTITY_UPDATE_JOINT_PIVOT;
break;
this->curr_update_method = this->update_method = ENTITY_UPDATE_JOINT_PIVOT;
break;
}
/*
if (c->render_type == CONN_RENDER_NAIL)
this->set_material(&m_conn);
else
*/
this->set_material(&m_conn_no_ao);
this->set_material(&m_conn_no_ao);
}

File diff suppressed because it is too large Load diff

View file

@ -17,20 +17,20 @@ class game;
class world;
class base_prompt;
struct worth
{
/// Struct representing the worth of an entity in terms of mineral resources and oil
struct worth {
uint32_t resources[NUM_RESOURCES];
float oil;
worth();
/* Add num resources */
/// Add num resources
struct worth& add(uint8_t resource_type, uint32_t num);
/* Add oil */
/// Add oil
struct worth& add_oil(float val);
/* Add resources and oil from another worth object */
/// Add resources and oil from another worth object
struct worth& add(const struct worth& worth);
};
@ -183,27 +183,32 @@ class connection;
#define JOINT_TYPE_SCUP 4
#define JOINT_TYPE_RAGDOLL 5
/// Data attached to connection joints
class joint_info {
public:
int type;
void *data;
bool should_destroy;
joint_info(int type, void *data)
{
joint_info(int type, void *data) {
this->type = type;
this->data = data;
this->should_destroy = true;
}
joint_info(){this->should_destroy=true;};
void destroy() const { if (this->should_destroy) delete this; }
joint_info() {
this->should_destroy = true;
}
void destroy() const {
if (this->should_destroy)
delete this;
}
protected:
~joint_info() {}
};
class connection
{
class connection {
private:
void remove_self_ent();
void create_self_ent(bool add);
@ -215,38 +220,43 @@ class connection
entity *self_ent;
b2Joint *j;
/* if the connection has an owner, e is the owner */
/// if the connection has an owner, e is the owner
entity *e;
entity *o;
bool fixed; /* can't be removed */
bool tolerant; /* if this joint allows slight displacement */
/// can't be removed
bool fixed;
/// if this joint allows slight displacement
bool tolerant;
/// if this connection has been destroyed during simulation
bool destroyed;
/* layer of the connection, if the connection spans multiple layers,
* this is the lowest layer of the two */
/// layer of the connection, if the connection spans multiple layers,
/// this is the lowest layer of the two
int layer;
/* sublayer mask of the connection, if the connection span multiple sublayers,
* this is the lowest sublayer of the two */
/// sublayer mask of the connection, if the connection span multiple sublayers,
/// this is the lowest sublayer of the two
int layer_mask;
int sublayer_dist;
/* if this connection is active, the point is in e's local
* coordinate frame, otherwise it is a world point */
b2Vec2 p, p_s; /* p_s is the secondary local anchor if weld or pivot joint */
/// if this connection is active, the point is in e's local
/// coordinate frame, otherwise it is a world point.
/// p_s is the secondary local anchor if weld or pivot joint
b2Vec2 p, p_s;
/* Coordinate frames for 'e' and 'o' */
/// Coordinate frames for 'e' and 'o'
uint8_t f[2];
bool owned;
uint8_t o_index;
bool pending;
bool multilayer; /* true if the connection spans two layers,
the rendered nail will not be rotated */
/// true if the connection spans two layers, the rendered nail will not be rotated
bool multilayer;
float relative_angle; /* relative angle of the entities level version 22 */
/// relative angle of the entities (level revision >= 22)
float relative_angle;
float angle;
uint8_t render_type;
@ -254,19 +264,22 @@ class connection
uint8_t option;
float max_force;
float damping; /* level VERSION 8, damping for rotary joints */
/// damping for rotary joints (level revision >= 8)
float damping;
uint32_t e_data; /* level version 28 (1.5) information about e */
uint32_t o_data; /* level version 28 (1.5) information about o */
/// information about e (level version >= 28)
uint32_t e_data;
/// information about o (level version >= 28)
uint32_t o_data;
/* we keep track of where this conn was last written or read */
/// we keep track of where this conn was last written or read
size_t write_ptr;
/// we keep track of where this conn was last written or read
size_t write_size;
connection *next[2];
connection()
{
connection() {
this->write_ptr = 0;
this->write_size = 0;
this->reset();
@ -274,35 +287,33 @@ class connection
b2Vec2 get_position();
/// Updates the relative angle between the bodies
void update_relative_angle(bool force);
inline void init_owned(int index, entity *e)
{
/// Initialise connection, being owned by an entity
inline void init_owned(int index, entity *e) {
this->reset();
this->e = e;
this->o_index = index;
}
inline entity *get_other(entity *e)
{
if (e == this->e) {
/// Get the other entity in the connection
inline entity *get_other(entity *e) {
if (e == this->e)
return this->o;
} else {
else
return this->e;
}
}
inline connection *get_next(entity *e)
{
if (e == this->e) {
/// Get the next connection for the given entity
inline connection *get_next(entity *e) {
if (e == this->e)
return next[0];
} else {
else
return next[1];
}
}
inline void reset(void)
{
inline void reset() {
this->ji = 0;
this->layer_mask = 0;
this->sublayer_dist = 0;
@ -334,21 +345,21 @@ class connection
destroyed = false;
}
void update(void);
void apply(void);
void update();
/// Apply is called the first time the connection is created
void apply();
void create_joint(bool add);
void destroy_joint(void);
void destroy_joint();
/// Update how the connection is rendered in-game
void update_render_type();
connection *clone()
{
connection *clone() {
return new connection(*this);
}
};
class property
{
class property {
public:
uint8_t type;
union {
@ -361,53 +372,60 @@ class property
} s;
} v;
property()
{
property() {
clear();
}
void clear()
{
void clear() {
type = 0;
memset(&this->v, 0, sizeof(this->v));
}
/* The receiving function is responsible for freeing the return value */
/// Serialise the property to a string.
/// The receiving function is responsible for freeing the return value
char* stringify();
/// Parse serialised property string back
void parse(char *buf);
};
struct entity_listener {
entity *self;
void *userdata;
void (*cb)(entity* self,void* userdata);
void (*cb)(entity* self, void* userdata);
};
/**
*
* entity pointer is stored in UserData of fixtures
* uint8 frame ID is stored in the body's UserData
**/
/// Main class for entities, including but not limited to objects as visible by players in-game.
///
/// - Entity pointer is stored in UserData of fixtures
/// - uint8 frame ID is stored in the body's UserData
class entity : public tms::entity
{
protected:
void easy_update();
/* shape creation functions, should be called from add_to_world */
void create_rect(b2BodyType type, float width, float height, m *m){create_rect(type,width,height,m,NULL);};
void create_rect(b2BodyType type, float width, float height, m *m) {
create_rect(type,width,height,m,NULL);
}
void create_rect(b2BodyType type, float width, float height, m *m, b2Fixture **fixture_out=NULL);
void create_circle(b2BodyType type, float radius, m *mat);
void create_rect(b2BodyType type, float width, float height, struct tms_material *mat){create_rect(type,width,height,static_cast<m*>(mat),NULL);};
void create_circle(b2BodyType type, float radius, struct tms_material* mat){ create_circle(type,radius,static_cast<m*>(mat)); };
void create_rect(b2BodyType type, float width, float height, struct tms_material *mat) {
create_rect(type,width,height,static_cast<m*>(mat),NULL);
}
void create_circle(b2BodyType type, float radius, struct tms_material* mat) {
create_circle(type,radius,static_cast<m*>(mat));
}
float m_scale;
float width; /* approximate width of the object, used for the menu rendering
and for positioning the rotation anchor */
/// Approximate width of the object, used for e.g. positioning the rotation anchor
float width;
public:
inline void fastbody_update()
{
inline void fastbody_update() {
const b2Transform &t = this->body->GetTransform();
//tmat4_load_identity(this->M);
@ -428,37 +446,30 @@ class entity : public tms::entity
void unsubscribe(entity *target);
void signal(int event);
inline float get_scale() const
{
inline float get_scale() const {
return this->m_scale;
}
void set_scale(float new_scale)
{
void set_scale(float new_scale) {
float old_scale = this->get_scale();
this->m_scale = new_scale;
this->scale_changed(old_scale, new_scale);
}
inline float get_width() const
{
inline float get_width() const {
return this->width * this->get_scale();
}
virtual void scale_changed(float old_scale, float new_scale)
{
virtual void scale_changed(float old_scale, float new_scale) {
this->recreate_fixtures(false);
}
virtual void recreate_fixtures(bool initial) { }
virtual void set_color(tvec4 c) {}
virtual tvec4 get_color() {return tvec4f(0.f, 0.f, 0.f, 0.f);}
virtual tvec4 get_color() {return tvec4f(0.f, 0.f, 0.f, 0.f); }
void set_color4(float r, float g, float b, float a=1.0f)
{
void set_color4(float r, float g, float b, float a=1.0f) {
this->set_color(tvec4f(r, g, b, a));
}
@ -469,11 +480,12 @@ class entity : public tms::entity
int curr_update_method;
b2Body *body;
uint8_t layer_mask;
//entity *owner;
property *properties;
uint8_t num_properties;
p_gid g_id; /* global object type identifier */
/// Global object type identifier
p_gid g_id;
/// ID of entity it was emitted by, for e.g. weapon projectiles
uint32_t emitted_by;
uint32_t emit_step;
@ -485,7 +497,7 @@ class entity : public tms::entity
b2Vec2 menu_pos;
b2Vec2 old_pos;
/* Used as a base for connection-checking */
/// Used as a base for connection-checking
b2Vec2 query_sides[4];
float query_len;
@ -493,12 +505,12 @@ class entity : public tms::entity
float _angle;
int dialog_id;
/* default state contains velocity and angular velocity of a single body */
/// default state contains velocity and angular velocity of a single body
float state[3];
size_t state_ptr;
size_t state_size;
/* we keep track of where this entity was last written or read */
/// we keep track of where this entity was last written or read
size_t write_ptr;
size_t write_size;
@ -510,13 +522,11 @@ class entity : public tms::entity
uint8_t protection_status;
void update_protection_status();
virtual void set_moveable(bool moveable)
{
virtual void set_moveable(bool moveable) {
this->set_flag(ENTITY_IS_MOVEABLE, moveable);
}
bool is_moveable()
{
bool is_moveable() {
return this->flag_active(ENTITY_IS_MOVEABLE);
}
@ -529,87 +539,130 @@ class entity : public tms::entity
uint64_t flags;
virtual uint32_t get_fixture_connection_data(b2Fixture *f){return 0;};
virtual uint32_t get_fixture_connection_data(b2Fixture *f) {
return 0;
}
inline bool flag_active(uint64_t flag)
{
inline bool flag_active(uint64_t flag) {
return this->flags & flag;
}
float get_total_mass()
{
float get_total_mass() {
float mass = 0.f;
b2Body *b;
for (int x=0; x<this->get_num_bodies(); x++) {
if ((b = this->get_body(x))) {
for (int x=0; x<this->get_num_bodies(); x++)
if ((b = this->get_body(x)))
mass += b->GetMass();
}
}
return mass;
}
inline void set_flag(uint64_t flag, bool v)
{
if (v) {
inline void set_flag(uint64_t flag, bool v) {
if (v)
this->flags |= flag;
} else {
else
this->flags &= ~flag;
}
}
/* Returns true if the entity has a wireless functionality, meaning it
* has at least one property and that first property is used for as
* a wireless frequency. */
inline bool is_wireless()
{
/// Returns true if the entity has a wireless functionality, meaning it
/// has at least one property and that first property is used for as
/// a wireless frequency.
inline bool is_wireless() {
return (this->g_id == O_RECEIVER || this->g_id == O_TRANSMITTER || this->g_id == O_MINI_TRANSMITTER);
}
inline bool is_item()
{
return (this->g_id == O_ITEM);
inline bool is_item() {
return this->g_id == O_ITEM;
}
inline bool is_prompt_compatible()
{
inline bool is_prompt_compatible() {
return this->flag_active(ENTITY_IS_PROMPT);
}
virtual bool is_zappable() { return this->flag_active(ENTITY_IS_ZAPPABLE); }
virtual bool is_zappable() {
return this->flag_active(ENTITY_IS_ZAPPABLE);
}
inline bool is_explosive() { return this->flag_active(ENTITY_IS_EXPLOSIVE); }
inline bool is_compressable() { return this->flag_active(ENTITY_CAN_BE_COMPRESSED); }
inline bool is_static() { return this->flag_active(ENTITY_IS_STATIC); }
inline bool is_bullet() { return this->flag_active(ENTITY_IS_BULLET); }
inline bool is_creature() { return this->flag_active(ENTITY_IS_CREATURE); }
inline bool is_robot() { return this->flag_active(ENTITY_IS_ROBOT); }
inline bool is_control_panel() { return this->flag_active(ENTITY_IS_CONTROL_PANEL); }
inline bool is_rc() { return this->flag_active(ENTITY_IS_CONTROL_PANEL); }
inline bool is_edevice() { return this->flag_active(ENTITY_IS_EDEVICE); }
inline bool is_interactive() { return this->flag_active(ENTITY_IS_INTERACTIVE); }
inline bool is_composable() { return this->flag_active(ENTITY_IS_COMPOSABLE); }
inline bool is_wheel() { return (this->type == ENTITY_WHEEL || this->type == ENTITY_GEAR); }
inline bool is_gearbox() { return (this->g_id == O_GEARBOX); }
inline bool allow_connections() { return this->flag_active(ENTITY_ALLOW_CONNECTIONS); }
inline bool has_tracker() { return this->flag_active(ENTITY_HAS_TRACKER); }
virtual bool is_locked() { return this->flag_active(ENTITY_IS_LOCKED); }
inline bool is_explosive() {
return this->flag_active(ENTITY_IS_EXPLOSIVE);
}
/// Can entity be compressed by the compressor item?
inline bool is_compressable() {
return this->flag_active(ENTITY_CAN_BE_COMPRESSED);
}
inline bool is_static() {
return this->flag_active(ENTITY_IS_STATIC);
}
inline bool is_bullet() {
return this->flag_active(ENTITY_IS_BULLET);
}
inline bool is_creature() {
return this->flag_active(ENTITY_IS_CREATURE);
}
inline bool is_robot() {
return this->flag_active(ENTITY_IS_ROBOT);
}
inline bool is_control_panel() {
return this->flag_active(ENTITY_IS_CONTROL_PANEL);
}
inline bool is_edevice() {
return this->flag_active(ENTITY_IS_EDEVICE);
}
inline bool is_interactive() {
return this->flag_active(ENTITY_IS_INTERACTIVE);
}
inline bool is_composable() {
return this->flag_active(ENTITY_IS_COMPOSABLE);
}
inline bool is_wheel() {
return (this->type == ENTITY_WHEEL || this->type == ENTITY_GEAR);
}
inline bool is_gearbox() {
return (this->g_id == O_GEARBOX);
}
inline bool allow_connections() {
return this->flag_active(ENTITY_ALLOW_CONNECTIONS);
}
inline bool has_tracker() {
return this->flag_active(ENTITY_HAS_TRACKER);
}
virtual bool is_locked() {
return this->flag_active(ENTITY_IS_LOCKED);
}
/// If this function returns true, then when the entity is to be deleted by
/// pressing Delete or the "remove entity" widget, a confirmation will be shown.
virtual bool requires_delete_confirmation() {
return false;
}
/* If this function returns true, then when the entity is to be deleted by
* pressing Delete or the "remove entity" widget, a confirmation will be shown. */
virtual bool requires_delete_confirmation() { return false; }
bool is_motor();
bool is_high_prio();
bool interacted_with; /* if the player has interacted with this entity
allows us to bypass auto protect and platform protect */
/// if the player has interacted with this entity.
/// allows us to bypass auto protect and platform protect
bool interacted_with;
entity();
virtual ~entity();
inline int sublayer_dist(entity *e)
{
inline int sublayer_dist(entity *e) {
int l0 = this->get_layer()*4;
int l1 = e->get_layer()*4;
@ -636,25 +689,33 @@ class entity : public tms::entity
virtual void prepare_fadeout();
virtual void ghost_update(){update();}
virtual void ghost_update() {
update();
}
virtual void construct(){}
virtual void construct() {}
virtual edevice *get_edevice(){return 0;}
virtual base_prompt *get_base_prompt(){return 0;}
virtual edevice *get_edevice() { return 0; }
virtual base_prompt *get_base_prompt() { return 0; }
virtual activator *get_activator() { return 0; }
void sidecheck(connection *c);
void sidecheck4(connection *cc);
/**
* Get all chunks that this entity is intersecting with
* We can get that info by looping through all bodies and checking their
* contacts.
*
* Static bodies don't collide with the sensors so for static bodies
* we instead calculate chunk intersection using width and height
*/
void get_chunk_intersections(std::set<chunk_pos> *chunks);
virtual void remove_connection(connection *cr);
virtual void destroy_connection(connection *cr);
virtual void disconnect_all();
b2Joint*
find_pivot(int dir, bool recursive)
{
b2Joint* find_pivot(int dir, bool recursive) {
if (this->is_wheel()) {
connection *c = this->conn_ll;
@ -673,20 +734,16 @@ class entity : public tms::entity
}
return 0;
};
}
inline void
add_connection(connection *c)
{
inline void add_connection(connection *c) {
//tms_infof("%p add connection %p", this, c);
connection *bkp = this->conn_ll;
this->conn_ll = c;
c->next[(this == c->e) ? 0:1] = bkp;
}
inline bool
connected_to(entity *e)
{
inline bool connected_to(entity *e) {
if (!this->conn_ll) return false;
connection *c = this->conn_ll;
@ -713,89 +770,81 @@ class entity : public tms::entity
int layer=-1
);
inline m* get_material(void)
{
inline m* get_material(void) {
return (m *)this->material;
}
virtual b2PolygonShape* get_resizable_shape(){return 0;};
virtual int get_resizable_vertices(int *out){return 0;};
virtual int get_resizable_edges(int *out){return 0;};
virtual bool on_resize_vertex(int v, b2Vec2 new_pos){return false;};
virtual bool on_resize_edge(int e, float movement){return false;};
virtual b2PolygonShape* get_resizable_shape() { return 0; }
virtual int get_resizable_vertices(int *out) { return 0; }
virtual int get_resizable_edges(int *out) { return 0; }
virtual bool on_resize_vertex(int v, b2Vec2 new_pos) { return false; }
virtual bool on_resize_edge(int e, float movement) { return false; }
virtual const char *get_slider_label(int s){return 0;};
virtual const char *get_slider_tooltip(int s){return 0;};
virtual float get_slider_snap(int s){return 0.f;};
virtual float get_slider_value(int s){return 0.f;};
virtual void on_slider_change(int s, float value){};
virtual const char *get_slider_label(int s) { return 0; }
virtual const char *get_slider_tooltip(int s) { return 0; }
virtual float get_slider_snap(int s) { return 0.f; }
virtual float get_slider_value(int s) {return 0.f; }
virtual void on_slider_change(int s, float value) {}
virtual entity *get_property_entity(void){return this;};
virtual entity *get_property_entity(void) {return this; }
virtual void update_effects(){};
virtual void update_effects() {}
virtual void update();
virtual void step(){};
virtual void mstep(){};
virtual void tick(){};
virtual void pre_step(){};
virtual void step() {}
virtual void mstep() {}
virtual void tick() {}
virtual void pre_step() {}
virtual void set_layer(int z);
void set_prio(int z);
// this is only fired in play-mode
virtual int handle_event(uint32_t type, uint64_t pointer_id, tvec2 pos){return EVENT_CONT;};
/// this is only fired in play-mode
virtual int handle_event(uint32_t type, uint64_t pointer_id, tvec2 pos) { return EVENT_CONT; }
virtual void set_position(float x, float y, uint8_t frame=0);
inline void set_position(b2Vec2 p, uint8_t frame=0) { set_position(p.x, p.y, frame); }
virtual b2Vec2 get_position();
virtual b2Vec2 get_position(uint8_t frame){return local_to_world(b2Vec2(0.f,0.f), frame);};
virtual b2Vec2 get_position(uint8_t frame) { return local_to_world(b2Vec2(0.f,0.f), frame); }
virtual void set_angle(float a);
virtual void set_angle(float a,uint8_t frame){set_angle(a);};
virtual void set_angle(float a,uint8_t frame) { set_angle(a); }
virtual float get_angle();
virtual float get_angle(uint8_t frame){return get_angle();};
virtual float get_angle(uint8_t frame) { return get_angle(); }
virtual void add_to_world()=0;
virtual void remove_from_world();
virtual void connection_create_joint(connection *c){};
virtual bool connection_destroy_joint(connection *c){return false;};
virtual void connection_create_joint(connection *c) { }
virtual bool connection_destroy_joint(connection *c) { return false; }
/* state reading/writing */
virtual void restore();
virtual void write_state(lvlinfo *lvl, lvlbuf *lb);
virtual void read_state(lvlinfo *lvl, lvlbuf *lb);
virtual void toggle_axis_rot(){};
virtual void toggle_axis_rot() {}
virtual void set_locked(bool locked, bool immediate=true);
virtual void load_flags(uint64_t f);
virtual uint64_t save_flags();
virtual bool get_axis_rot(){return this->flag_active(ENTITY_AXIS_ROT);};
virtual bool get_axis_rot() { return this->flag_active(ENTITY_AXIS_ROT); }
virtual const char *get_axis_rot_tooltip() { return "Toggle axis rotation"; }
virtual struct tms_sprite * get_axis_rot_sprite(){return 0;};
virtual struct tms_sprite * get_axis_rot_sprite() { return 0; }
/* "editor" events */
/* XXX */
virtual void on_grab(game *g);
virtual void on_release(game *g);
virtual void on_grab_playing(){};
virtual void on_release_playing(){};
virtual void on_grab_playing() {}
virtual void on_release_playing() {}
virtual void on_touch(b2Fixture *my, b2Fixture *other);
virtual void on_untouch(b2Fixture *my, b2Fixture *other);
virtual void on_paused_touch(b2Fixture *my, b2Fixture *other){};
virtual void on_paused_untouch(b2Fixture *my, b2Fixture *other){};
virtual void on_paused_touch(b2Fixture *my, b2Fixture *other) {}
virtual void on_paused_untouch(b2Fixture *my, b2Fixture *other) {}
/*
virtual void collision_begin(b2Contact *c, int order) = 0;
virtual void collision_presolve(b2Contact *c, int order) = 0;
virtual void collision_postsolve(b2Contact *c, int order) = 0;
virtual void collision_end(b2Contact *c, int order) = 0;
*/
inline int get_layer(){return this->prio;};
inline int get_layer() { return this->prio; }
virtual bool compatible_with(entity *o);
@ -809,12 +858,11 @@ class entity : public tms::entity
virtual uint32_t get_num_bodies();
virtual b2Body *get_body(uint8_t frame);
virtual void find_pairs(){};
virtual void find_pairs() {}
virtual const char *get_name(void) = 0;
virtual const char *get_real_name(void)
{
virtual const char *get_real_name(void) {
return this->get_name();
}
@ -823,42 +871,36 @@ class entity : public tms::entity
virtual void write_object_id(char *out);
virtual void pre_write(void);
virtual void post_write(void){};
virtual void on_load(bool created, bool has_state){};
virtual connection* load_connection(connection &conn){return 0;};
virtual void post_write(void) {}
virtual void on_load(bool created, bool has_state) {}
virtual connection* load_connection(connection &conn) { return 0; }
inline void initialize_interactive(void)
{
inline void initialize_interactive(void) {
this->in_dragfield = 0;
this->interactive_hp = 1.f;
};
}
/* Init is always called, regardless if the entity
* has a state to be loaded or not. */
virtual void init() {};
/// Init is always called, regardless if the entity has a state to be loaded or not.
virtual void init() {}
/* Setup is called after init if the entity has no
* state to load from */
virtual void setup()
{
/// Setup is called after init if the entity has no state to load from
virtual void setup() {
this->listeners.clear();
this->subscriptions.clear();
};
}
virtual void on_pause()
{
virtual void on_pause() {
this->subscriptions.clear();
this->listeners.clear();
};
}
virtual void on_absorb() {};
virtual void on_absorb() {}
inline void on_entity_play()
{
inline void on_entity_play() {
this->interacted_with = false;
}
virtual bool allow_connection(entity *asker, uint8_t frame, b2Vec2 p){return true;};
virtual bool allow_connection(entity *asker, uint8_t frame, b2Vec2 p) { return true; }
virtual bool enjoys_connection(uint32_t g_id) { return false; }
/* Zappable stuff */
@ -873,16 +915,14 @@ class entity : public tms::entity
void set_property(uint8_t id, uint32_t v);
void set_property(uint8_t id, const char *v);
void set_propertyi8(uint8_t id, uint8_t v);
inline void set_property(uint8_t id, uint8_t v){set_property(id, (uint32_t)v);};
inline void set_property(uint8_t id, uint16_t v){set_property(id, (uint32_t)v);};
inline void set_property(uint8_t id, uint8_t v) { set_property(id, (uint32_t)v); }
inline void set_property(uint8_t id, uint16_t v) { set_property(id, (uint32_t)v); }
void set_property(uint8_t id, const char *v, uint32_t len);
void set_num_properties(uint8_t num);
void reset_flags(void);
/* this takes a value between 0.0 and 1.0 and converts it to the proper density scale value */
void help_set_density_scale(float value)
{
/// this takes a value between 0.0 and 1.0 and converts it to the proper density scale value
void help_set_density_scale(float value) {
this->set_density_scale(ENTITY_DENSITY_SCALE_MIN + value*(ENTITY_DENSITY_SCALE_MAX-ENTITY_DENSITY_SCALE_MIN));
}
@ -890,7 +930,7 @@ class entity : public tms::entity
static tvec2 get_nearest_point(const b2Vec2 &query_point, b2Fixture *fx);
virtual void set_density_scale(float v) {}
virtual float get_density_scale(){return 1.f;};
virtual float get_density_scale() { return 1.f; }
virtual uint32_t get_sub_id() { return 0; }
@ -899,19 +939,17 @@ class entity : public tms::entity
friend class connection;
};
class entity_simpleconnect : public entity, public b2RayCastCallback
{
class entity_simpleconnect : public entity, public b2RayCastCallback {
public:
b2Vec2 query_pt;
b2Vec2 query_vec; /* Set in the constructor of the
object, direction of raycast */
/// Set in the constructor of the object, direction of raycast
b2Vec2 query_vec;
entity *query_result;
b2Fixture *query_result_fx;
uint8_t query_frame;
connection c;
entity_simpleconnect()
{
entity_simpleconnect() {
this->c.init_owned(0, this);
this->c.type = CONN_GROUP;
this->query_vec = b2Vec2(0.f, -.5f);
@ -923,13 +961,11 @@ class entity_simpleconnect : public entity, public b2RayCastCallback
void find_pairs();
};
class entity_multiconnect : public entity
{
class entity_multiconnect : public entity {
public:
connection c_side[4];
entity_multiconnect()
{
entity_multiconnect() {
this->c_side[0].init_owned(0, this); this->c_side[0].type = CONN_GROUP;
this->c_side[1].init_owned(1, this); this->c_side[1].type = CONN_GROUP;
this->c_side[2].init_owned(2, this); this->c_side[2].type = CONN_GROUP;
@ -940,21 +976,4 @@ class entity_multiconnect : public entity
void find_pairs();
};
class ghost : public entity, public b2QueryCallback
{
public:
connection c;
ghost();
void update();
const char *get_name(){return "Shape Extruder";};
void init();
bool ReportFixture(b2Fixture *f);
void find_pairs();
void add_to_world();
connection* load_connection(connection &conn);
void connection_create_joint(connection *c);
bool connection_destroy_joint(connection *c);
};
void entity_fast_update(struct tms_entity *t);

View file

@ -53,6 +53,7 @@
#include "screenshot_marker.hh"
#include "scup.hh"
#include "settings.hh"
#include "shape_extruder.hh"
#include "simplebg.hh"
#include "soundman.hh"
#include "soundmanager.hh"
@ -3349,7 +3350,7 @@ game::render()
case O_SHAPE_EXTRUDER: {
// Draw bounding box of Shape extruder
ghost *g = static_cast<ghost*>(this->selection.e);
shape_extruder *g = static_cast<shape_extruder*>(this->selection.e);
if (g->conn_ll) {
tms_ddraw_set_color(this->dd, 0.0f, 0.0f, 1.0f, 1.0f);
composable *other = static_cast<composable*>(g->c.o);
@ -4930,7 +4931,7 @@ game::set_control_panel(entity *e)
wdg_misc_i = 0;
if (this->current_panel) {
if (this->current_panel->is_rc()) {
if (this->current_panel->is_control_panel()) {
/* If we are already connected to a panel and it's an RC,
* call the panel_disconnected for the RC.
*
@ -4968,7 +4969,7 @@ game::set_control_panel(entity *e)
return;
}
panel *p = (e && e->is_rc() ? static_cast<panel*>(e) : 0);
panel *p = (e && e->is_control_panel() ? static_cast<panel*>(e) : 0);
creature *c = (e && e->is_creature() ? static_cast<creature*>(e) : 0);
this->current_panel = e;

View file

@ -107,6 +107,7 @@
#include "seesaw.hh"
#include "sequencer.hh"
#include "sfxemitter.hh"
#include "shape_extruder.hh"
#include "shelf.hh"
#include "sincos.hh"
#include "sinewave.hh"
@ -351,7 +352,7 @@ static entity* new_snap(void){return new snapgate();};
static entity* new_var_getter(void){return new var_getter();};
static entity* new_var_setter(void){return new var_setter();};
static entity* new_sequencer(void){return new sequencer();};
static entity* new_ghost(void){return new ghost();};
static entity* new_shape_extruder(void){return new shape_extruder();};
static entity* new_cursorfield(void){return new cursorfield();};
static entity* new_escript(void){return new escript();};
static entity* new_ldecay(void){return new ldecay();};
@ -574,7 +575,7 @@ static entity* (*c_creator[])(void) = {
&new_var_setter,
&new_snap,
&new_sequencer,
&new_ghost, /* 180 */
&new_shape_extruder, /* 180 */
&new_ldecay,
&new_elimit,
&new_cursorfield,

171
src/shape_extruder.cc Normal file
View file

@ -0,0 +1,171 @@
#include "shape_extruder.hh"
#include "entity.hh"
#include "game.hh"
#include "model.hh"
#include "ui.hh"
shape_extruder::shape_extruder() {
this->set_flag(ENTITY_IS_BETA, true);
this->set_flag(ENTITY_ALLOW_CONNECTIONS, false);
this->set_flag(ENTITY_ALLOW_ROTATION, false);
this->set_flag(ENTITY_HAS_CONFIG, true);
this->dialog_id = DIALOG_SHAPEEXTRUDER;
this->set_mesh(mesh_factory::get_mesh(MODEL_BOX0));
this->set_material(&m_red);
this->layer_mask = 1;
this->update_method = ENTITY_UPDATE_CUSTOM;
this->set_num_properties(4);
this->properties[0].type = P_FLT;
this->properties[0].v.f = 0.f; /* extra right */
this->properties[1].type = P_FLT;
this->properties[1].v.f = 0.f; /* extra up */
this->properties[2].type = P_FLT;
this->properties[2].v.f = 0.f; /* extra left */
this->properties[3].type = P_FLT;
this->properties[3].v.f = 1.f; /* extra down */
this->c.init_owned(0, this);
this->c.type = CONN_CUSTOM;
}
connection *shape_extruder::load_connection(connection &conn) {
this->c = conn;
return &this->c;
}
void shape_extruder::update() {
if (G && !W->is_paused()) {
// Hide the object when in-game
memset(this->M, 0, sizeof(float)*16);
return;
}
entity *ths = static_cast<entity*>(this);
if (ths->body) {
b2Transform t;
t = ths->body->GetTransform();
tmat4_load_identity(ths->M);
ths->M[0] = t.q.c;
ths->M[1] = t.q.s;
ths->M[4] = -t.q.s;
ths->M[5] = t.q.c;
ths->M[12] = t.p.x;
ths->M[13] = t.p.y;
ths->M[14] = ths->prio * LAYER_DEPTH;
tmat3_copy_mat4_sub3x3(ths->N, ths->M);
} else {
//tms_infof("rendering with _pos");
tmat4_load_identity(ths->M);
tmat4_translate(ths->M, ths->_pos.x, ths->_pos.y, 0);
tmat4_rotate(ths->M, ths->_angle * (180.f/M_PI), 0, 0, -1);
tmat3_copy_mat4_sub3x3(ths->N, ths->M);
/* XXX rotate */
}
}
void shape_extruder::connection_create_joint(connection *c) {
c->j = (b2Joint*)1;
c->max_force = INFINITY;
if (W->is_paused()) {
b2WeldJointDef wjd;
wjd.localAnchorA = c->e->local_to_body(b2Vec2(0.f, 0.f), c->f[0]);
wjd.localAnchorB = c->o->local_to_body(b2Vec2(0.f, 0.f), c->f[1]);
wjd.bodyA = c->e->get_body(c->f[0]);
wjd.bodyB = c->o->get_body(c->f[1]);
wjd.referenceAngle = c->o->get_body(c->f[1])->GetAngle() - c->e->get_body(c->f[0])->GetAngle();
wjd.collideConnected = false;
wjd.frequencyHz = 0.f;
c->j = W->b2->CreateJoint(&wjd);
}
}
bool shape_extruder::connection_destroy_joint(connection *c) {
return !(c->j != (void*)1 && c->j != 0);
}
bool shape_extruder::ReportFixture(b2Fixture *f) {
entity *e = static_cast<entity*>(f->GetUserData());
if (e && e != this) {
uint8_t frame = (uint8_t)(uintptr_t)(f->GetBody()->GetUserData());
if (this->c.pending && frame == 0 && e->get_body(frame)->GetFixtureList()[0].TestPoint(this->get_position())
&& e->flag_active(ENTITY_IS_COMPOSABLE)
&& e->get_layer() == this->get_layer()) {
this->c.type = CONN_CUSTOM;
this->c.o = e;
this->c.p = e->get_position();
this->c.o_data = e->get_fixture_connection_data(f);
G->add_pair(this, e, &this->c);
}
}
return true;
}
void shape_extruder::init() {
//this->create_rect(w, b2_dynamicBody, .5f, .5, this->material);
if (this->conn_ll && this->c.o && this->c.o->flag_active(ENTITY_IS_COMPOSABLE)) {
composable *other = static_cast<composable*>(this->c.o);
if (!other)
return;
float w = other->get_width();
float h = other->height;
b2Filter f = other->fx->GetFilterData();
f.groupIndex = 1+this->get_layer();
other->fx->SetFilterData(f);
//other->fx->SetSensor(true);
b2PolygonShape sh;
b2Vec2 vertices[4] = {
other->local_to_body(b2Vec2(w+this->properties[0].v.f, h+this->properties[1].v.f), 0),
other->local_to_body(b2Vec2(-(w+this->properties[2].v.f), h+this->properties[1].v.f), 0),
other->local_to_body(b2Vec2(-(w+this->properties[2].v.f), -(h+this->properties[3].v.f)), 0),
other->local_to_body(b2Vec2(w+this->properties[0].v.f, -(h+this->properties[3].v.f)), 0)
};
sh.Set(vertices, 4);
b2FixtureDef fd;
fd.shape = &sh;
fd.density = 0.00001f;
fd.friction = other->fd.friction;
fd.restitution = other->fd.restitution;
fd.filter = other->fd.filter;
fd.filter.groupIndex = -(1+this->get_layer());
other->get_body(0)->CreateFixture(&fd)->SetUserData(other);
}
}
void shape_extruder::find_pairs() {
b2AABB aabb;
b2Vec2 p = this->get_position();
aabb.lowerBound = b2Vec2(p.x-.1f, p.y-.1f);
aabb.upperBound = b2Vec2(p.x+.1f, p.y+.1f);
W->b2->QueryAABB(this, aabb);
}
void shape_extruder::add_to_world() {
if (W->is_paused()) {
this->create_rect(b2_dynamicBody, .25f, .25f, this->material);
this->body->GetFixtureList()[0].SetSensor(true);
}
}

19
src/shape_extruder.hh Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include "entity.hh"
class shape_extruder : public entity, public b2QueryCallback {
public:
connection c;
shape_extruder();
void update();
const char *get_name() { return "Shape Extruder"; }
void init();
bool ReportFixture(b2Fixture *f);
void find_pairs();
void add_to_world();
connection* load_connection(connection &conn);
void connection_create_joint(connection *c);
bool connection_destroy_joint(connection *c);
};