/* * Copyright (C) 2002-2007 The Warp Rogue Team * Part of the Warp Rogue Project * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License. * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY. * * See the license.txt file for more details. */ /* * Module Name: Area * Description: - */ #define Uses_Util #define Uses_Sector #define Uses_Event #define Uses_Character #define Uses_Object #define Uses_Terrain #define Uses_ProgramManager #define Uses_Faction #define Uses_Perception #include "mheader.h" #include "area.h" #define max(a, b) ((a) < (b) ? (b) : (a)) #define min(a, b) ((a) < (b)? (a) : (b)) static void character_free_hack(void *); /* * the currently active (i.e. loaded) area */ static AREA Area; /* * direct link to the sectors for fast accesss */ static SECTOR (* const AreaSector)[AREA_WIDTH] = Area.sector; /* * the NIL point */ static const AREA_POINT AreaPointNil = { AREA_COORD_NIL, AREA_COORD_NIL }; /* * area bounds */ static const AREA_SECTION AreaBounds = { 0, AREA_HEIGHT -1, 0, AREA_WIDTH -1 }; /* * area module init */ void area_init(void) { Area.events = list_new(); Area.characters = list_new(); Area.objects = list_new(); Area.terrain = list_new(); memset(AreaSector, 0, AREA_HEIGHT * AREA_WIDTH * sizeof(SECTOR)); } /* * area module clean up */ void area_clean_up(void) { area_clear(); list_free(Area.events); list_free(Area.characters); list_free(Area.objects); list_free(Area.terrain); } /* * clears the currently active area */ void area_clear(void) { list_clear_with(Area.events, event_free); list_clear_with(Area.characters, character_free_hack); list_clear_with(Area.objects, object_free); list_clear_with(Area.terrain, terrain_free); memset(AreaSector, 0, AREA_HEIGHT * AREA_WIDTH * sizeof(SECTOR)); } /* * returns the active area */ AREA * active_area(void) { return &Area; } /* * returns the terrain list of the active area */ LIST * area_terrain_list(void) { return Area.terrain; } /* * returns the object list of the active area */ LIST * area_object_list(void) { return Area.objects; } /* * returns the character list of the active area */ LIST * area_character_list(void) { return Area.characters; } /* * returns the event list of the active area */ LIST * area_event_list(void) { return Area.events; } /* * returns the number of characters in the active area */ N_CHARACTERS area_n_characters(void) { return Area.characters->n_nodes; } /* * returns true if the coordinates of both area points are equal */ bool area_points_equal(const AREA_POINT *p1, const AREA_POINT *p2) { if (p1->x == p2->x && p1->y == p2->y) { return true; } return false; } /* * moves an area point one step in the passed direction */ void move_area_point(AREA_POINT *area_point, DIRECTION direction) { area_point->x += direction_modifier(COORD_X, direction); area_point->y += direction_modifier(COORD_Y, direction); } /* * returns the estimated euclidian distance between two area points */ AREA_DISTANCE area_distance(const AREA_POINT *p1, const AREA_POINT *p2) { AREA_DISTANCE xdiff, ydiff, distance; xdiff = abs(p1->x - p2->x); ydiff = abs(p1->y - p2->y); distance = xdiff + ydiff + max(xdiff, ydiff); distance >>= 1; return distance; } /* * returns the area bounds */ const AREA_SECTION * area_bounds(void) { return &AreaBounds; } /* * returns true if the passed point is out of bounds */ bool out_of_area_bounds(const AREA_POINT *location) { if (location->y < 0 || location->x < 0 || location->y >= AREA_HEIGHT || location->x >= AREA_WIDTH) { return true; } return false; } /* * return the area point NIL */ const AREA_POINT * area_point_nil(void) { return &AreaPointNil; } /* * places a terrain at the passed point */ void place_terrain(TERRAIN *terrain, const AREA_POINT *target_point) { sector_at(target_point)->terrain = terrain; if (terrain->list_node != NULL) return; terrain->list_node = list_add(Area.terrain, terrain); } /* * removes a terrain object from the currently active area */ void remove_terrain(TERRAIN *terrain, LIST *terrain_events) { remove_terrain_events(terrain, terrain_events); list_remove_node(Area.terrain, terrain->list_node); terrain->list_node = NULL; } /* * places an object at the passed point */ void place_object(OBJECT *object, const AREA_POINT *target_point) { sector_at(target_point)->object = object; if (object->list_node != NULL) return; object->list_node = list_add(Area.objects, object); } /* * removes an object from the currently active area */ void remove_object(OBJECT *object, LIST *object_events) { remove_object_events(object, object_events); list_remove_node(Area.objects, object->list_node); object->list_node = NULL; } /* * places a character at the passed point */ void place_character(CHARACTER *character, const AREA_POINT *target_point) { LIST_NODE *node; sector_at(target_point)->character = character; character->location = *target_point; if (character->list_node != NULL) return; character->list_node = list_add(Area.characters, character ); for (node = character->inventory->head; node != NULL; node = node->next) { OBJECT *object; object = (OBJECT *)node->data; object->list_node = list_add(Area.objects, object ); } } /* * removes a character from the currently active area */ void remove_character(CHARACTER *character, LIST *character_events) { LIST_NODE *node; remove_character_events(character, character_events); for (node = character->inventory->head; node != NULL; node = node->next) { OBJECT *object; object = (OBJECT *)node->data; remove_object(object, character_events); } list_remove_node(Area.characters, character->list_node); character->list_node = NULL; sector_at(&character->location)->character = NULL; character->location = *area_point_nil(); } /* * returns the sector located at the passed point */ SECTOR * sector_at(const AREA_POINT *location) { return &AreaSector[location->y][location->x]; } /* * returns the terrain located at the passed point */ TERRAIN * terrain_at(const AREA_POINT *location) { return AreaSector[location->y][location->x].terrain; } /* * returns the object located at the passed point */ OBJECT * object_at(const AREA_POINT *location) { return AreaSector[location->y][location->x].object; } /* * returns the character located at the passed point */ CHARACTER * character_at(const AREA_POINT *location) { return AreaSector[location->y][location->x].character; } /* * character free hack */ static void character_free_hack(void *p) { CHARACTER *character; character = (CHARACTER *)p; list_free(character->inventory); list_free(character->noticed_enemies); free(character); }