/* * Copyright (c) 2022-2023 Julien Nadeau Carriere * 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 #include #include #include #include #include #include #include #include /* * Insert a dynamic map object (MAP_Object). */ typedef struct map_insert_obj_tool { MAP_Tool tool; /* MAP_Tool -> MAP_InsertObjTool */ Uint flags; #define MAP_INSERTOBJTOOL_REPLACE 0x01 /* Replace mode */ Uint32 _pad; MAP_Object *selectedObj; /* Selected object */ } MAP_InsertObjTool; static void Init(void *_Nonnull p) { MAP_InsertObjTool *tool = p; tool->flags = MAP_INSERTOBJTOOL_REPLACE; tool->selectedObj = NULL; MAP_ToolPushStatus(tool, _("Select a location on the map. " "Drag to instantiate over multiple nodes.")); } static void EditPane(void *_Nonnull p, void *_Nonnull box) { MAP_InsertObjTool *tool = p; MAP_View *mv = TOOL(tool)->mv; AG_TlistItem *it; MAP_Object *mo; AG_ObjectClass **hier; int i, nHier; if ((it = AG_TlistSelectedItem(mv->lib_tl)) == NULL || strcmp(it->cat, "object") != 0) { AG_LabelNewS(box, 0, _("Select a library object...")); return; } mo = it->p1; AG_LabelNew(box, 0, _("Insert " AGSI_YEL "%s" AGSI_RST " (" AGSI_CYAN "%s" AGSI_RST ")"), OBJECT(mo)->name, OBJECT(mo)->cls->name); AG_CheckboxNewFlag(box, 0, _("Replace mode"), &tool->flags, MAP_INSERTOBJTOOL_REPLACE); AG_SeparatorNewHoriz(box); if (AG_ObjectGetInheritHier(mo, &hier, &nHier) != 0) { AG_FatalError(NULL); } for (i = nHier-1; i >= 0; i--) { MAP_ObjectClass *clsMo = (MAP_ObjectClass *)hier[i]; AG_Label *lbl; if (!AG_ClassIsNamed(clsMo, "MAP_Object:*") || clsMo->edit == NULL) { continue; } lbl = AG_LabelNew(box, AG_LABEL_HFILL, "%s:", AGOBJECTCLASS(clsMo)->name); AG_SetFontSize(lbl, "80%"); clsMo->edit(mo, box, TOOL(tool)); AG_SeparatorNewHoriz(box); } free(hier); } static int InsertObjectAt(MAP_InsertObjTool *_Nonnull tool, MAP_Node *_Nonnull node, MAP_Object *_Nonnull mo) { MAP_View *mv = TOOL(tool)->mv; MAP_Location *loc; if (tool->flags & MAP_INSERTOBJTOOL_REPLACE) { Uint i; for (i = 0; i < node->nLocs; i++) { if (node->locs[i].obj == mo) break; } if (i < node->nLocs) { MAP_ViewStatus(mv, _("Existing " AGSI_YEL "%s" AGSI_RST " (id %u) at %d,%d : [" AGSI_BOLD "%d" AGSI_RST "] (Replace mode is ON)"), OBJECT(mo)->name, mo->id, mv->cx, mv->cy, i); return (0); } } node->locs = Realloc(node->locs, (node->nLocs + 1)*sizeof(MAP_Location)); loc = &node->locs[node->nLocs++]; loc->obj = mo; loc->flags = (MAP_OBJECT_LOCATION_SELECTED | MAP_OBJECT_LOCATION_VALID); loc->x = mv->cx; loc->y = mv->cy; loc->layer = mv->map->layerCur; loc->z = 0.0f; loc->h = 1.0f; loc->neigh = NULL; loc->nNeigh = 0; MAP_ViewStatus(mv, _("Inserted " AGSI_YEL "%s" AGSI_RST " (id %u) at %d,%d : [" AGSI_BOLD "%d" AGSI_RST "]"), OBJECT(mo)->name, mo->id, mv->cx, mv->cy, node->nLocs - 1); return (1); } static int MouseMotion(void *_Nonnull p, int x, int y, int xrel, int yrel) { MAP_InsertObjTool *tool = p; MAP_View *mv = TOOL(tool)->mv; MAP *m = mv->map; if (tool->selectedObj != NULL) { MAP_Node *node; if (mv->cx == -1 || mv->cy == -1) { return (0); } node = &m->map[mv->cy][mv->cx]; #ifdef AG_DEBUG if ((node->flags & MAP_NODE_VALID) == 0) AG_FatalError("Invalid node"); #endif return InsertObjectAt(tool, node, tool->selectedObj); } return (0); } static int MouseButtonDown(void *_Nonnull obj, int x, int y, int button) { MAP_InsertObjTool *tool = obj; MAP_View *mv = TOOL(tool)->mv; MAP *map = mv->map; MAP_Node *node; AG_TlistItem *it; MAP_Object *moLib, *mo; if (button != AG_MOUSE_LEFT) return (0); if ((it = AG_TlistSelectedItem(mv->lib_tl)) == NULL || strcmp(it->cat, "object") != 0 || mv->cx == -1 || mv->cy == -1) { return (1); } moLib = it->p1; if (!MAP_OBJECT_ISA(moLib)) { AG_SetErrorS(_("Library item is not a MAP_Object")); goto fail; } node = &map->map[mv->cy][mv->cx]; if ((node->flags & MAP_NODE_VALID) == 0) { AG_SetErrorS(_("Invalid map node")); goto fail; } if ((mo = TryMalloc(AGOBJECT_CLASS(moLib)->size)) == NULL) { goto fail; } AG_ObjectInit(mo, OBJECT(moLib)->cls); OBJECT(mo)->flags |= AG_OBJECT_NAME_ONATTACH; AG_ObjectAttach(map, mo); map->objs = Realloc(map->objs, (map->nObjs + 1) * sizeof(MAP_Object *)); mo->id = map->nObjs++; map->objs[mo->id] = mo; tool->selectedObj = mo; return InsertObjectAt(tool, node, mo); fail: MAP_ViewStatus(mv, _("Failed: %s"), AG_GetError()); return (1); } static int MouseButtonUp(void *_Nonnull obj, int x, int y, int btn) { MAP_InsertObjTool *tool = obj; // MAP_View *mv = TOOL(tool)->mv; // MAP *m = mv->map; if (tool->selectedObj) { tool->selectedObj = NULL; return (1); } return (0); } static int Cursor(void *_Nonnull p, AG_Rect *_Nonnull rd) { #if 0 MAP_InsertObjTool *tool = p; MAP_View *mv = TOOL(tool)->mv; MAP *m = mv->map; #endif return (-1); } static int Effect(void *_Nonnull p, MAP_Node *_Nonnull n) { return (0); } const MAP_ToolOps mapInsertObjOps = { "InsertObj", N_("Insert map object"), &mapIconStamp, sizeof(MAP_InsertObjTool), 0, 1, Init, NULL, /* destroy */ EditPane, NULL, /* edit */ Cursor, Effect, MouseMotion, MouseButtonDown, MouseButtonUp, NULL, /* keydown */ NULL /* keyup */ };