/* * Copyright (c) 2005-2007 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include MAP_Actor * MAP_ActorNew(void *parent, const char *name) { MAP_Actor *ma; ma = Malloc(sizeof(MAP_Actor)); AG_ObjectInit(ma, &mapActorClass); AG_ObjectSetNameS(ma, name); AG_ObjectAttach(parent, ma); return (ma); } static void Init(void *_Nonnull obj) { MAP_Actor *a = obj; OBJECT(a)->flags |= AG_OBJECT_REMAIN_DATA; a->flags = 0; a->parent = NULL; a->type = AG_ACTOR_MAP; a->g_map.x = 0; a->g_map.y = 0; a->g_map.l0 = 0; a->g_map.l1 = 0; a->g_map.x0 = 0; a->g_map.y0 = 0; a->g_map.x1 = 0; a->g_map.y1 = 0; a->g_map.xmot = 0; a->g_map.ymot = 0; } static int Load(void *_Nonnull obj, AG_DataSource *_Nonnull ds, const AG_Version *_Nonnull ver) { MAP_Actor *a = obj; #if 0 MAP *m; if (a->parent != NULL) { Debug(a, "Reattaching to %s\n", OBJECT(a->parent)->name); m = a->parent; MAP_DetachActor(m, a); } else { m = NULL; } #endif a->type = (enum map_actor_type)AG_ReadUint32(ds); a->flags = (int)AG_ReadUint32(ds) & AG_ACTOR_SAVED_FLAGS; switch (a->type) { case AG_ACTOR_MAP: a->g_map.x = (int)AG_ReadUint32(ds); a->g_map.y = (int)AG_ReadUint32(ds); a->g_map.l0 = (int)AG_ReadUint8(ds); a->g_map.l1 = (int)AG_ReadUint8(ds); a->g_map.x0 = a->g_map.x; a->g_map.y0 = a->g_map.y; a->g_map.x1 = a->g_map.x; a->g_map.y1 = a->g_map.y; break; case AG_ACTOR_SCENE: a->g_scene.x = AG_ReadDouble(ds); a->g_scene.y = AG_ReadDouble(ds); a->g_scene.z = AG_ReadDouble(ds); a->g_scene.dx = AG_ReadDouble(ds); a->g_scene.dy = AG_ReadDouble(ds); a->g_scene.dz = AG_ReadDouble(ds); break; default: break; } #if 0 if (m != NULL) { MAP_DetachActor(m, a); Debug(a, "Reattached to %s\n", OBJECT(m)->name); } #endif return (0); } static int Save(void *_Nonnull obj, AG_DataSource *_Nonnull ds) { MAP_Actor *a = obj; AG_WriteUint32(ds, (Uint32)a->type); AG_WriteUint32(ds, (Uint32)a->flags & AG_ACTOR_SAVED_FLAGS); switch (a->type) { case AG_ACTOR_MAP: AG_WriteUint32(ds, (Uint32)a->g_map.x); AG_WriteUint32(ds, (Uint32)a->g_map.y); AG_WriteUint8(ds, (Uint8)a->g_map.l0); AG_WriteUint8(ds, (Uint8)a->g_map.l1); break; case AG_ACTOR_SCENE: AG_WriteDouble(ds, a->g_scene.x); AG_WriteDouble(ds, a->g_scene.y); AG_WriteDouble(ds, a->g_scene.z); AG_WriteDouble(ds, a->g_scene.dx); AG_WriteDouble(ds, a->g_scene.dy); AG_WriteDouble(ds, a->g_scene.dz); break; default: break; } return (0); } static void MoveNodes(MAP_Actor *a, int xo, int yo) { MAP *m = a->parent; int x, y; for (y = a->g_map.y0; y <= a->g_map.y1; y++) { for (x = a->g_map.x0; x <= a->g_map.x1; x++) { MAP_Node *n1 = &m->map[y][x]; MAP_Node *n2 = &m->map[y+yo][x+xo]; MAP_Item *r, *nr; for (r = TAILQ_FIRST(&n1->nrefs); r != TAILQ_END(&n1->nrefs); r = nr) { nr = TAILQ_NEXT(r, nrefs); if (r->p == a && r->layer >= a->g_map.l0 && r->layer <= a->g_map.l1) { TAILQ_REMOVE(&n1->nrefs, r, nrefs); TAILQ_INSERT_TAIL(&n2->nrefs, r, nrefs); r->r_gfx.xmotion = a->g_map.xmot; r->r_gfx.ymotion = a->g_map.ymot; break; } } } } a->g_map.x += xo; a->g_map.y += yo; a->g_map.x0 += xo; a->g_map.y0 += yo; a->g_map.x1 += xo; a->g_map.y1 += yo; } void MAP_ActorMoveTile(void *obj, int xo, int yo) { MAP_Actor *a = obj; MAP *m = a->parent; int x, y; AG_ObjectLock(a); a->g_map.xmot += xo; a->g_map.ymot += yo; for (y = a->g_map.y0; y <= a->g_map.y1; y++) { for (x = a->g_map.x0; x <= a->g_map.x1; x++) { MAP_Node *node = &m->map[y][x]; MAP_Item *r; TAILQ_FOREACH(r, &node->nrefs, nrefs) { if (r->p != a || r->layer < a->g_map.l0 || r->layer > a->g_map.l1) { continue; } r->r_gfx.xmotion = a->g_map.xmot; r->r_gfx.ymotion = a->g_map.ymot; switch (a->g_map.da) { case 0: if (a->g_map.xmot < -MAPTILESZ/2) { a->g_map.xmot = +MAPTILESZ/2; MoveNodes(a, -1, 0); goto out; } break; case 90: if (a->g_map.ymot < -MAPTILESZ/2) { a->g_map.ymot = +MAPTILESZ/2; MoveNodes(a, 0, -1); goto out; } break; case 180: if (a->g_map.xmot > +MAPTILESZ/2) { a->g_map.xmot = -MAPTILESZ/2; MoveNodes(a, +1, 0); goto out; } break; case 270: if (a->g_map.ymot > +MAPTILESZ/2) { a->g_map.ymot = -MAPTILESZ/2; MoveNodes(a, 0, +1); goto out; } break; } } } } out: AG_ObjectUnlock(a); } int MAP_ActorSetTile(void *obj, int x, int y, int l0, RG_Tileset *ts, const char *name) { MAP_Actor *a = obj; int rv; AG_ObjectLock(a); MAP_ActorUnmapTile(a); rv = MAP_ActorMapTile(a, x, y, l0, ts, name); AG_ObjectUnlock(a); return (rv); } int MAP_ActorMapTile(void *obj, int X0, int Y0, int L0, RG_Tileset *ts, const char *name) { MAP_Actor *a = obj; MAP *m = a->parent; RG_Tile *tile; int x = a->g_map.x + X0; int y = a->g_map.y + Y0; int l0 = a->g_map.l0 + L0, l; int sx, sy, dx, dy; int dx0, dy0, xorig, yorig; int n = 0; AG_ObjectLock(a); if ((tile = RG_TilesetFindTile(ts, name)) == NULL) { AG_ObjectUnlock(a); return (-1); } dx0 = x - tile->xOrig/MAPTILESZ; dy0 = y - tile->yOrig/MAPTILESZ; xorig = tile->xOrig%MAPTILESZ; yorig = tile->yOrig%MAPTILESZ; for (sy = 0, dy = dy0; sy < tile->su->h; sy += MAPTILESZ, dy++) { for (sx = 0, dx = dx0; sx < tile->su->w; sx += MAPTILESZ, dx++) { MAP_Node *dn; MAP_Item *r; if (dx < 0 || dx >= (int)m->mapw || dy < 0 || dy >= (int)m->maph) { goto out; } dn = &m->map[dy][dx]; r = MAP_NodeAddTile(m, dn, ts, tile->main_id); r->p = obj; r->r_gfx.rs.x = sx; r->r_gfx.rs.y = sy; r->r_gfx.rs.w = MAPTILESZ; r->r_gfx.rs.h = MAPTILESZ; r->r_gfx.xorigin = xorig; r->r_gfx.yorigin = yorig; r->r_gfx.xcenter = MAPTILESZ/2; r->r_gfx.ycenter = MAPTILESZ/2; r->r_gfx.xmotion = a->g_map.xmot; r->r_gfx.ymotion = a->g_map.ymot; r->flags |= tile->attrs[n]; r->flags |= MAP_ITEM_NOSAVE; l = l0 + tile->layers[n]; if (l < 0) { l = 0; } else { while ((int)m->nlayers <= l) MAP_PushLayer(m, ""); } r->layer = l; if (dx < a->g_map.x0) { a->g_map.x0 = dx; } else if (dx > a->g_map.x1) { a->g_map.x1 = dx; } if (dy < a->g_map.y0) { a->g_map.y0 = dy; } else if (dy > a->g_map.y1) { a->g_map.y1 = dy; } if (l < a->g_map.l0) { a->g_map.l0 = l; } else if (l > a->g_map.l1) { a->g_map.l1 = l; } out: n++; } } AG_ObjectUnlock(a); return (0); } void MAP_ActorUnmapTile(void *obj) { MAP_Actor *a = obj; MAP *m; int x, y; AG_ObjectLock(a); if ((m = a->parent) == NULL) { goto out; } for (y = a->g_map.y0; y <= a->g_map.y1; y++) { for (x = a->g_map.x0; x <= a->g_map.x1; x++) { MAP_Node *node = &m->map[y][x]; MAP_Item *r, *nr; for (r = TAILQ_FIRST(&node->nrefs); r != TAILQ_END(&node->nrefs); r = nr) { nr = TAILQ_NEXT(r, nrefs); if (r->p == a && r->layer >= a->g_map.l0 && r->layer <= a->g_map.l1) MAP_NodeDelItem(m, node, r); } } } out: AG_ObjectUnlock(a); } static void *_Nonnull Edit(void *_Nonnull p) { MAP_Actor *a = p; AG_Window *win; if ((win = AG_WindowNew(0)) == NULL) { AG_FatalError(NULL); } AG_WindowSetCaption(win, _("Actor: %s"), OBJECT(a)->name); AG_WindowSetPosition(win, AG_WINDOW_LOWER_LEFT, 1); AG_LabelNewPolled(win, 0, _("Type: %d"), &a->type); AG_LabelNewPolled(win, 0, _("Flags: 0x%x"), &a->flags); AG_LabelNewPolled(win, 0, _("Map layers: %d-%d"), &a->g_map.l0, &a->g_map.l1); AG_LabelNewPolled(win, 0, _("Map position: [%d,%d]"), &a->g_map.x, &a->g_map.y); AG_LabelNewPolled(win, 0, _("Map extent: [%d,%d]-[%d,%d]"), &a->g_map.x0, &a->g_map.y0, &a->g_map.x1, &a->g_map.y1); AG_LabelNewPolled(win, 0, _("Map offset: [%d,%d]"), &a->g_map.xmot, &a->g_map.ymot); AG_LabelNewPolled(win, 0, _("Direction: %d(%d)"), &a->g_map.da, &a->g_map.dv); return (win); } AG_ObjectClass mapActorClass = { "MAP(Actor)", sizeof(MAP_Actor), { 0, 0 }, Init, NULL, /* reset */ NULL, /* destroy */ Load, Save, Edit };