/* $Id: olc_area.c,v 1.666 2004/09/20 10:50:30 shrike Exp $ */
/************************************************************************************
* Copyright 2004 Astrum Metaphora consortium *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
************************************************************************************/
/************************************************************************************
* ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR *
* ANATOLIA has been brought to you by ANATOLIA consortium *
* Serdar BULUT {Chronos} bulut@rorqual.cc.metu.edu.tr *
* Ibrahim Canpunar {Asena} canpunar@rorqual.cc.metu.edu.tr *
* Murat BICER {KIO} mbicer@rorqual.cc.metu.edu.tr *
* D.Baris ACAR {Powerman} dbacar@rorqual.cc.metu.edu.tr *
* By using this code, you have agreed to follow the terms of the *
* ANATOLIA license, in the file Anatolia/anatolia.licence *
***********************************************************************************/
/************************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
************************************************************************************/
/************************************************************************************
* ROM 2.4 is copyright 1993-1995 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@pacinfo.com) *
* Gabrielle Taylor (gtaylor@pacinfo.com) *
* Brian Moore (rom@rom.efn.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
*************************************************************************************/
/************************************************************************************
* Copyright (c) 1998 fjoe <fjoe@iclub.nsu.ru> *
* 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 AUTHOR 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "merc.h"
#include "olc.h"
#include "db/db.h"
#include "conquer.h"
#define EDIT_AREA(ch, area) (area = (AREA_DATA*) ch->desc->pEdit)
DECLARE_OLC_FUN(areaed_create );
DECLARE_OLC_FUN(areaed_edit );
DECLARE_OLC_FUN(areaed_touch );
DECLARE_OLC_FUN(areaed_show );
DECLARE_OLC_FUN(areaed_list );
DECLARE_OLC_FUN(areaed_name );
DECLARE_OLC_FUN(areaed_mlname );
DECLARE_OLC_FUN(areaed_file );
DECLARE_OLC_FUN(areaed_flags );
DECLARE_OLC_FUN(areaed_age );
DECLARE_OLC_FUN(areaed_reset );
DECLARE_OLC_FUN(areaed_security );
DECLARE_OLC_FUN(areaed_builders );
DECLARE_OLC_FUN(areaed_resetmsg );
DECLARE_OLC_FUN(areaed_minvnum );
DECLARE_OLC_FUN(areaed_maxvnum );
DECLARE_OLC_FUN(areaed_move );
DECLARE_OLC_FUN(areaed_credits );
DECLARE_OLC_FUN(areaed_minlevel );
DECLARE_OLC_FUN(areaed_maxlevel );
DECLARE_OLC_FUN(areaed_clan );
DECLARE_OLC_FUN(areaed_climat );
DECLARE_OLC_FUN(areaed_maxguards );
DECLARE_OLC_FUN(areaed_guardrooms );
DECLARE_OLC_FUN(areaed_explore_req );
DECLARE_OLC_FUN(areaed_planet );
DECLARE_OLC_FUN(areaed_timezone );
DECLARE_OLC_FUN(areaed_xcoordinat );
DECLARE_OLC_FUN(areaed_ycoordinat );
DECLARE_OLC_FUN(areaed_zcoordinat );
DECLARE_OLC_FUN(areaed_breadth );
DECLARE_OLC_FUN(areaed_longitude );
DECLARE_VALIDATE_FUN(validate_security );
DECLARE_VALIDATE_FUN(validate_minvnum );
DECLARE_VALIDATE_FUN(validate_maxvnum );
DECLARE_VALIDATE_FUN(validate_move );
DECLARE_VALIDATE_FUN(validate_maxguards );
olc_cmd_t olc_cmds_area[] =
{
{ "create", areaed_create, 5 },
{ "edit", areaed_edit, 5 },
{ "touch", areaed_touch, 5 },
{ "show", areaed_show, 5 },
{ "list", areaed_list, 5 },
{ "name", areaed_name, 5 },
{ "mlname", areaed_mlname, 5 },
{ "filename", areaed_file, 5, validate_filename },
{ "area", areaed_flags, 5, area_flags },
{ "age", areaed_age, 5 },
{ "reset", areaed_reset, 0 },
{ "security", areaed_security, 5, validate_security },
{ "builders", areaed_builders, 5 },
{ "resetmsg", areaed_resetmsg, 0 },
{ "minvnum", areaed_minvnum, 0, validate_minvnum },
{ "maxvnum", areaed_maxvnum, 0, validate_maxvnum },
{ "move", areaed_move, 5, validate_move },
{ "credits", areaed_credits, 5 },
{ "minlevel", areaed_minlevel, 0 },
{ "maxlevel", areaed_maxlevel, 0 },
{ "clan", areaed_clan, 5 },
{ "commands", show_commands, 0 },
{ "version", show_version, 0 },
{ "climat", areaed_climat, 0, climat_flags },
{ "planet", areaed_planet, 0, planet_flags },
{ "maxguards", areaed_maxguards, 0, validate_maxguards },
{ "guardrooms", areaed_guardrooms, 0 },
{ "explorereq", areaed_explore_req, 0 },
{ "longitude", areaed_longitude, 0 },
{ "breadth", areaed_breadth, 0 },
{ "timezone", areaed_timezone, 0 },
{ "xcoordinate", areaed_xcoordinat, 0 },
{ "ycoordinate", areaed_ycoordinat, 0 },
{ "zcoordinate", areaed_zcoordinat, 0 },
{ NULL }
};
AREA_DATA *check_range(AREA_DATA *pArea, int ilower, int iupper);
/*
* Area Editor Functions.
*/
OLC_FUN(areaed_create)
{
AREA_DATA *pArea;
if (ch->pcdata->security < SECURITY_AREA_CREATE)
{
char_puts("AreaEd: Insufficient security.\n", ch);
return FALSE;
}
pArea = new_area();
area_last->next = pArea;
area_last = pArea; /* Thanks, Walker. */
ch->desc->pEdit = (void*) pArea;
OLCED(ch) = olced_lookup(ED_AREA);
touch_area(pArea);
char_puts("AreaEd: Area created.\n", ch);
return FALSE;
}
OLC_FUN(areaed_edit)
{
AREA_DATA *pArea;
char arg[MAX_STRING_LENGTH];
one_argument(argument, arg, sizeof(arg));
if (arg[0] == '\0')
pArea = ch->in_room->area;
else if (!is_number(arg) || (pArea = area_lookup(atoi(arg))) == NULL)
{
char_puts("AreaEd: That area vnum does not exist.\n", ch);
return FALSE;
}
if (!IS_BUILDER(ch, pArea))
{
char_puts("AreaEd: Insufficient security.\n", ch);
return FALSE;
}
ch->desc->pEdit = (void *) pArea;
OLCED(ch) = olced_lookup(ED_AREA);
return FALSE;
}
OLC_FUN(areaed_touch)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return touch_area(pArea);
}
OLC_FUN(areaed_show)
{
AREA_DATA *pArea;
char arg[MAX_STRING_LENGTH];
int i;
BUFFER *output;
one_argument(argument, arg, sizeof(arg));
if (arg[0] == '\0')
{
if (IS_EDIT(ch, ED_AREA))
EDIT_AREA(ch, pArea);
else
pArea = ch->in_room->area;
}
else if (!is_number(arg) || (pArea = area_lookup(atoi(arg))) == NULL)
{
char_puts("AreaEd: That area vnum does not exist.\n", ch);
return FALSE;
}
if (!IS_BUILDER(ch, pArea))
{
char_puts("AreaEd: Insufficient security.\n", ch);
return FALSE;
}
output = buf_new(ch->lang);
buf_printf(output, "Name: [%5d] %s\n", pArea->vnum, pArea->name);
mlstr_dump(output, "ML name: ", pArea->mlname);
buf_printf(output, "File: %s\n", pArea->file_name);
buf_printf(output, "Version: [%.2lf]\n", pArea->version);
buf_printf(output, "Vnums: [%d-%d]\n", pArea->min_vnum, pArea->max_vnum);
buf_printf(output, "Levels: [%d-%d]\n", pArea->min_level, pArea->max_level);
if (pArea->clan)
buf_printf(output, "Clan: [%s]\n", clan_name(pArea->clan));
buf_printf(output, "Age: [%d]\n", pArea->age);
buf_printf(output, "Players: [%d]\n", pArea->nplayer);
buf_printf(output, "Security: [%d]\n", pArea->security);
if (!IS_NULLSTR(pArea->builders))
buf_printf(output, "Builders: [%s]\n", pArea->builders);
buf_printf(output, "Credits: [%s]\n", pArea->credits);
buf_printf(output, "Flags: [%s]\n", flag_string(area_flags, pArea->flags));
buf_printf(output, "Climat: [%s]\n\r", flag_string(climat_flags, pArea->climat_type));
buf_printf(output, "Planet: [%s]\n\r", flag_string(planet_flags, pArea->planet));
buf_printf(output, "Longitude: [%-2f]\n\r", pArea->longitude);
buf_printf(output, "Breadth: [%-2f]\n\r", pArea->breadth);
buf_printf(output, "Time Zone: [%d]\n\r", pArea->timezone);
buf_printf(output, "X Coordinate: [%d]\n\r", pArea->x_coord);
buf_printf(output, "Y Coordinate: [%d]\n\r", pArea->y_coord);
buf_printf(output, "Z Coordinate: [%d]\n\r", pArea->z_coord);
buf_printf(output, "Sun rise/set: [%-2d] [%-2d]\n\r", pArea->sunrise, pArea->sunset);
buf_printf(output, "MaxGuards: [%d]\n", pArea->max_guard_count);
buf_printf(output, "GuardRooms: [");
for (i = 0; i < MAX_GUARD_COUNT; ++i)
if (pArea->guard_room_vnums[i] != 0)
buf_printf(output, " %d ", pArea->guard_room_vnums[i]);
buf_printf(output, "]\n");
buf_printf(output, "\n");
switch (pArea->explore_required)
{
case EXPLORE_NOT_REQ:
buf_printf(output, "Explore before conquer: NOT REQUIRED\n");
break;
case EXPLORE_GUARDROOMS_REQ:
buf_printf(output, "Explore before conquer: ROOMS MUST BE EXPLORED\n");
break;
case EXPLORE_ALL_AREA_REQ:
buf_printf(output, "Explore before conquer: WHOLE AREA MUST BE EXPLORED\n");
break;
}
page_to_char(buf_string(output), ch);
buf_free(output);
return FALSE;
}
OLC_FUN(areaed_climat)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_flag64(ch, argument, cmd, &pArea->climat_type);
}
OLC_FUN(areaed_planet)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_flag64(ch, argument, cmd, &pArea->planet);
}
OLC_FUN(areaed_list)
{
char arg[MAX_STRING_LENGTH];
AREA_DATA *pArea;
BUFFER *output = NULL;
one_argument(argument, arg, sizeof(arg));
for (pArea = area_first; pArea; pArea = pArea->next)
{
if (arg[0] != '\0' && !strstr(strlwr(pArea->name), arg))
continue;
if (!IS_BUILDER(ch, pArea))
continue;
if (output == NULL)
{
output = buf_new(-1);
buf_printf(output, "[%3s] [%-27s] (%-5s-%5s) [%-10s] %3s [%-10s]\n",
"Num", "Area Name", "lvnum", "uvnum",
"Filename", "Sec", "Builders");
}
buf_printf(output, "[%3d] %s (%-5d-%5d) %-12.12s [%d] [%-10.10s]\n",
pArea->vnum, fmt_color_str(pArea->name, 29),
pArea->min_vnum, pArea->max_vnum,
pArea->file_name, pArea->security, pArea->builders);
}
if (output != NULL)
{
send_to_char(buf_string(output), ch);
buf_free(output);
}
else
char_puts("No areas with that name found.\n", ch);
return FALSE;
}
OLC_FUN(areaed_reset)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
reset_area(pArea);
char_puts("Area reset.\n", ch);
return FALSE;
}
OLC_FUN(areaed_name)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_str(ch, argument, cmd, &pArea->name);
}
OLC_FUN(areaed_mlname)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_mlstr(ch, argument, cmd, &pArea->mlname);
}
OLC_FUN(areaed_credits)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_str(ch, argument, cmd, &pArea->credits);
}
OLC_FUN(areaed_file)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_str(ch, argument, cmd, &pArea->file_name);
}
OLC_FUN(areaed_age)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->age);
}
OLC_FUN(areaed_longitude)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_double(ch, argument, cmd, &pArea->longitude);
}
OLC_FUN(areaed_breadth)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_double(ch, argument, cmd, &pArea->breadth);
}
OLC_FUN(areaed_timezone)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->timezone);
}
OLC_FUN(areaed_xcoordinat)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->x_coord);
}
OLC_FUN(areaed_ycoordinat)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->y_coord);
}
OLC_FUN(areaed_zcoordinat)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->z_coord);
}
OLC_FUN(areaed_flags)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_flag64(ch, argument, cmd, &pArea->flags);
}
OLC_FUN(areaed_security)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->security);
}
OLC_FUN(areaed_minlevel)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->min_level);
}
OLC_FUN(areaed_maxlevel)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->max_level);
}
OLC_FUN(areaed_resetmsg)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_mlstr(ch, argument, cmd, &pArea->resetmsg);
}
OLC_FUN(areaed_builders)
{
AREA_DATA *pArea;
char name[MAX_STRING_LENGTH];
EDIT_AREA(ch, pArea);
one_argument(argument, name, sizeof(name));
if (name[0] == '\0')
{
do_help(ch, "'OLC AREA BUILDER'");
return FALSE;
}
if (ch->pcdata->security < SECURITY_AREA_CREATE
&& is_name_raw(ch->name, pArea->builders, str_cmp))
{
char_puts("AreaEd: Insufficient security.\n", ch);
return FALSE;
}
name_toggle(ch, name, "AreaEd", &pArea->builders);
return TRUE;
}
OLC_FUN(areaed_minvnum)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->min_vnum);
}
OLC_FUN(areaed_maxvnum)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->max_vnum);
}
OLC_FUN(areaed_move)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->min_vnum);
}
OLC_FUN(areaed_clan)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_clan(ch, argument, cmd, &pArea->clan);
}
OLC_FUN(areaed_maxguards)
{
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
return olced_number(ch, argument, cmd, &pArea->max_guard_count);
}
OLC_FUN(areaed_guardrooms)
{
int val, i;
char *endptr;
char arg[MAX_STRING_LENGTH];
AREA_DATA *pArea;
ROOM_INDEX_DATA *pRoomIndex;
EDIT_AREA(ch, pArea);
one_argument(argument, arg, sizeof(arg));
val = strtol(arg, &endptr, 0);
if (*arg == '\0' || *endptr != '\0')
{
char_printf(ch, "Syntax: guardroom number\n");
return FALSE;
}
// validator has been placed here, because there is no number_toggle function
if ((val < pArea->min_vnum) || (val > pArea->max_vnum))
{
char_printf(ch, "AEdit: vnum must be between %d and %d for this area.\n",
pArea->min_vnum, pArea->max_vnum);
return FALSE;
}
if (!(pRoomIndex = get_room_index(val)))
{
char_printf(ch, "AEdit: guardroom vnum %d does not exist.\n", val);
return FALSE;
}
// trying to find vnum. if it exists we have to delete it from array
for (i=0; i < pArea->max_guard_count; ++i)
{
if (pArea->guard_room_vnums[i] == val)
{
pArea->guard_room_vnums[i] = 0;
char_printf(ch, "%d: room vnum deleted.\n", val);
return TRUE;
}
}
//trying to find empty space for vnum
for (i=0; i < pArea->max_guard_count; ++i)
{
if (pArea->guard_room_vnums[i] == 0)
{
pArea->guard_room_vnums[i] = val;
char_printf(ch, "%d: room vnum added.\n", val);
return TRUE;
}
}
// vnum does not exist in list and there are no space for adding
char_printf(ch, "AEdit: room vnums limit reached. Room %d was not added.\n", val);
return FALSE;
}
OLC_FUN(areaed_explore_req)
{
char arg[MAX_STRING_LENGTH];
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
one_argument(argument, arg, sizeof(arg));
//possible values: no/rooms/all
if (!str_prefix(arg, "no"))
{
pArea->explore_required = EXPLORE_NOT_REQ;
char_act("Now char must not explore this area before conquer it.", ch);
return TRUE;
}
if (!str_prefix(arg, "rooms"))
{
pArea->explore_required = EXPLORE_GUARDROOMS_REQ;
char_act("Now char must explore guardrooms in this area before conquer it.", ch);
return TRUE;
}
if (!str_prefix(arg, "all"))
{
pArea->explore_required = EXPLORE_ALL_AREA_REQ;
char_act("Now char must completely explore this area before conquer it.", ch);
return TRUE;
}
// incorrect value
char_printf(ch, "AEdit: %s - incorrect value. Possible values: no/rooms/all.\n", arg);
return FALSE;
}
/* Validators */
VALIDATE_FUN(validate_security)
{
int sec = *(int*) arg;
if (sec > ch->pcdata->security || sec < 0)
{
if (ch->pcdata->security != 0)
char_printf(ch, "AreaEd: Valid security range is 0..%d.\n", ch->pcdata->security);
else
char_puts("AreaEd: Valid security is 0 only.\n", ch);
return FALSE;
}
return TRUE;
}
VALIDATE_FUN(validate_minvnum)
{
int min_vnum = *(int*) arg;
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
if (min_vnum && pArea->max_vnum)
{
if (min_vnum > pArea->max_vnum)
{
char_puts("AreaEd: Min vnum must be less than max vnum.\n", ch);
return FALSE;
}
if (check_range(pArea, min_vnum, pArea->max_vnum))
{
char_puts("AreaEd: Range must include only this area.\n", ch);
return FALSE;
}
}
return TRUE;
}
VALIDATE_FUN(validate_maxvnum)
{
int max_vnum = *(int*) arg;
AREA_DATA *pArea;
EDIT_AREA(ch, pArea);
if (pArea->min_vnum && max_vnum)
{
if (max_vnum < pArea->min_vnum)
{
char_puts("AreaEd: Max vnum must be greater than min vnum.\n", ch);
return FALSE;
}
if (check_range(pArea, pArea->min_vnum, max_vnum))
{
char_puts("AreaEd: Range must include only this area.\n", ch);
return FALSE;
}
}
return TRUE;
}
VALIDATE_FUN(validate_maxguards)
{
int value = *(int*) arg;
if (value <0 || value > MAX_GUARD_COUNT)
{
char_printf(ch, "AEdit: Guard count for area must be between 0 and %d.\n", MAX_GUARD_COUNT);
return FALSE;
}
return TRUE;
}
#define IN_RANGE(i, l, u) ((l) <= (i) && (i) <= (u))
#define MOVE(i) if (IN_RANGE(i, pArea->min_vnum, pArea->max_vnum)) { \
i += delta; \
touched = TRUE; \
}
static void move_mob(MOB_INDEX_DATA *mob, AREA_DATA *pArea, int delta);
static void move_obj(OBJ_INDEX_DATA *obj, AREA_DATA *pArea, int delta);
static void move_room(ROOM_INDEX_DATA *room, AREA_DATA *pArea, int delta);
VALIDATE_FUN(validate_move)
{
int i;
int new_min = *(int*) arg;
int delta;
bool touched;
AREA_DATA *pArea;
MPCODE *mpc;
clan_t *clan;
religion_t *religion;
hometown_t *hometown;
EDIT_AREA(ch, pArea);
if (ch->pcdata->security < SECURITY_AREA_CREATE)
{
char_puts("AreaEd: Insufficient security.\n", ch);
return FALSE;
}
if (!pArea->min_vnum || !pArea->max_vnum)
{
char_puts("AreaEd: Both min_vnum and max_vnum must be set "
"in order to perform area vnum move.\n", ch);
return FALSE;
}
/* check new region */
delta = new_min - pArea->min_vnum;
if (check_range(pArea, new_min, pArea->max_vnum+delta))
{
char_puts("AreaEd: New vnum range overlaps other areas.\n", ch);
return FALSE;
}
/* everything is ok -- change vnums of all rooms, objs, mobs in area */
/* fix hometowns */
touched = FALSE;
for (i = 0; i < hometowns.nused; i++)
{
int j;
bool touched2 = touched;
touched = FALSE;
hometown = HOMETOWN(i);
for (j = 0; j < MAX_ANUM; j++)
{
if (IN_RANGE(hometown->recall[j]->vnum, pArea->min_vnum, pArea->max_vnum))
touched = TRUE;
if (IN_RANGE(hometown->map[j]->vnum, pArea->min_vnum, pArea->max_vnum))
touched = TRUE;
if (IN_RANGE(hometown->altar[j].room->vnum, pArea->min_vnum, pArea->max_vnum))
touched = TRUE;
if (IN_RANGE(hometown->altar[j].pit->vnum, pArea->min_vnum, pArea->max_vnum))
touched = TRUE;
}
if (touched)
touch_hometown(hometown);
else
touched = touched2;
}
if (touched)
{
char_puts("AreaEd: Changed hometowns:\n", ch);
for (i = 0; i < hometowns.nused; i++)
{
hometown = HOMETOWN(i);
if (IS_SET(hometown->flags, HOMETOWN_CHANGED))
char_printf(ch, "- %s\n", hometown->area);
}
}
/* fix religion tattoo vnum */
touched = FALSE;
for (i = 0; i < religions.nused; i++)
{
bool touched2 = touched;
touched = FALSE;
religion = RELIGION(i);
MOVE(religion->tattoo_vnum);
if (touched)
touch_religion(religion);
else
touched = touched2;
}
if (touched)
{
char_puts("AreaEd: Changed religions:\n", ch);
for (i = 0; i < religions.nused; i++)
{
religion = RELIGION(i);
if (IS_SET(religion->flags, RELIGION_CHANGED))
char_printf(ch, "- %s\n", religion->name);
}
}
/* fix clan recall, item and altar vnums */
touched = FALSE;
for (i = 0; i < clans.nused; i++)
{
bool touched2 = touched;
touched = FALSE;
clan = CLAN(i);
MOVE(clan->altar_vnum);
MOVE(clan->recall_vnum);
MOVE(clan->obj_vnum);
MOVE(clan->mark_vnum);
MOVE(clan->altar_trophy_vnum);
MOVE(clan->item_at);
if (touched)
touch_clan(clan);
else
touched = touched2;
}
if (touched)
{
char_puts("AreaEd: Changed clans:\n", ch);
for (i = 0; i < clans.nused; i++)
{
clan = CLAN(i);
if (IS_SET(clan->flags, CLAN_CHANGED))
char_printf(ch, "- %s\n", clan->name);
}
}
/* fix mprogs */
for (mpc = mpcode_list; mpc; mpc = mpc->next)
MOVE(mpc->vnum);
/* fix oprogs */
for (mpc = opcode_list; mpc; mpc = mpc->next)
MOVE(mpc->vnum);
/* fix rprogs */
for (mpc = rpcode_list; mpc; mpc = mpc->next)
MOVE(mpc->vnum);
/* fix mobs */
for (i = 0; i < MAX_KEY_HASH; i++)
{
MOB_INDEX_DATA *mob;
for (mob = mob_index_hash[i]; mob; mob = mob->next)
move_mob(mob, pArea, delta);
}
/* fix objs */
for (i = 0; i < MAX_KEY_HASH; i++)
{
OBJ_INDEX_DATA *obj;
for (obj = obj_index_hash[i]; obj; obj = obj->next)
move_obj(obj, pArea, delta);
}
/* fix rooms */
for (i = 0; i < MAX_KEY_HASH; i++)
{
ROOM_INDEX_DATA *room;
for (room = room_index_hash[i]; room; room = room->next)
move_room(room, pArea, delta);
}
/* rebuild mob index hash */
top_vnum_mob = 0;
for (i = 0; i < MAX_KEY_HASH; i++)
{
MOB_INDEX_DATA *mob, *mob_next, *mob_prev = NULL;
for (mob = mob_index_hash[i]; mob; mob = mob_next)
{
int mob_hash = mob->vnum % MAX_KEY_HASH;
mob_next = mob->next;
if (top_vnum_mob < mob->vnum)
top_vnum_mob = mob->vnum;
if (mob_hash != i)
{
if (!mob_prev)
mob_index_hash[i] = mob->next;
else
mob_prev->next = mob->next;
mob->next = mob_index_hash[mob_hash];
mob_index_hash[mob_hash] = mob;
}
else
mob_prev = mob;
}
}
/* rebuild obj index hash */
top_vnum_obj = 0;
for (i = 0; i < MAX_KEY_HASH; i++)
{
OBJ_INDEX_DATA *obj, *obj_next, *obj_prev = NULL;
for (obj = obj_index_hash[i]; obj; obj = obj_next)
{
int obj_hash = obj->vnum % MAX_KEY_HASH;
obj_next = obj->next;
if (top_vnum_obj < obj->vnum)
top_vnum_obj = obj->vnum;
if (obj_hash != i)
{
if (!obj_prev)
obj_index_hash[i] = obj->next;
else
obj_prev->next = obj->next;
obj->next = obj_index_hash[obj_hash];
obj_index_hash[obj_hash] = obj;
}
else
obj_prev = obj;
}
}
/* rebuild room index hash */
top_vnum_room = 0;
for (i = 0; i < MAX_KEY_HASH; i++)
{
ROOM_INDEX_DATA *room, *room_next, *room_prev = NULL;
for (room = room_index_hash[i]; room; room = room_next)
{
int room_hash = room->vnum % MAX_KEY_HASH;
room_next = room->next;
if (top_vnum_room < room->vnum)
top_vnum_room = room->vnum;
if (room_hash != i)
{
if (!room_prev)
room_index_hash[i] = room->next;
else
room_prev->next = room->next;
room->next = room_index_hash[room_hash];
room_index_hash[room_hash] = room;
}
else
room_prev = room;
}
}
pArea->max_vnum += delta;
touch_area(pArea);
char_puts("AreaEd: Changed areas:\n", ch);
for (pArea = area_first; pArea; pArea = pArea->next)
if (IS_SET(pArea->flags, AREA_CHANGED))
char_printf(ch, "[%3d] %s (%s)\n",
pArea->vnum, pArea->name, pArea->file_name);
return TRUE;
}
/* Local functions */
/*****************************************************************************
Name: check_range(lower vnum, upper vnum)
Purpose: Ensures the range spans only one area.
Called by: areaed_vnum(olc_act.c).
****************************************************************************/
AREA_DATA *check_range(AREA_DATA *this, int ilower, int iupper)
{
AREA_DATA *pArea;
for (pArea = area_first; pArea; pArea = pArea->next)
{
if (pArea == this || !pArea->min_vnum || !pArea->max_vnum)
continue;
if (IN_RANGE(ilower, pArea->min_vnum, pArea->max_vnum)
|| IN_RANGE(iupper, pArea->min_vnum, pArea->max_vnum)
|| IN_RANGE(pArea->min_vnum, ilower, iupper)
|| IN_RANGE(pArea->max_vnum, ilower, iupper))
return pArea;
}
return NULL;
}
static void move_mob(MOB_INDEX_DATA *mob, AREA_DATA *pArea, int delta)
{
bool touched = FALSE;
MPTRIG *mp;
int old_vnum = mob->vnum;
MOVE(mob->vnum);
if (mob->pShop)
MOVE(mob->pShop->keeper);
for (mp = mob->mptrig_list; mp; mp = mp->next)
MOVE(mp->vnum);
// MOVE(mob->fvnum);
/* touch area if it is not area being moved */
if (touched && !IN_RANGE(old_vnum, pArea->min_vnum, pArea->max_vnum))
touch_vnum(old_vnum);
}
static void move_obj(OBJ_INDEX_DATA *obj, AREA_DATA *pArea, int delta)
{
bool touched = FALSE;
int old_vnum = obj->vnum;
/* fix containers */
switch (obj->item_type)
{
case ITEM_CONTAINER:
MOVE(obj->value[2]);
if (touched)
{
OBJ_DATA *o;
for (o = object_list; o; o = o->next)
if (o->pIndexData == obj)
o->value[2] += delta;
}
}
MOVE(obj->vnum);
/* touch area if it is not area being moved */
if (touched && !IN_RANGE(old_vnum, pArea->min_vnum, pArea->max_vnum))
touch_vnum(old_vnum);
}
static void move_room(ROOM_INDEX_DATA *room, AREA_DATA *pArea, int delta)
{
int i;
bool touched = FALSE;
int old_vnum = room->vnum;
RESET_DATA *r;
MOVE(room->vnum);
for (i = 0; i < MAX_DIR; i++)
{
EXIT_DATA *pExit = room->exit[i];
if (!pExit || !pExit->to_room.r)
continue;
if (IN_RANGE(pExit->to_room.r->vnum, pArea->min_vnum+delta,
pArea->max_vnum+delta))
touched = TRUE;
// Welesh : added for connected areas conversion
if (IN_RANGE(pExit->to_room.r->vnum, pArea->min_vnum,
pArea->max_vnum))
{
pExit->to_room.r->vnum += delta;
touched = TRUE;
}
// end-added
}
for (r = room->reset_first; r; r = r->next)
{
switch (r->command)
{
case 'M':
case 'O':
case 'P':
MOVE(r->arg1);
MOVE(r->arg3);
break;
case 'G':
case 'E':
case 'D':
case 'R':
MOVE(r->arg1);
break;
}
}
/* touch area if it is not area being moved */
if (touched && !IN_RANGE(old_vnum, pArea->min_vnum, pArea->max_vnum))
touch_vnum(old_vnum);
}