123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- /*
- A Thing is anything that "physically exists" in an Area, that is, a "level".
- */
- #include "thing.h"
- #include "area.h"
- #include "flags.h"
- #include "draw.h"
- #include "mem.h"
- #include "monolog.h"
- #include "thing_struct.h"
- #define THING_WALL_MASS INFINITY
- #define THING_ACTOR_MASS 1.0
- /** Gets the ID of the thing. Returns negative on error or for a
- thing that doesn't belong to an area yet.*/
- int thing_id(Thing * thing) {
- if (!thing) return -3;
- return thing->id;
- }
- /** Sets the ID of the thing. Returns negative on error or
- for a thing that doesn't belong to an area yet (as inicated by newid)
- */
- int thing_id_(Thing * thing, int newid) {
- if (!thing) return -3;
- return thing->id = newid;
- }
- /** Sets the z value of the Thing. This influences which layer it
- and, if set, it's Shape is in. Logically,
- there are 4 layers in every area, 2 bottom ones and 2 top ones.
- Layer 0 is for the floor or walls itself, layer 1 for things that
- are standing or lying on the floor, or for edges,
- layer 2 is for things on the "top floor", that is, another
- floor above the current one which may be used for bridges,
- overpasess, etc. Layer 3 is then for things standing
- or lying on that top layer.
- */
- Thing * thing_z_(Thing * self, int z) {
- if (!self) return NULL;
- self->z = z;
- if(self->hull) {
- bumphull_layers_(self->hull, 1 << z);
- }
- return self;
- }
- /** Sets an individual flag on the Thing. */
- int thing_setflag(Thing * self, int flag) {
- return flags_set(&self->flags, flag);
- }
- /** Unsets an individual flag on the Thing. */
- int thing_unsetflag(Thing * self, int flag) {
- register int wflags = self->flags;
- return flags_unset(&self->flags, flag);
- }
- /** Sets or unsets an individual flag on the Thing.
- If set is true the flag is set, if false it's unset. */
- int thing_flag_(Thing * self, int flag, int set) {
- return flags_put(&self->flags, flag, set);
- }
- /** Checks if an individual flag is set. */
- int thing_flag(Thing * self, int flag) {
- return flags_get(self->flags, flag);
- }
- /** Uninitializes a thing. */
- Thing * thing_done(Thing * self) {
- if(!self) return NULL;
- bumphull_free(self->hull);
- bumpbody_free(self->physical);
- self->physical= NULL;
- self->hull = NULL;
- self->area = NULL;
- self->z = -1;
- self->kind = THING_UNUSED;
- spritestate_done(&self->spritestate);
- return self;
- }
- /** Frees a thing. */
- Thing * thing_free(Thing * self) {
- thing_done(self);
- mem_free(self);
- return NULL;
- }
- /** Allocates a Thing. */
- Thing * thing_alloc() {
- return STRUCT_ALLOC(Thing);
- }
- /* Sets the sprite of a thing. */
- Sprite * thing_sprite_(Thing * thing, Sprite * sprite) {
- if (!thing) return NULL;
- return spritestate_sprite_(&thing->spritestate, sprite);
- }
- /* Gets the sprite of a thing. */
- Sprite * thing_sprite(Thing * thing) {
- if (!thing) return NULL;
- return spritestate_sprite(&thing->spritestate);
- }
- /* Sets the pose of the sprite state of a thing. The direction is
- kept the same as it was. */
- int thing_pose_(Thing * thing, int pose) {
- if (!thing) return -3;
- return spritestate_pose_(&thing->spritestate, pose);
- }
- /* Sets the direction of the sprite state of a thing. The pose is
- kept the same as it was. */
- int thing_direction_(Thing * thing, int direction) {
- if (!thing) return -3;
- return spritestate_direction_(&thing->spritestate, direction);
- }
- /** Generic initialization of a thing Initializes a Thing.
- Sets the given values and some flags. Links the Shape given
- to the Thing if shape is not NULL.
- Does NOT call area_addthing on the given area.
- Returns null if that failed, but does no cleanup. */
- Thing * thing_init_generic(Thing * self, Area * area, int id, int kind, int z,
- BumpBody * body, BumpHull * shape) {
- if(!self) return NULL;
- self->kind = kind;
- self->id = id;
- self->area = area;
- self->physical= body;
- self->hull = shape;
- self->flags = 0;
- thing_z_(self, z);
- spritestate_init(&self->spritestate, NULL, self);
-
- /* If the thing has a body and it is not static,
- assume it is owned by this thing and must be freed when calling
- thing_done.
- */
- bumpbody_data_(self->physical, self);
- return self;
- }
- /** Initializes a rectangular, static, non-rotating Thing. Uses the
- area's static body, and makes a new rectangular shape for it.
- Returns NULL on error. Uses the area's static body.
- thing_initstatic isn't needed since bump understands tile maps.
- */
- /** Initializes a rectangular, dynamic, non-rotating Thing, with mass 1
- and makes a new body and rectangular shape for it. Returns NULL on error.
- Uses the area's static body. */
- Thing * thing_init_dynamic(Thing * self, Area * area,
- int id, int kind, int x, int y, int z, int w, int h) {
- BumpBody * body = NULL;
- BumpHull * shape = NULL;
- BeVec pos , delta;
- BumpAABB bounds;
- if(!self) return NULL;
- if(!area) return NULL;
- pos = bevec(x, y);
- body = bumpbody_new(pos, 1.0);
- if(!body) goto out_of_memory;
- // dynamic things ARE positioned correctly and do not use an offset
- // the object's shape is locally around the body
- bounds = bumpaabb(x, y, w, h);
- delta = bevec0();
- shape = bumphull_newall(body, delta, bounds, 1 << z, kind);
- if(!shape) goto out_of_memory;
- return thing_init_generic(self, area, id, kind, z, body, shape);
-
- out_of_memory:
- bumpbody_free(body);
- thing_done(self);
- return NULL;
- }
- /** Allocates and initializes a new static Thing. Not needed anymore. */
- /* thing_newstatic */
- /** Allocates and initializes a new dynamic Thing. */
- Thing * thing_new_dynamic(Area * area,
- int id, int kind,
- int x, int y, int z, int w, int h) {
- Thing * self = thing_alloc();
- if(!thing_init_dynamic(self, area, id, kind, x, y, z, w, h)) {
- return thing_free(self);
- }
- return self;
- }
- /** Accessors for thing's properties, forwarded to the body
- of the thing. **/
- /** Position of the thing. */
- BeVec thing_p(Thing * self) {
- return bumpbody_p(self->physical);
- }
- /** Bounds box of the thing */
- BumpAABB thing_aabb(Thing *self) {
- return bumphull_aabb(self->hull);
- }
- /** Width of thing. */
- int thing_w(Thing * self) {
- return thing_aabb(self).hs.x * 2;
- }
- /** Height of thing. */
- int thing_h(Thing * self) {
- return thing_aabb(self).hs.y * 2;
- }
- /** Position X coordinates (top left). */
- int thing_x(Thing * self) {
- return thing_p(self).x - thing_aabb(self).hs.x ;
- }
- /** Position Y coordinates (top left). */
- int thing_y(Thing * self) {
- return thing_p(self).y - thing_aabb(self).hs.y ;
- }
- /** Position X coordinates (center). */
- int thing_cx(Thing * self) {
- return thing_p(self).x;
- }
- /** Position Y coordinates (center). */
- int thing_cy(Thing * self) {
- return thing_p(self).y;
- }
- /** Layer of thing. */
- int thing_z(Thing * self) {
- return self->z;
- }
- /** Velocity of the thing. */
- BeVec thing_v(Thing * self) {
- return bumpbody_v(self->physical);
- }
- /** Speed X coordinates. */
- int thing_vx(Thing * self) {
- return thing_v(self).x;
- }
- /** Speed Y coordinates. */
- int thing_vy(Thing * self) {
- return thing_v(self).y;
- }
- /** Set velocity. */
- void thing_v_(Thing * self, BeVec v) {
- bumpbody_v_(self->physical, v);
- }
- /** Set velocity by xy. */
- void thing_vxy_(Thing * self, int vx, int vy) {
- BeVec v = bevec(vx, vy);
- thing_v_(self, v);
- }
- /** Set x velocity only, leaving y unchanged . */
- void thing_vx_(Thing * self, int vx) {
- BeVec v = thing_v(self);
- v.x = vx;
- thing_v_(self, v);
- }
- /** Set y velocity only, leaving x unchanged . */
- void thing_vy_(Thing * self, int vy) {
- BeVec v = thing_v(self);
- v.y = vy;
- thing_v_(self, v);
- }
- /** Sets position of thing's body. */
- void thing_p_(Thing * self, BeVec p) {
- bumpbody_p_(self->physical, p);
- }
- /** Adds delta to the position of thing's body. */
- void thing_deltap(Thing * self, BeVec delta) {
- BeVec old = thing_p(self);
- thing_p_(self, bevec_add(old, delta));
- }
- /** Set position by xy. */
- void thing_pxy_(Thing * self, int x, int y) {
- BeVec p = bevec(x, y);
- thing_p_(self, p);
- }
- /** Set x velocity only, leaving y unchanged . */
- void thing_x_(Thing * self, int x) {
- BeVec p = thing_p(self);
- p.x = x;
- thing_p_(self, p);
- }
- /** Set x velocity only, leaving y unchanged . */
- void thing_y_(Thing * self, int y) {
- BeVec p = thing_p(self);
- p.y = y;
- thing_p_(self, p);
- }
- /** Applies a force on the center of gravity of the thing. */
- void thing_applyforce(Thing * thing, const BeVec f) {
- bumpbody_applyforce(thing->physical, f);
- }
- /** Applies an impulse on the center of gravity of the thing. */
- void thing_applyimpulse(Thing * thing, const BeVec f) {
- bumpbody_applyimpulse(thing->physical, f);
- }
- /* Resets the force on this thing to 0. */
- void thing_resetforces(Thing * thing) {
- bumpbody_resetforces(thing->physical);
- }
- /* Returns the position of self, works both for static and dynamic things.
- * Redundant but kept for backcompat.
- */
- BeVec thing_sdp(Thing * self) {
- return thing_p(self);
- }
- /* Draws a thing to the current active drawing target, corresponding
- to it's shape and kind and taking the camera into account. Useful for
- checking or debugging the physics. */
- void thing_draw(Thing * self, Camera * camera) {
- int cx ;
- int cy ;
- int drawx, x;
- int drawy, y;
- int w, h ;
- int sw, sh ;
- int sx, sy ;
- int t = 2;
- Color color;
- // don't draw null things.
- if(!self) return;
- cx = camera_at_x(camera);
- cy = camera_at_y(camera);
- w = self->size.x;
- h = self->size.y;
- if ((self->physical) && (self->hull)) {
- x = bumpbody_p(self->physical).x - bumphull_aabb(self->hull).hs.x;
- y = bumpbody_p(self->physical).y - bumphull_aabb(self->hull).hs.y;
- w = bumphull_aabb(self->hull).hs.x * 2;
- h = bumphull_aabb(self->hull).hs.y * 2;
- }
-
- color = color_rgba(0xee, 0x44, 0x00, 0x88);
- t = 8;
- /* Do not draw out of camera range. */
- if(!camera_cansee(camera, x, y, w, h)) {
- return;
- }
- drawx = x - cx;
- drawy = y - cy;
- /* Draw sprite if available... */
- if(spritestate_can_draw_p(&self->spritestate)) {
- BeVec spriteat = bevec(drawx, drawy);
- /* Draw elliptical shadow under sprite unless disabled */
- if (!(self->flags & THING_FLAGS_NO_SHADOW)) {
- color = color_rgbaf(0.0, 0.0, 0.0, 0.5);
- sx = drawx + w / 2;
- sy = drawy + ((4*h)/5);
- sw = (4 * w) / 11;
- sh = h / 3;
- al_draw_filled_ellipse(sx, sy, sw, sh, color);
- }
- spritestate_draw(&self->spritestate, &spriteat);
- } else {
- /* ... otherwise debug box to alert scripters of it's absence. */
- draw_box(drawx, drawy, w, h, color, t);
- }
- }
- /* Returns the direction the sprite of this thing is currently facing */
- int thing_direction(Thing * self) {
- if (!self) return SPRITE_NO_DIRECTION;
- return spritestate_direction(&self->spritestate);
- }
- /* Returns the pose of the sprite of this thing */
- int thing_pose(Thing * self) {
- if (!self) return SPRITE_STAND;
- return spritestate_pose(&self->spritestate);
- }
- /* Changes the pose to newpose but only if it's oldpose.
- * Returns negative if the pose wasn't changed. */
- int thing_poseifold_(Thing * self, int oldpose, int newpose) {
- if (thing_pose(self) == oldpose) {
- return thing_pose_(self, newpose);
- }
- return -1;
- }
- /* Updates the thing, especialy it's spite state direction and animation. */
- void thing_update(Thing * self, double dt) {
- /* Update the things layer if uit has no support under hit's feet and
- it's level is greater than 1 and it's flying. */
- if ((thing_z(self) > 1) && (self->hull)) {
- if(!bumphull_support(self->hull)) {
- /* No support, drop down. */
- thing_z_(self, 1);
- }
- }
-
- if(!flags_get(self->flags, THING_FLAGS_LOCK_DIRECTION)) {
- int newdir;
- BeVec vel = thing_v(self);
- double magnitude = bevec_length(vel);
- if (fabs(magnitude) > 0.00) {
- /* could change dir if moving. TODO: take the old direction into
- account for more control of facing when moving diagonally. */
- if (vel.x < -0.01) {
- newdir = SPRITE_WEST;
- } else if (vel.x > 0.01) {
- newdir = SPRITE_EAST;
- } else if (vel.y < -0.01) {
- newdir = SPRITE_NORTH;
- } else if (vel.y > 0.01) {
- newdir = SPRITE_SOUTH;
- } else { /* Not much motion, don't change dir */
- newdir = thing_direction(self);
- }
- /* Change direction. spritestate_pose will see if nothing changed and do nothing. in that case */
- thing_poseifold_(self, SPRITE_STAND, SPRITE_WALK);
- thing_direction_(self, newdir);
- } else {
- thing_poseifold_(self, SPRITE_WALK, SPRITE_STAND);
- /* This won't work on attacking, etc. */
- }
- } else {
- LOG("Thing direction locked!");
- }
-
- spritestate_update(&self->spritestate, dt);
- }
- /* Compares a thing with another, for drawing order. Things with low
- z come before those with high z, and with same z, low y comes before high y.
- qsort compatible. */
- int thing_compare_for_drawing(const void * p1, const void * p2) {
- Thing * self = *((Thing **) p1);
- Thing * other = *((Thing **) p2);
- BeVec pos1, pos2;
- if(!self) {
- if(!other) {
- return 0;
- }
- /* Sort nulls to the back. */
- return 1;
- }
- if(!self) return -1;
- /* Compare Z if no nulls. */
- if (self->z < other->z) return -1;
- if (self->z > other->z) return 1;
- pos1 = thing_sdp(self);
- pos2 = thing_sdp(other);
- /* compare y if z is equal */
- if ( pos1.y < pos2.y ) return -1;
- if ( pos1.y > pos2.y ) return 1;
- /* Compare by address or whatever*/
- if (((uintptr_t)p1) < ((uintptr_t)p2)) return -1;
- if (((uintptr_t)p1) > ((uintptr_t)p2)) return 1;
- if (((uintptr_t)p1) == ((uintptr_t)p2)) return 0;
- return 0;
- }
- /** Tints a layer in the sprite's state of this thing. */
- int thing_tint_layer(Thing * me, int layer_index, Color color) {
- if (!me) return -1;
- return spritestate_tint_layer(&me->spritestate, layer_index, color);
- }
- /** Hides or shows a layer in he sprite of this thing. */
- int thing_hide_layer(Thing * me, int layer, int hidden) {
- if (!me) return -1;
- return spritestate_set_layer_hidden(&me->spritestate, layer, hidden);
- }
- /** Returns true if the layer of the sprite is hidden false if not. */
- int thing_is_layer_hidden(Thing * me, int layer) {
- return spritestate_get_layer_hidden(&me->spritestate, layer);
- }
- /** Sets the loop mode of the given action of the thing. */
- int thing_set_action_loop(Thing * me, int action, int loopmode) {
- return spritestate_set_action_loop(&me->spritestate, action, loopmode);
- }
- /** Gets the loop mode of the given action of the thing. */
- int thing_get_action_loop(Thing * me, int action) {
- return spritestate_get_action_loop(&me->spritestate, action);
- }
- /** Checks if the given action is done in case of actions set to one-shot
- * loop mode only.
- */
- int thing_is_action_done(Thing * me, int action) {
- return spritestate_is_action_done(&me->spritestate, action);
- }
- /** Sets the loop mode for the given pose and direction of the thing. */
- int thing_set_pose_direction_loop
- (Thing * me, int pose, int direction, int loopmode) {
- return spritestate_set_pose_direction_loop(&me->spritestate, pose, direction, loopmode);
- }
- /** Gets the loop mode for the given pose and direction of the thing. */
- int thing_get_pose_direction_loop
- (Thing * me, int pose, int direction) {
- return spritestate_get_pose_direction_loop(&me->spritestate, pose, direction);
- }
- /** Sets a flag on the main hull of the Thing. */
- int thing_set_hull_flag(Thing * me, int flag) {
- if (!me) return 0;
- return bumphull_set_flag(me->hull, flag);
- }
- /** Unsets a flag for the main hull of the thing. */
- int thing_unset_hull_flag(Thing * me, int flag) {
- if (!me) return 0;
- return bumphull_unset_flag(me->hull, flag);
- }
- /** Sets all flags for the main hull of the thing. */
- int thing_hull_flags_(Thing * me, int flags) {
- if (!me) return 0;
- return bumphull_flags_(me->hull, flags);
- }
- /** Gets all flags for the main hull of the thing. */
- int thing_hull_flags(Thing * me) {
- if (!me) return 0;
- return bumphull_flags(me->hull);
- }
- /** Returns the group of the main hull of the thing. */
- int thing_hull_group(Thing * me) {
- if (!me) return -1;
- return bumphull_group(me->hull);
- }
- /** Sets the group of the main hull of the thing. */
- int thing_hull_group_(Thing * me, int group) {
- if (!me) return -1;
- return bumphull_group_(me->hull, group);
- }
|