/*
* $Id: ds.bay.c,v 1.4 2005/06/24 04:39:07 av1-op Exp $
*
* Author: Markus Stenberg <fingon@iki.fi>
*
* Copyright (c) 1996 Markus Stenberg
* Copyright (c) 1998-2002 Thomas Wouters
* Copyright (c) 2000-2002 Cord Awtry
* All rights reserved
*
* Created: Wed Nov 20 20:48:28 1996 fingon
* Last modified: Sat Jul 18 22:25:57 1998 fingon
*
*/
#include "config.h"
#include <math.h>
#include "mech.h"
#include "mech.events.h"
#include "p.mech.utils.h"
#include "p.bsuit.h"
#include "p.eject.h"
#include "p.mech.restrict.h"
#include "p.mech.startup.h"
dbref match_thing(dbref player, char *name);
void mech_createbays(dbref player, void *data, char *buffer)
{
char *args[NUM_BAYS + 1];
int argc;
dbref it;
int i;
MECH *ds = (MECH *) data;
MAP *map;
DOCHECK((argc =
mech_parseattributes(buffer, args,
NUM_BAYS + 1)) == (NUM_BAYS + 1),
"Invalid number of arguments!");
for (i = 0; i < argc; i++) {
it = match_thing(player, args[i]);
DOCHECK(it == NOTHING, tprintf("Argument %d is invalid.", i + 1));
DOCHECK(!IsMap(it), tprintf("Argument %d is not a map.", i + 1));
map = FindObjectsData(it);
AeroBay(ds, i) = it;
map->onmap = ds->mynum;
}
for (i = argc; i < NUM_BAYS; i++)
AeroBay(ds, i) = -1;
notify(player, tprintf("%d bay(s) set up!", argc));
}
extern int dirs[6][2];
static int dir2loc[6] =
{ DS_NOSE, DS_RWING, DS_RRWING, DS_AFT, DS_LRWING, DS_LWING };
int Find_DS_Bay_Number(MECH * ds, int dir)
{
int bayn = 0;
int i, j;
for (i = 0; i <= dir; i++) {
for (j = 0; j < NUM_CRITICALS; j++)
if (GetPartType(ds, dir2loc[i % 6],
j) == I2Special(DS_MECHDOOR) ||
GetPartType(ds, dir2loc[i % 6],
j) == I2Special(DS_AERODOOR))
break;
if (j != NUM_CRITICALS) {
if (i == dir)
return bayn;
bayn++;
}
}
return -1;
}
int Find_DS_Bay_Dir(MECH * ds, int num)
{
int i;
for (i = 0; i < 6; i++)
if (Find_DS_Bay_Number(ds, i) == num)
return i;
return -1;
}
#define KLUDGE(fx,tx) ((((fx)%2)&&!((tx)%2)) ? -1 : 0)
int Find_DS_Bay_In_MechHex(MECH * seer, MECH * ds, int *bayn)
{
int i;
int t = DSBearMod(ds);
for (i = t; i < (t + 6); i++) {
if (((MechX(ds) + dirs[i % 6][0]) == MechX(seer)) &&
((MechY(ds) + dirs[i % 6][1] + KLUDGE(MechX(ds),
MechX(ds) + dirs[i % 6][0])) == MechY(seer))) {
if ((*bayn = Find_DS_Bay_Number(ds, ((i - t + 6) % 6))) >= 0)
return 1;
return 0;
}
}
return 0;
}
static int Find_Single_DS_In_MechHex(MECH * mech, int *ref, int *bayn)
{
MAP *map = FindObjectsData(mech->mapindex);
int loop;
MECH *tempMech;
int count = 0;
*ref = 0;
if (!map)
return 0;
for (loop = 0; loop < map->first_free; loop++)
if (map->mechsOnMap[loop] >= 0) {
if (!(tempMech = getMech(map->mechsOnMap[loop])))
continue;
if (!IsDS(tempMech))
continue;
if (!Landed(tempMech))
continue; /* This might break midflight-aero-DS-docking. But aeros are broken anyway. */
if (Find_DS_Bay_In_MechHex(mech, tempMech, bayn)) {
if (count++)
*ref = -1;
else
*ref = tempMech->mynum;
}
}
return count;
}
static void mech_enterbay_event(MUXEVENT * e)
{
MECH *mech = (MECH *) e->data, *ds, *tmpm = NULL;
int ref = (int) e->data2;
int bayn;
int x = 5, y = 5;
MAP *tmpmap;
if (!Started(mech) || Uncon(mech) || Jumping(mech) ||
(MechType(mech) == CLASS_MECH && (Fallen(mech) || Standing(mech))) ||
OODing(mech) || (fabs(MechSpeed(mech)) * 5 >= MMaxSpeed(mech) &&
fabs(MMaxSpeed(mech)) >= MP1) || (MechType(mech) == CLASS_VTOL
&& AeroFuel(mech) <= 0))
return;
tmpmap = getMap(ref);
if (!(ds = getMech(tmpmap->onmap)))
return;
if (!Find_DS_Bay_In_MechHex(mech, ds, &bayn))
return;
/* whee */
ref = AeroBay(ds, bayn);
StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 1);
mech_notify(mech, MECHALL, "You enter bay.");
MechLOSBroadcast(mech, tprintf("has entered %s at %d,%d.",
GetMechID(ds), MechX(mech), MechY(mech)));
MarkForLOSUpdate(mech);
if (MechType(mech) == CLASS_MW && !In_Character(ref)) {
enter_mw_bay(mech, ref);
return;
}
if (MechCarrying(mech) > 0)
tmpm = getMech(MechCarrying(mech));
mech_Rsetmapindex(GOD, (void *) mech, tprintf("%d", ref));
mech_Rsetxy(GOD, (void *) mech, tprintf("%d %d", x, y));
MechLOSBroadcast(mech, "has entered the bay.");
loud_teleport(mech->mynum, ref);
if (tmpm) {
mech_Rsetmapindex(GOD, (void *) tmpm, tprintf("%d", ref));
mech_Rsetxy(GOD, (void *) tmpm, tprintf("%d %d", x, y));
loud_teleport(tmpm->mynum, ref);
}
}
static int DS_Bay_Is_Open(MECH * mech, MECH * ds, dbref bayref)
{
int i, j;
for (i = 0; i < NUM_BAYS; i++)
if (AeroBay(ds, i) > 0)
if (AeroBay(ds, i) == bayref) {
j = Find_DS_Bay_Dir(ds, i);
for (i = 0; i < NUM_CRITICALS; i++) {
if (((is_aero(mech) &&
GetPartType(ds, dir2loc[j],
i) == I2Special(DS_AERODOOR)) ||
(!is_aero(mech)
&& GetPartType(ds, dir2loc[j],
i) == I2Special(DS_MECHDOOR))) &&
!PartIsDestroyed(ds, dir2loc[j], i))
return 1;
}
return 0;
}
return 0;
}
static int DS_Bay_Is_EnterOK(MECH * mech, MECH * ds, dbref bayref)
{
int i;
for (i = 0; i < NUM_BAYS; i++)
if (AeroBay(ds, i) > 0)
if (AeroBay(ds, i) == bayref)
return muxevent_count_type_data2(EVENT_ENTER_HANGAR,
(void *) bayref) > 0 ? 0 : 1;
return 0;
}
/* ID / Number, both optional (this _will_ be painful) */
void mech_enterbay(dbref player, void *data, char *buffer)
{
char *args[3];
int argc;
dbref ref = -1, bayn = -1;
MECH *mech = data, *ds;
MAP *map;
cch(MECH_USUAL);
DOCHECK(MechType(mech) == CLASS_VTOL &&
AeroFuel(mech) <= 0, "You lack fuel to maneuver in!");
DOCHECK(Jumping(mech), "While in mid-jump? No way.");
DOCHECK(MechType(mech) == CLASS_MECH && (Fallen(mech) ||
Standing(mech)), "Crawl inside? I think not. Stand first.");
DOCHECK(OODing(mech), "While in mid-flight? No way.");
DOCHECK((argc =
mech_parseattributes(buffer, args, 2)) == 2,
"Hmm, invalid number of arguments?");
if (argc > 0)
DOCHECK((ref =
FindTargetDBREFFromMapNumber(mech, args[0])) <= 0,
"Invalid target!");
if (ref < 0) {
DOCHECK(!Find_Single_DS_In_MechHex(mech, &ref, &bayn),
"No DS bay found in your hex!");
DOCHECK(ref < 0,
"Multiple enterable things found ; use the id for specifying which you want.");
DOCHECK(!(ds =
getMech(ref)), "You sense wrongness in fabric of space.");
} else {
DOCHECK(!(ds =
getMech(ref)), "You sense wrongness in fabric of space.");
DOCHECK(!Find_DS_Bay_In_MechHex(mech, ds, &bayn),
"You see no bays in your hex.");
}
DOCHECK(IsDS(mech) && !(MechSpecials2(mech) & CARRIER_TECH), "Your craft can't enter bays.");
DOCHECK(!DS_Bay_Is_Open(mech, ds, AeroBay(ds, bayn)),
"The door has been jammed!");
DOCHECK(IsDS(mech),
"Your unit is a bit too large to fit in there.");
DOCHECK((fabs((float) (MechSpeed(mech) - MechSpeed(ds)))) > MP1,
"Speed difference's too large to enter!");
DOCHECK(MechZ(ds) != MechZ(mech),
"Get to same elevation before thinking about entering!");
DOCHECK(abs(MechVerticalSpeed(mech) - MechVerticalSpeed(ds)) > 10,
"Vertical speed difference is too great to enter safely!");
DOCHECK(MechType(mech) == CLASS_MECH && !MechIsQuad(mech) &&
(IsMechLegLess(mech)), "Without legs? Are you kidding?");
ref = AeroBay(ds, bayn);
map = getMap(ref);
DOCHECK(!map, "You sense wrongness in fabric of space.");
DOCHECK(EnteringHangar(mech), "You are already entering the hangar!");
if (!can_pass_lock(mech->mynum, ref, A_LENTER)) {
char *msg = silly_atr_get(ref, A_FAIL);
if (!msg || !*msg)
msg = "You are unable to enter the bay!";
notify(player, msg);
return;
}
DOCHECK(!DS_Bay_Is_EnterOK(mech, ds, AeroBay(ds, bayn)),
"Someone else is using the door at the moment.");
DOCHECK(!(map =
getMap(mech->mapindex)),
"You sense a wrongness in fabric of space.");
HexLOSBroadcast(map, MechX(mech), MechY(mech),
"The bay doors at $h start to open..");
MECHEVENT(mech, EVENT_ENTER_HANGAR, mech_enterbay_event, 12, ref);
}
static void DS_Place(MECH * ds, MECH * mech, int frombay)
{
int i;
int nx, ny;
MAP *mech_map;
for (i = 0; i < NUM_BAYS; i++)
if (AeroBay(ds, i) == frombay)
break;
if (i == NUM_BAYS || !(mech_map = getMap(mech->mapindex))) {
/* i _should_ be set, otherwise things are deeply disturbing */
mech_notify(mech, MECHALL, "Reality collapse imminent.");
return;
}
i = Find_DS_Bay_Dir(ds, i);
nx = dirs[(DSBearMod(ds) + i) % 6][0] + MechX(ds);
ny = dirs[(DSBearMod(ds) + i) % 6][1] + MechY(ds) + KLUDGE(MechX(ds),
nx);
nx = BOUNDED(0, nx, mech_map->map_width - 1);
ny = BOUNDED(0, ny, mech_map->map_height - 1);
/* snippage from mech_Rsetxy */
MechX(mech) = nx;
MechLastX(mech) = nx;
MechY(mech) = ny;
MechLastY(mech) = ny;
MechZ(mech) = MechZ(ds);
MechElev(mech) = MechElev(ds);
MapCoordToRealCoord(MechX(mech), MechY(mech), &MechFX(mech),
&MechFY(mech));
MechTerrain(mech) = GetTerrain(mech_map, MechX(mech), MechY(mech));
}
static int Leave_DS_Bay(MAP * map, MECH * ds, MECH * mech, dbref frombay)
{
MECH *car = NULL;
StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 1);
MechLOSBroadcast(mech, "has left the bay.");
/* We escape confines of the bay to open air/land! */
mech_Rsetmapindex(GOD, (void *) mech, tprintf("%d", ds->mapindex));
if (MechCarrying(mech) > 0)
car = getMech(MechCarrying(mech));
if (car)
mech_Rsetmapindex(GOD, (void *) car, tprintf("%d", ds->mapindex));
DOCHECKMA0(mech->mapindex == map->mynum,
"Fatal error: Unable to find the map 'ship is on.");
loud_teleport(mech->mynum, mech->mapindex);
if (car)
loud_teleport(car->mynum, mech->mapindex);
mech_notify(mech, MECHALL, "You have left the bay.");
DS_Place(ds, mech, frombay);
if (car)
MirrorPosition(mech, car, 0);
MechLOSBroadcasti(mech, ds, "has left %s's bay.");
mech_notify(ds, MECHALL, tprintf("%s has left the bay.",
GetMechID(mech)));
ContinueFlying(mech);
if (In_Character(mech->mynum) &&
Location(MechPilot(mech)) != mech->mynum) {
mech_notify(mech, MECHALL,
"%ch%cr%cf%ciINTRUDER ALERT! INTRUDER ALERT!%c");
mech_notify(mech, MECHALL,
"%ch%cr%cfAutomatic self-destruct sequence initiated.%c");
mech_shutdown(GOD, (void *) mech, "");
}
return 1;
}
int Leave_DS(MAP * map, MECH * mech)
{
MECH *car;
DOCHECKMA0(!(car =
getMech(map->onmap)), "Invalid : No parent object?");
DOCHECKMA0(!DS_Bay_Is_Open(mech, car, map->mynum),
"The door has been jammed!");
DOCHECKMA0(!Landed(car) &&
!FlyingT(mech), "The 'ship is still airborne!");
DOCHECKMA0(Zombie(car->mynum),
"You don't feel leaving right now would be prudent..");
return Leave_DS_Bay(map, car, mech, map->mynum);
}