888 lines
30 KiB
C++
888 lines
30 KiB
C++
#include "actor.h"
|
|
#include "jdraw.h"
|
|
#include "jinput.h"
|
|
#include "room.h"
|
|
#include <vector>
|
|
|
|
namespace actor
|
|
{
|
|
uint8_t anims[2][4] = {
|
|
{0, 1, 0, 2},
|
|
{0, 1, 2, 3}
|
|
};
|
|
|
|
actor_t *first = nullptr;
|
|
actor_t *dirty = nullptr;
|
|
actor_t *selected = nullptr;
|
|
|
|
actor_t *getFirst()
|
|
{
|
|
return first;
|
|
}
|
|
|
|
actor_t *getSelected()
|
|
{
|
|
return selected;
|
|
}
|
|
|
|
actor_t *create(std::string name, vec3_t p, vec3_t s, std::string bmp, SDL_Rect r, SDL_Point o)
|
|
{
|
|
actor_t *act = (actor_t*)malloc(sizeof(actor_t));
|
|
strcpy(act->name, name.c_str());
|
|
strcpy(act->bmp, bmp.c_str());
|
|
act->pos = p;
|
|
act->size = s;
|
|
act->surface = draw::loadSurface(bmp.c_str());
|
|
act->bmp_rect = r;
|
|
act->bmp_offset = o;
|
|
act->anim_cycle = act->orient = 0;
|
|
act->push = act->mov_push = PUSH_NONE;
|
|
act->below = act->above = nullptr;
|
|
act->prev = act->next = nullptr;
|
|
act->anim_wait = act->anim_wait_count = 0;
|
|
act->anim_frame=0;
|
|
act->react_mask = act->react_push = 0;
|
|
return act;
|
|
}
|
|
|
|
const bool check_2d_collision(actor_t *obj1, actor_t *obj2)
|
|
{
|
|
return (obj1->pos.x < obj2->pos.x + obj2->size.x) &&
|
|
(obj1->pos.x + obj1->size.x > obj2->pos.x ) &&
|
|
(obj1->pos.y < obj2->pos.y + obj2->size.y) &&
|
|
(obj1->pos.y + obj1->size.y > obj2->pos.y );
|
|
}
|
|
|
|
const bool is_above(actor_t *obj1, actor_t *obj2)
|
|
{
|
|
return check_2d_collision(obj1, obj2) && (obj1->pos.z==obj2->pos.z+obj2->size.z);
|
|
}
|
|
|
|
actor_t *any_above_me(actor_t *act)
|
|
{
|
|
actor_t *other = first;
|
|
while (other)
|
|
{
|
|
if (is_above(other, act)) return other;
|
|
other = other->next;
|
|
if (other == act) other = other->next;
|
|
}
|
|
other = dirty;
|
|
while (other)
|
|
{
|
|
if (is_above(other, act)) return other;
|
|
other = other->next;
|
|
if (other == act) other = other->next;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
actor_t *any_below_me(actor_t *act)
|
|
{
|
|
actor_t *other = first;
|
|
while (other)
|
|
{
|
|
if (is_above(act, other)) return other;
|
|
other = other->next;
|
|
if (other == act) other = other->next;
|
|
}
|
|
other = dirty;
|
|
while (other)
|
|
{
|
|
if (is_above(act, other)) return other;
|
|
other = other->next;
|
|
if (other == act) other = other->next;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void setDirty(actor_t *act, const bool force)
|
|
{
|
|
|
|
if (act->prev==nullptr && act != first && !force) return;
|
|
|
|
if (act->prev) act->prev->next = act->next;
|
|
if (act->next) act->next->prev = act->prev;
|
|
if (act == first) first = act->next;
|
|
|
|
act->prev = nullptr;
|
|
act->next = dirty;
|
|
dirty = act;
|
|
|
|
}
|
|
|
|
void select(actor_t *act) {
|
|
selected = act;
|
|
}
|
|
|
|
const bool isInFront(actor_t *act1, actor_t *act2) {
|
|
|
|
if (act1->pos.x >= act2->pos.x+act2->size.x) { return true; }
|
|
else if (act2->pos.x >= act1->pos.x+act1->size.x) { return false; }
|
|
else if (act1->pos.y >= act2->pos.y+act2->size.y) { return true; }
|
|
else if (act2->pos.y >= act1->pos.y+act1->size.y) { return false; }
|
|
else if (act1->pos.z >= act2->pos.z+act2->size.z) { return true; }
|
|
else if (act2->pos.z >= act1->pos.z+act1->size.z) { return false; }
|
|
else { return false; }
|
|
}
|
|
|
|
void reorder()
|
|
{
|
|
while (dirty)
|
|
{
|
|
if (first)
|
|
{
|
|
actor_t *current = first;
|
|
while (true)
|
|
{
|
|
if (isInFront(current, dirty))
|
|
{
|
|
dirty->prev = current->prev;
|
|
current->prev = dirty;
|
|
if (dirty->prev) dirty->prev->next = dirty;
|
|
dirty = dirty->next;
|
|
current->prev->next = current;
|
|
if (current==first) first=current->prev;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (current->next)
|
|
{
|
|
current = current->next;
|
|
}
|
|
else
|
|
{
|
|
current->next = dirty;
|
|
dirty = dirty->next;
|
|
current->next->prev = current;
|
|
current->next->next = nullptr;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
first = dirty;
|
|
dirty = dirty->next;
|
|
first->prev=first->next=nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t push(actor_t *act, uint8_t push)
|
|
{
|
|
uint8_t result = 0;
|
|
if (act->flags & FLAG_PUSHABLE) act->push |= push;
|
|
if ( (act->flags & FLAG_REACTIVE) && (act->react_mask & push) ) result = act->react_push;
|
|
if (act->flags & FLAG_DEADLY) result |= PUSH_KILL;
|
|
|
|
return result;
|
|
}
|
|
|
|
void updateUserInput(actor_t *act)
|
|
{
|
|
vec3_t min = room::getMin();
|
|
vec3_t max = room::getMax();
|
|
|
|
bool moving = false;
|
|
if ( input::keyDown(SDL_SCANCODE_LEFT) )
|
|
{
|
|
act->orient=PUSH_XN;
|
|
if ( (act->pos.x>min.x && act->pos.y>=min.y && act->pos.y<=max.y) || ( (room::getDoors()&DOOR_XN) && (act->pos.y>=24) && (act->pos.y<=32) ) )
|
|
{
|
|
moving = true;
|
|
if ( (act->pos.x<=min.x) && (act->pos.z==room::getDoor(XN)*4) && (room::getDoors()&DOOR_XN) ) {
|
|
if (act->pos.y<28)
|
|
act->push |= PUSH_YP;
|
|
else if (act->pos.y>28)
|
|
act->push |= PUSH_YN;
|
|
else
|
|
act->push |= PUSH_XN;
|
|
} else
|
|
act->push |= PUSH_XN;
|
|
}
|
|
}
|
|
if ( input::keyDown(SDL_SCANCODE_RIGHT) )
|
|
{
|
|
act->orient=PUSH_XP;
|
|
if ( (act->pos.x<max.x && act->pos.y>=min.y && act->pos.y<=max.y) || ( (room::getDoors()&DOOR_XP) && (act->pos.y>=24) && (act->pos.y<=32) ) )
|
|
{
|
|
moving = true;
|
|
if ( (act->pos.x>=max.x) && (act->pos.z==room::getDoor(XP)*4) && (room::getDoors()&DOOR_XP) ) {
|
|
if (act->pos.y<28)
|
|
act->push |= PUSH_YP;
|
|
else if (act->pos.y>28)
|
|
act->push |= PUSH_YN;
|
|
else
|
|
act->push |= PUSH_XP;
|
|
} else
|
|
act->push |= PUSH_XP;
|
|
}
|
|
}
|
|
if ( input::keyDown(SDL_SCANCODE_UP) )
|
|
{
|
|
act->orient=PUSH_YN;
|
|
if ( (act->pos.y>min.y && act->pos.x>=min.x && act->pos.x<=max.x) || ( (room::getDoors()&DOOR_YN) && (act->pos.x>=24) && (act->pos.x<=32) ) )
|
|
{
|
|
moving = true;
|
|
if ( (act->pos.y<=min.y) && (act->pos.z==room::getDoor(YN)*4) && (room::getDoors()&DOOR_YN) ) {
|
|
if (act->pos.x<28)
|
|
act->push |= PUSH_XP;
|
|
else if (act->pos.x>28)
|
|
act->push |= PUSH_XN;
|
|
else
|
|
act->push |= PUSH_YN;
|
|
} else
|
|
act->push |= PUSH_YN;
|
|
}
|
|
}
|
|
if ( input::keyDown(SDL_SCANCODE_DOWN) )
|
|
{
|
|
act->orient=PUSH_YP;
|
|
if ( (act->pos.y<max.y && act->pos.x>=min.x && act->pos.x<=max.x) || ( (room::getDoors()&DOOR_YP) && (act->pos.x>=24) && (act->pos.x<=32) ) )
|
|
{
|
|
moving = true;
|
|
if ( (act->pos.y>=max.y) && (act->pos.z==room::getDoor(YP)*4) && (room::getDoors()&DOOR_YP) ) {
|
|
if (act->pos.x<28)
|
|
act->push |= PUSH_XP;
|
|
else if (act->pos.x>28)
|
|
act->push |= PUSH_XN;
|
|
else
|
|
act->push |= PUSH_YP;
|
|
} else
|
|
act->push |= PUSH_YP;
|
|
}
|
|
}
|
|
if ( input::keyDown(SDL_SCANCODE_SPACE) && act->pos.y<=max.y && act->pos.y>=min.y && act->pos.x<=max.x && act->pos.x>=min.x && act->react_mask==0 && (act->pos.z==0 || act->below))
|
|
{
|
|
// [RZC 14/05/2024] hack usant react_mask i react_push del heroi. Llegir més avall.
|
|
act->react_mask=1; // =1 estic botant (anant cap amunt)
|
|
act->react_push=0; // es el comptador de botant, seguirà pujant mentres siga < 8
|
|
act->flags &= uint8_t(~FLAG_GRAVITY);
|
|
if (act->below)
|
|
{
|
|
act->below->above = nullptr;
|
|
act->below = nullptr;
|
|
}
|
|
}
|
|
if (input::keyDown(SDL_SCANCODE_Z) && act->pos.z>0) { act->push |= PUSH_ZN; moving = true; }
|
|
if (input::keyDown(SDL_SCANCODE_A) && act->pos.z<max.z) { act->push |= PUSH_ZP; moving = true; }
|
|
|
|
// [RZC 14/05/2024] Açò es un hack. estic usant react_mask i react_push del hero com a guarda
|
|
// i contador per al bot. Supose que perque se suposa que el heroi no te raons
|
|
// per a ser REACTIU. Però si arriba a vindre la guardia civil m'en pega més
|
|
// que a un xixo.
|
|
if (act->react_mask)
|
|
{
|
|
// Si topetem en una vora de l'habitació, s'acabat el bot
|
|
if (act->pos.x>max.x || act->pos.x<min.x || act->pos.y>max.y || act->pos.y<min.y) act->react_push=9;
|
|
|
|
// Si encara està botant (react_push < 8)...
|
|
if (act->react_push<9)
|
|
{
|
|
act->pos.z++; // seguim pujant
|
|
act->react_push++; // augmentem el comptador de bot
|
|
}
|
|
else // Si ja ha acabat de botar...
|
|
{
|
|
act->react_mask=0; // desactivem la guarda (react_mask=0)
|
|
act->flags |= FLAG_GRAVITY; // i reactivem el flag de gravetat
|
|
}
|
|
}
|
|
|
|
// Que faça l'animació nomes si al final realment s'ha menejat
|
|
if (moving)
|
|
{
|
|
act->flags |= FLAG_ANIMATED;
|
|
}
|
|
else
|
|
{
|
|
act->flags &= uint8_t(~FLAG_ANIMATED);
|
|
}
|
|
}
|
|
|
|
void updateMoving(actor_t *act)
|
|
{
|
|
act->push |= act->mov_push;
|
|
}
|
|
|
|
void changeMoving(actor_t *act)
|
|
{
|
|
switch(act->movement)
|
|
{
|
|
case MOV_X:
|
|
act->mov_push = act->mov_push==PUSH_XP ? PUSH_XN : PUSH_XP;
|
|
break;
|
|
case MOV_Y:
|
|
act->mov_push = act->mov_push==PUSH_YP ? PUSH_YN : PUSH_YP;
|
|
break;
|
|
case MOV_Z:
|
|
act->mov_push = act->mov_push==PUSH_ZN ? PUSH_ZP : PUSH_ZN;
|
|
break;
|
|
case MOV_CW:
|
|
switch (act->mov_push)
|
|
{
|
|
case PUSH_XP: act->mov_push=PUSH_YN; break;
|
|
case PUSH_YN: act->mov_push=PUSH_XN; break;
|
|
case PUSH_XN: act->mov_push=PUSH_YP; break;
|
|
case PUSH_YP: act->mov_push=PUSH_XP; break;
|
|
}
|
|
break;
|
|
case MOV_CCW:
|
|
switch (act->mov_push)
|
|
{
|
|
case PUSH_XP: act->mov_push=PUSH_YP; break;
|
|
case PUSH_YP: act->mov_push=PUSH_XN; break;
|
|
case PUSH_XN: act->mov_push=PUSH_YN; break;
|
|
case PUSH_YN: act->mov_push=PUSH_XP; break;
|
|
}
|
|
break;
|
|
case MOV_RAND:
|
|
switch (rand()%4)
|
|
{
|
|
case 0: act->mov_push=PUSH_YP; break;
|
|
case 1: act->mov_push=PUSH_XN; break;
|
|
case 2: act->mov_push=PUSH_YN; break;
|
|
case 3: act->mov_push=PUSH_XP; break;
|
|
}
|
|
break;
|
|
case MOV_HUNT:
|
|
// TODO
|
|
break;
|
|
}
|
|
if (act->flags & FLAG_ORIENTABLE) act->orient = act->mov_push;
|
|
}
|
|
|
|
void updatePush(actor_t *act)
|
|
{
|
|
vec3_t min = room::getMin();
|
|
vec3_t max = room::getMax();
|
|
|
|
//if ((act->flags&FLAG_HERO) && (act->pos.x>max.x || act->pos.x<min.x || act->pos.y>max.y || act->pos.y<min.y) )
|
|
//return;
|
|
|
|
if (act->push & PUSH_ZP) {
|
|
if (act->pos.z>=max.z)
|
|
{
|
|
if (act->flags & FLAG_MOVING) changeMoving(act);
|
|
}
|
|
else
|
|
{
|
|
// Tractament especial del moviment cap amunt: Estem movent, directament,
|
|
// TOTS els objectes des d'este cap amunt si son pushables, en compte de
|
|
// enviar el flag de push. Ho vem així perque sino la gravetat els tiraria
|
|
// avall. De totes formes [TODO] revisar.
|
|
// Estem tenint en compte els MOVILS, pero no els REACT
|
|
actor_t *now = act;
|
|
do {
|
|
actor::actor_t *other = actor::any_above_me(now);
|
|
if (!other || (other->flags & FLAG_PUSHABLE)) now->pos.z++;
|
|
now = other;
|
|
if (now && !(now->flags & FLAG_PUSHABLE)) {
|
|
if (act->flags & FLAG_MOVING) changeMoving(act);
|
|
now = nullptr;
|
|
}
|
|
} while (now);
|
|
|
|
actor::setDirty(act);
|
|
}
|
|
act->push &= ~PUSH_ZP;
|
|
}
|
|
|
|
if (act->push & PUSH_XN) {
|
|
act->pos.x--;
|
|
actor::actor_t *other = actor::get_collision(act);
|
|
if (other || ( act->pos.x<min.x && ( !(room::getDoors()&DOOR_XN) || (act->pos.y!=28) || (act->pos.z!=room::getDoor(XN)*4) || !(act->flags&FLAG_HERO) ) ))
|
|
{
|
|
if (other) act->push |= push(other, PUSH_XN);
|
|
act->pos.x++;
|
|
if (act->flags & FLAG_MOVING) changeMoving(act);
|
|
}
|
|
else
|
|
{
|
|
// Si tenim a algú damunt, el movem també
|
|
if (act->above && act->above->flags & FLAG_PUSHABLE) {
|
|
push(act->above, PUSH_XN);
|
|
}
|
|
|
|
// Si ja havem atravesat la porta, ens movem a la porta de l'altra costat
|
|
// [TODO] que es moga a l'habitació que toca!!!
|
|
if (act->pos.x<min.x-4) {
|
|
act->pos.x = max.x;
|
|
act->pos.z = room::getDoor(XP)*4;
|
|
}
|
|
|
|
actor::setDirty(act);
|
|
}
|
|
act->push &= ~PUSH_XN;
|
|
}
|
|
|
|
if (act->push & PUSH_XP) {
|
|
act->pos.x++;
|
|
actor::actor_t *other = actor::get_collision(act);
|
|
if (other || (act->pos.x>max.x && ( !(room::getDoors()&DOOR_XP) || (act->pos.y!=28) || !(act->flags&FLAG_HERO) ) ))
|
|
{
|
|
if (other) act->push |= push(other, PUSH_XP);
|
|
act->pos.x--;
|
|
if (act->flags & FLAG_MOVING) changeMoving(act);
|
|
}
|
|
else
|
|
{
|
|
if (act->above && act->above->flags & FLAG_PUSHABLE) {
|
|
push(act->above, PUSH_XP);
|
|
}
|
|
|
|
if (act->pos.x>max.x+4) {
|
|
act->pos.x = min.x;
|
|
act->pos.z = room::getDoor(XN)*4;
|
|
}
|
|
|
|
actor::setDirty(act);
|
|
}
|
|
act->push &= ~PUSH_XP;
|
|
}
|
|
|
|
if (act->push & PUSH_YN) {
|
|
act->pos.y--;
|
|
actor::actor_t *other = actor::get_collision(act);
|
|
if (other || ( act->pos.y<min.y && ( !(room::getDoors()&DOOR_YN) || (act->pos.x!=28) || (act->pos.z!=room::getDoor(XN)*4) || !(act->flags&FLAG_HERO) ) ))
|
|
{
|
|
if (other) act->push |= push(other, PUSH_YN);
|
|
act->pos.y++;
|
|
if (act->flags & FLAG_MOVING) changeMoving(act);
|
|
}
|
|
else
|
|
{
|
|
if (act->above && act->above->flags & FLAG_PUSHABLE) {
|
|
push(act->above, PUSH_YN);
|
|
}
|
|
|
|
if (act->pos.y<min.y-4) {
|
|
act->pos.y = max.y;
|
|
act->pos.z = room::getDoor(YP)*4;
|
|
}
|
|
|
|
actor::setDirty(act);
|
|
}
|
|
act->push &= ~PUSH_YN;
|
|
}
|
|
|
|
if (act->push & PUSH_YP) {
|
|
act->pos.y++;
|
|
actor::actor_t *other = actor::get_collision(act);
|
|
if (other || ( act->pos.y>max.y && ( !(room::getDoors()&DOOR_YP) || (act->pos.x!=28) || !(act->flags&FLAG_HERO) ) ))
|
|
{
|
|
if (other) act->push |= push(other, PUSH_YP);
|
|
act->pos.y--;
|
|
if (act->flags & FLAG_MOVING) changeMoving(act);
|
|
}
|
|
else
|
|
{
|
|
if (act->above && act->above->flags & FLAG_PUSHABLE) {
|
|
push(act->above, PUSH_YP);
|
|
}
|
|
|
|
if (act->pos.y>max.y+4) {
|
|
act->pos.y = min.y;
|
|
act->pos.z = room::getDoor(YN)*4;
|
|
}
|
|
|
|
actor::setDirty(act);
|
|
}
|
|
act->push &= ~PUSH_YP;
|
|
}
|
|
|
|
if (act->push & PUSH_ZN) {
|
|
// Si estic sobre el piso, no faig res [TODO]: Si no hi ha piso ha de caure
|
|
if (act->pos.z == 0) return;
|
|
|
|
// Si tinc a algú baix...
|
|
if (act->below)
|
|
{
|
|
// ...i encara està baix...
|
|
if (is_above(act, act->below)) {
|
|
// ...li pase a ell el push, neteje el meu flag, canvie direcció si pertoca i me ane
|
|
act->push |= push(act->below, PUSH_ZN);
|
|
act->push &= ~PUSH_ZN;
|
|
if (act->flags & FLAG_MOVING) changeMoving(act);
|
|
return;
|
|
}
|
|
// ... pero si ja no està baix, el desasociem, i seguim el proces
|
|
act->below->above = nullptr;
|
|
act->below = nullptr;
|
|
}
|
|
|
|
// Busquem si hi ha algú nou baix de mi
|
|
actor_t *below = any_below_me(act); // [TODO] Jo crec que açò ho pot fer el propi get_collision()
|
|
|
|
// Si sí que hi ha...
|
|
if (below)
|
|
{
|
|
// ...el asociem...
|
|
act->below = below;
|
|
below->above = act;
|
|
// ... i li passem el push, netejem el meu flag i gonnem
|
|
act->push |= push(act->below, PUSH_ZN);
|
|
act->push &= ~PUSH_ZN;
|
|
if (act->flags & FLAG_MOVING) changeMoving(act);
|
|
return;
|
|
}
|
|
|
|
// Si estem dins d'una porta, no caiguem. [TODO] Revisar
|
|
if (act->flags&FLAG_HERO && (act->pos.x>max.x || act->pos.x<min.x || act->pos.y>max.y || act->pos.y<min.y) ) return;
|
|
|
|
// Si arribem fins ací, podem moure la posició
|
|
act->push &= ~PUSH_ZN;
|
|
act->pos.z--;
|
|
actor::setDirty(act);
|
|
}
|
|
|
|
if ( (act->push & PUSH_KILL) && (act->flags & FLAG_HERO) ) {
|
|
//[TODO] Matar al ruiseñor
|
|
}
|
|
/*
|
|
if (act->push & PUSH_ZN) {
|
|
act->pos.z--;
|
|
actor::actor_t *other = actor::get_collision(act);
|
|
if (other || act->pos.z<0 || act->pos.x>max.x || act->pos.x<min.x || act->pos.y>max.y || act->pos.y<min.y)
|
|
{
|
|
if (other && other->flags & FLAG_REACTIVE) other->push |= PUSH_ZN;
|
|
act->pos.z++;
|
|
if (act->flags & FLAG_MOVING) changeMoving(act);
|
|
}
|
|
else
|
|
{
|
|
actor::setDirty(act);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
void update(actor_t *act, const bool update_all)
|
|
{
|
|
actor_t *next = act->next;
|
|
|
|
// Actualitzem el frame de l'animació (si no te el flag de animat, no afectarà per a res)
|
|
if (act->anim_wait_count==act->anim_wait) {
|
|
act->anim_frame=(act->anim_frame+1)%4;
|
|
act->anim_wait_count=0;
|
|
} else {
|
|
act->anim_wait_count++;
|
|
}
|
|
|
|
if (act->flags & FLAG_HERO) updateUserInput(act);
|
|
if (act->flags & FLAG_MOVING) updateMoving(act);
|
|
if (act->flags & FLAG_GRAVITY) act->push |= PUSH_ZN;
|
|
|
|
//if (act->flags & FLAG_PUSHABLE)
|
|
updatePush(act);
|
|
//if (act->flags & FLAG_GRAVITY) updateGravity(act);
|
|
//if (act->flags & FLAG_REACTIVE) updateReactive(act);
|
|
|
|
//act->push = PUSH_NONE;
|
|
|
|
if (update_all && next) update(next);
|
|
}
|
|
|
|
void updateEditor(actor_t *act, const bool update_all)
|
|
{
|
|
actor_t *next = act->next;
|
|
|
|
if (act->anim_wait_count==act->anim_wait) {
|
|
act->anim_frame=(act->anim_frame+1)%4;
|
|
act->anim_wait_count=0;
|
|
} else {
|
|
act->anim_wait_count++;
|
|
}
|
|
|
|
if (update_all && next) updateEditor(next);
|
|
}
|
|
|
|
void print(int x, int y, int num)
|
|
{
|
|
int digits=0;
|
|
bool sign = num < 0;
|
|
num = SDL_abs(num);
|
|
int n = num;
|
|
while (n>0) {n=n/10;digits++;}
|
|
if (sign) digits++;
|
|
x=x+digits*4;
|
|
if (num==0) draw::draw(x+4,y,5,7,0,120);
|
|
while (num>0)
|
|
{
|
|
draw::draw(x,y,5,7,(num%10)*5,120);
|
|
num=num/10;
|
|
x=x-4;
|
|
}
|
|
if (sign) draw::draw(x,y,5,7,50,120);
|
|
}
|
|
|
|
//int order=0;
|
|
void draw(actor_t *act, const bool draw_all)
|
|
{
|
|
if (!act) return;
|
|
//if (act==first)order=0;
|
|
//order++;
|
|
|
|
const int x = 148-act->bmp_offset.x + act->pos.x*2 - act->pos.y*2;
|
|
const int y = 91-act->bmp_offset.y + act->pos.x + act->pos.y - act->pos.z*2;
|
|
|
|
const bool flip = ( (act->flags & FLAG_ORIENTABLE) && (act->orient==PUSH_XN || act->orient==PUSH_YP) ) ? DRAW_FLIP_HORIZONTAL : DRAW_FLIP_NONE;
|
|
const int oo = ( (act->flags & FLAG_ORIENTABLE) && (act->orient==PUSH_XN || act->orient==PUSH_YN) ) ? act->bmp_rect.h : 0;
|
|
|
|
const int ao = (act->flags & FLAG_ANIMATED) ? anims[act->anim_cycle][act->anim_frame]*act->bmp_rect.w : 0;
|
|
|
|
draw::pushSource();
|
|
draw::setSource(act->surface);
|
|
if (act==selected) draw::swapcol(1, room::getColor()==9?11:9); // Si està seleccionat, que canvie de color
|
|
draw::draw(x, y, act->bmp_rect.w, act->bmp_rect.h, act->bmp_rect.x+ao, act->bmp_rect.y+oo, flip);
|
|
draw::swapcol(1, room::getColor()); // Tornem al color per defecte
|
|
draw::popSource();
|
|
//print(x+5,y,act->pos.x);
|
|
//print(x+5,y+6,act->pos.y);
|
|
//print(x+5,y+12,act->pos.z);
|
|
//print(x+5,y+12,order);
|
|
//print(x+5,y,act->flags);
|
|
|
|
if (draw_all && act->next) draw(act->next);
|
|
}
|
|
|
|
actor_t *find(std::string name)
|
|
{
|
|
actor_t *act = first;
|
|
while (act)
|
|
{
|
|
if (name == act->name)
|
|
{
|
|
return act;
|
|
}
|
|
act = act->next;
|
|
}
|
|
|
|
act = dirty;
|
|
while (act)
|
|
{
|
|
if (name == act->name)
|
|
{
|
|
return act;
|
|
}
|
|
act = act->next;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
actor_t *find_at(const int x, const int y, const int z)
|
|
{
|
|
actor_t *act = first;
|
|
while (act)
|
|
{
|
|
if (act->pos.x==x && act->pos.y==y && act->pos.z==z)
|
|
{
|
|
return act;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
actor_t *get_collision(actor_t *act)
|
|
{
|
|
actor_t *other = first;
|
|
while (other)
|
|
{
|
|
if (other != act)
|
|
{
|
|
if (check_collision(act, other))
|
|
{
|
|
return other;
|
|
}
|
|
}
|
|
other = other->next;
|
|
}
|
|
|
|
other = dirty;
|
|
while (other)
|
|
{
|
|
if (other != act)
|
|
{
|
|
if (check_collision(act, other))
|
|
{
|
|
return other;
|
|
}
|
|
}
|
|
other = other->next;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const bool check_collision(actor_t *obj1, actor_t *obj2)
|
|
{
|
|
return (obj1->pos.x < obj2->pos.x + obj2->size.x) &&
|
|
(obj1->pos.x + obj1->size.x > obj2->pos.x ) &&
|
|
(obj1->pos.y < obj2->pos.y + obj2->size.y) &&
|
|
(obj1->pos.y + obj1->size.y > obj2->pos.y ) &&
|
|
(obj1->pos.z < obj2->pos.z + obj2->size.z) &&
|
|
(obj1->pos.z + obj1->size.z > obj2->pos.z );
|
|
}
|
|
|
|
void remove(actor_t *act)
|
|
{
|
|
if (!act) return;
|
|
if (act->prev) act->prev->next = act->next;
|
|
if (act==first) first = act->next;
|
|
if (act==dirty) dirty = act->next;
|
|
if (act->next) act->next->prev = act->prev;
|
|
free(act);
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
actor_t *hero = nullptr;
|
|
actor_t *act = first;
|
|
while (act)
|
|
{
|
|
actor_t *tmp = act->next;
|
|
if (act->flags & FLAG_HERO) {
|
|
hero = act;
|
|
} else {
|
|
draw::freeSurface(act->surface);
|
|
free(act);
|
|
}
|
|
act = tmp;
|
|
}
|
|
act = dirty;
|
|
while (act)
|
|
{
|
|
actor_t *tmp = act->next;
|
|
if (act->flags & FLAG_HERO) {
|
|
hero = act;
|
|
} else {
|
|
draw::freeSurface(act->surface);
|
|
free(act);
|
|
}
|
|
act = tmp;
|
|
}
|
|
first = dirty = nullptr;
|
|
if (hero) {
|
|
hero->above = hero->below = hero->next = hero->prev = nullptr;
|
|
dirty = hero;
|
|
}
|
|
selected = nullptr;
|
|
}
|
|
|
|
namespace templates
|
|
{
|
|
char tmp[255];
|
|
|
|
std::vector<actor_t> templates;
|
|
|
|
const char *numToOrient(uint8_t value)
|
|
{
|
|
tmp[0]=0;
|
|
if (value==0) return "NONE";
|
|
if (value&1) strcat(tmp, "XP ");
|
|
if (value&2) strcat(tmp, "XN ");
|
|
if (value&4) strcat(tmp, "YP ");
|
|
if (value&8) strcat(tmp, "YN ");
|
|
if (value&16) strcat(tmp, "ZP ");
|
|
if (value&32) strcat(tmp, "ZN ");
|
|
return tmp;
|
|
}
|
|
|
|
const char *numToFlags(uint16_t value)
|
|
{
|
|
tmp[0]=0;
|
|
if (value==0) return "NONE";
|
|
if (value&1) strcat(tmp, "HERO ");
|
|
if (value&2) strcat(tmp, "PUSHABLE ");
|
|
if (value&4) strcat(tmp, "REACTIVE ");
|
|
if (value&8) strcat(tmp, "MOVING ");
|
|
if (value&16) strcat(tmp, "ANIMATED ");
|
|
if (value&32) strcat(tmp, "ORIENTABLE ");
|
|
if (value&64) strcat(tmp, "DEADLY ");
|
|
if (value&128) strcat(tmp, "GRAVITY ");
|
|
return tmp;
|
|
}
|
|
|
|
const char *numToMov(uint8_t value)
|
|
{
|
|
if (value==0) return "NONE";
|
|
if (value==1) return "X";
|
|
if (value==2) return "Y";
|
|
if (value==3) return "Z";
|
|
if (value==4) return "CW";
|
|
if (value==5) return "CCW";
|
|
if (value==6) return "RAND";
|
|
if (value==7) return "HUNT";
|
|
return "NONE";
|
|
}
|
|
|
|
void load()
|
|
{
|
|
templates.clear();
|
|
FILE *f = fopen("data/templates.txt", "r");
|
|
if (!f) return;
|
|
int size = 0;
|
|
fscanf(f, "TEMPLATES %i\n", &size);
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
void save()
|
|
{
|
|
FILE *f = fopen("data/templates.txt", "w");
|
|
fprintf(f, "TEMPLATES %i\n", templates.size());
|
|
|
|
for (int i=0; i<templates.size(); ++i)
|
|
{
|
|
actor_t t = templates[i];
|
|
fprintf(f, "name = %s\n", t.name);
|
|
fprintf(f, "bmp = %s\n", t.bmp);
|
|
fprintf(f, "bmp_rect = %i %i %i %i\n", t.bmp_rect.x, t.bmp_rect.y, t.bmp_rect.w, t.bmp_rect.h);
|
|
fprintf(f, "bmp_offset = %i %i\n", t.bmp_offset.x, t.bmp_offset.y);
|
|
fprintf(f, "pos = %i %i %i\n", t.pos.x, t.pos.y, t.pos.z);
|
|
fprintf(f, "size = %i %i %i\n", t.size.x, t.size.y, t.size.z);
|
|
fprintf(f, "orient = %s\n", numToOrient(t.orient));
|
|
fprintf(f, "anim_cycle = %s\n", t.anim_cycle==0 ? "WALK" : "SEQ");
|
|
fprintf(f, "anim_wait = %i\n", t.anim_wait);
|
|
fprintf(f, "flags = %s\n", numToFlags(t.flags));
|
|
fprintf(f, "react_mask = %s\n", numToOrient(t.react_mask));
|
|
fprintf(f, "react_push = %s\n", numToOrient(t.react_push));
|
|
fprintf(f, "movement = %s\n\n", numToMov(t.movement));
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
const int size()
|
|
{
|
|
return templates.size();
|
|
}
|
|
|
|
actor_t *get(const int index)
|
|
{
|
|
return &templates[index];
|
|
}
|
|
|
|
void add(actor_t *actor){
|
|
actor_t new_template;
|
|
strcpy(new_template.name, actor->name);
|
|
strcpy(new_template.bmp, actor->bmp);
|
|
new_template.bmp_rect = actor->bmp_rect;
|
|
new_template.bmp_offset = actor->bmp_offset;
|
|
new_template.pos = actor->pos;
|
|
new_template.size = actor->size;
|
|
new_template.orient = actor->orient;
|
|
new_template.anim_cycle = actor->anim_cycle;
|
|
new_template.anim_wait = actor->anim_wait;
|
|
new_template.flags = actor->flags;
|
|
new_template.react_mask = actor->react_mask;
|
|
new_template.react_push = actor->react_push;
|
|
new_template.movement = actor->movement;
|
|
templates.push_back(new_template);
|
|
}
|
|
}
|
|
|
|
} |