/* * $Id: map.obj.c,v 1.1.1.1 2005/01/11 21:18:09 kstevens 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 Oct 9 11:29:42 1996 fingon * Last modified: Tue Oct 13 07:52:27 1998 fingon * */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <sys/file.h> #include "mech.h" #include "mech.events.h" #include "create.h" #include "p.mech.utils.h" #include "p.mine.h" #include "scen.h" #include "p.btechstats.h" #define FIRESPEED(map) (MAX(20,60 - map->windspeed)) static char *map_types[] = { "FIRE", "SMOKE", "DECO", "MINE", "BUILDING", "LEAVE", "ENTRA", "LINKED", "TBITS", "BLZ", NULL }; mapobj *free_mapobjs = NULL; #define MAPOBJSTART_MAGICNUM 27 #define MAPOBJEND_MAGICNUM 39 mapobj *next_mapobj(mapobj * m) { return m->next; } mapobj *first_mapobj(MAP * map, int type) { return map->mapobj[type]; } void save_mapobjs(FILE * f, MAP * map) { #define outbyte(a) tmpb=(a);fwrite(&tmpb, 1, 1, f); int i; unsigned char tmpb; mapobj *tmp; outbyte(MAPOBJSTART_MAGICNUM); for (i = 0; i < NUM_MAPOBJTYPES; i++) if (map->mapobj[i]) { if (i == TYPE_BITS) { tmp = map->mapobj[i]; map_save_bits(f, map, tmp); } else for (tmp = map->mapobj[i]; tmp; tmp = tmp->next) { outbyte(i + 1); fwrite(tmp, sizeof(mapobj), 1, f); } } outbyte(0); outbyte(MAPOBJEND_MAGICNUM); } int find_entrance(MAP * map, char dir, int *x, int *y) { mapobj *tmp; for (tmp = first_mapobj(map, TYPE_ENTRANCE); tmp; tmp = next_mapobj(tmp)) if (!dir || tmp->datac == dir) { *x = tmp->x; *y = tmp->y; return 1; } return 0; } char *structure_name(mapobj * mapo) { static char buf[MBUF_SIZE]; sprintf(buf, "the %s", Name(mapo->obj)); return buf; } mapobj *find_entrance_by_target(MAP * map, dbref target) { mapobj *tmp; for (tmp = first_mapobj(map, TYPE_BUILD); tmp; tmp = next_mapobj(tmp)) if (tmp->obj == target) return tmp; return NULL; } mapobj *find_entrance_by_xy(MAP * map, int x, int y) { mapobj *tmp; for (tmp = first_mapobj(map, TYPE_BUILD); tmp; tmp = next_mapobj(tmp)) if (tmp->x == x && tmp->y == y) return tmp; return NULL; } mapobj *find_mapobj(MAP * map, int x, int y, int type) { mapobj *tmp; int i; if (type >= 0) { for (tmp = first_mapobj(map, type); tmp; tmp = next_mapobj(tmp)) if (tmp->x == x && tmp->y == y) return tmp; } else { for (i = 0; i < NUM_MAPOBJTYPES; i++) for (tmp = first_mapobj(map, i); tmp; tmp = next_mapobj(tmp)) if (tmp->x == x && tmp->y == y) return tmp; } return NULL; } char find_decorations(MAP * map, int x, int y) { int i; mapobj *m; for (i = 0; i <= TYPE_LAST_DEC; i++) { for (m = first_mapobj(map, i); m; m = next_mapobj(m)) if (m->x == x && m->y == y) return m->datac; } return 0; } void del_mapobj(MAP * map, mapobj * mapob, int type, int zap) { /* Delete the specified mapobj */ struct mapobj_struct *tmp; if (!(map->flags & MAPFLAG_MAPO)) return; if (map->mapobj[type] != mapob) { for (tmp = map->mapobj[type]; tmp->next && tmp->next != mapob; tmp = tmp->next); if (!tmp->next) return; tmp->next = mapob->next; } else map->mapobj[type] = mapob->next; /* Then, the silly thing. Decorations, they suck */ if (type <= TYPE_LAST_DEC) { /* Need to alter terrain back to 'usual' */ if (!(zap & 2)) SetTerrain(map, mapob->x, mapob->y, mapob->datac); if (zap) StopDec(mapob); } mapob->next = free_mapobjs; free_mapobjs = mapob; } void del_mapobjst(MAP * map, int type) { if (!(map->flags & MAPFLAG_MAPO)) return; while (map->mapobj[type]) del_mapobj(map, map->mapobj[type], type, 3); } void del_mapobjs(MAP * map) { int i; for (i = 0; i < NUM_MAPOBJTYPES; i++) del_mapobjst(map, i); if (map->flags & MAPFLAG_MAPO) map->flags &= ~MAPFLAG_MAPO; } mapobj *add_mapobj(MAP * map, mapobj ** to, mapobj * from, int flag) { mapobj *realto; map->flags |= MAPFLAG_MAPO; from->next = *to; if (!free_mapobjs) { Create(realto, mapobj, 1); } else { realto = free_mapobjs; free_mapobjs = realto->next; } bcopy(from, realto, sizeof(mapobj)); *to = realto; return realto; } static void smoke_dissipation_event(MUXEVENT * e) { MAP *map = (MAP *) e->data; mapobj *o = (mapobj *) e->data2; del_mapobj(map, o, TYPE_SMOKE, 0); } static void fire_dissipation_event(MUXEVENT * e) { MAP *map = (MAP *) e->data; mapobj *o = (mapobj *) e->data2; int x, y; x = o->x; y = o->y; del_mapobj(map, o, TYPE_FIRE, 0); if (IsForestHex(map, x, y)) { if (Number(1, 6) < 3) SetTerrain(map, x, y, GRASSLAND); else SetTerrain(map, x, y, ROUGH); } } int FindXEven(wind, x) int wind; int x; { switch (wind) { case 0: if (x == 0) return 0; if (x == 1) return -1; return 1; case 60: if (x == 0) return 1; if (x == 1) return 0; return 1; case 120: if (x == 0) return 1; if (x == 1) return 1; return 0; case 180: if (x == 0) return 0; if (x == 1) return 1; return -1; case 240: return x - 1; case 300: if (x == 0) return -1; if (x == 1) return 0; return -1; } return 0; } int FindYEven(wind, y) int wind; int y; { switch (wind) { case 0: if (y == 0) return -1; if (y == 1) return 0; return 0; case 60: if (y == 0) return 0; if (y == 1) return -1; return 1; case 120: if (y == 0) return 1; if (y == 1) return 0; return 1; case 180: return 1; case 240: if (y == 0) return 1; if (y == 1) return 1; return 0; case 300: if (y == 0) return 0; if (y == 1) return -1; return 1; } return 0; } int FindXOdd(wind, x) int wind; int x; { switch (wind) { case 0: if (x == 0) return 0; if (x == 1) return 1; return -1; case 60: if (x == 0) return 1; if (x == 1) return 0; return 1; case 120: if (x == 0) return 1; if (x == 1) return 1; return 0; case 180: if (x == 0) return 0; if (x == 1) return 1; return -1; case 240: return x - 1; case 300: if (x == 0) return -1; if (x == 1) return -1; return 0; } return 0; } int FindYOdd(wind, y) int wind; int y; { switch (wind) { case 0: if (y == 0) return -1; if (y == 1) return -1; return -1; case 60: if (y == 0) return -1; if (y == 1) return -1; return 0; case 120: if (y == 0) return 0; if (y == 1) return -1; return 1; case 180: if (y == 0) return 1; if (y == 1) return 0; return 0; case 240: if (y == 0) return 0; if (y == 1) return 1; return -1; case 300: if (y == 0) return -1; if (y == 1) return 0; return -1; } return 0; } #define NUM_SPREAD_HEX 4 void CheckForFire(MAP * map, int x[], int y[]) { int i; for (i = 0; i < NUM_SPREAD_HEX; i++) { if (x[i] < 0 || y[i] < 0) continue; /* Cackle */ if (IsForestHex(map, x[i], y[i])) add_decoration(map, x[i], y[i], TYPE_FIRE, FIRE, FIRE_DURATION); } } void CheckForSmoke(MAP * map, int x[], int y[]) { int i; for (i = 0; i < NUM_SPREAD_HEX; i++) { if (x[i] < 0 || y[i] < 0) continue; if (find_decorations(map, x[i], y[i])) continue; /* Cackle */ switch (GetTerrain(map, x[i], y[i])) { case BUILDING: case WALL: continue; default: break; } add_decoration(map, x[i], y[i], TYPE_SMOKE, SMOKE, SMOKE_DURATION); } } static void FindMyCoord(MAP * map, int tx, int ty, int i, int wdir, int *x, int *y) { int dx, dy; wdir = (((wdir + 30) / 60) * 60) % 360; if (tx % 2) { dx = tx + FindXOdd(wdir, i); dy = ty + FindYOdd(wdir, i); } else { dx = tx + FindXEven(wdir, i); dy = ty + FindYEven(wdir, i); } if (dx < 0 || dy < 0 || dx >= map->map_width || dy >= map->map_height) { *x = -1; *y = -1; return; } *x = dx; *y = dy; } static void fire_spreading_event(MUXEVENT * e) { MAP *map = (MAP *) e->data; mapobj *o = (mapobj *) e->data2; int x, y, loop; int flaggo; int new_fire_hex_x[4]; int new_fire_hex_y[4]; int new_smoke_hex_x[4]; int new_smoke_hex_y[4]; /* if (Number(1, 10) == 3) */ /* { */ /* x = o->x; */ /* y = o->y; */ /* fire_dissipation_event(e); */ /* add_decoration(map, x, y, TYPE_SMOKE, SMOKE, SMOKE_DURATION); */ /* return; */ /* } */ x = o->x; y = o->y; for (loop = 0; loop < 3; loop++) { new_fire_hex_x[loop] = -1; new_fire_hex_y[loop] = -1; FindMyCoord(map, x, y, loop, map->winddir, &new_smoke_hex_x[loop], &new_smoke_hex_y[loop]); } new_fire_hex_x[3] = -1; new_fire_hex_y[3] = -1; FindMyCoord(map, new_smoke_hex_x[0], new_smoke_hex_y[0], 0, map->winddir, &new_smoke_hex_x[3], &new_smoke_hex_y[3]); #define Spr(n,ch) \ if(Roll() >= ch && Number(1,60) <= map->windspeed) \ { \ new_fire_hex_x[n] = new_smoke_hex_x[n]; \ new_fire_hex_y[n] = new_smoke_hex_y[n]; \ } Spr(0, 9); Spr(1, 11); Spr(2, 11); Spr(3, 12); /* 2 hexes 'downwind' */ #undef Spr CheckForSmoke(map, new_smoke_hex_x, new_smoke_hex_y); CheckForFire(map, new_fire_hex_x, new_fire_hex_y); flaggo = (o->datas -= FIRESPEED(map)); if (flaggo > FIRESPEED(map)) MAPEVENT(map, EVENT_DECORATION, fire_spreading_event, FIRESPEED(map), o); else MAPEVENT(map, EVENT_DECORATION, fire_dissipation_event, flaggo, o); } void add_decoration(MAP * map, int x, int y, int type, char data, int flaggo) { mapobj foo; mapobj *tmpo; bzero(&foo, sizeof(mapobj)); foo.x = x; foo.y = y; foo.datac = GetRTerrain(map, x, y); /* if (foo.datac) */ { mapobj *m, *m2; int i; for (i = 0; i <= TYPE_LAST_DEC; i++) { for (m = first_mapobj(map, i); m; m = m2) { m2 = next_mapobj(m); if (m->x == x && m->y == y) del_mapobj(map, m, i, 1); } } } SetTerrain(map, x, y, data); foo.datas = (short) flaggo; tmpo = add_mapobj(map, &map->mapobj[type], &foo, 1); if (flaggo) { if (type == TYPE_SMOKE) MAPEVENT(map, EVENT_DECORATION, smoke_dissipation_event, flaggo, tmpo); if (type == TYPE_FIRE) { foo.datas = foo.datas * FIRESPEED(map) * 4 / 3 / 60; foo.datas = MAX(foo.datas, FIRESPEED(map) * 2); MAPEVENT(map, EVENT_DECORATION, fire_spreading_event, FIRESPEED(map), tmpo); } } } void load_mapobjs(FILE * f, MAP * map) { unsigned char tmpb; int i; mapobj tmp; fread(&tmpb, 1, 1, f); if (tmpb != MAPOBJSTART_MAGICNUM) { fprintf(stderr, "Error: No mapobjstart found!"); return; } /* Clean out */ for (i = 0; i < NUM_MAPOBJTYPES; i++) map->mapobj[i] = NULL; fread(&tmpb, 1, 1, f); while (tmpb && !feof(f)) { if ((tmpb - 1) == TYPE_BITS) map_load_bits(f, map); else { fread(&tmp, sizeof(mapobj), 1, f); add_mapobj(map, &map->mapobj[tmpb - 1], &tmp, 0); if ((tmpb - 1) == TYPE_BUILD) possibly_start_building_regen(tmp.obj); } fread(&tmpb, 1, 1, f); } fread(&tmpb, 1, 1, f); if (tmpb != MAPOBJEND_MAGICNUM) fprintf(stderr, "Error: No mapobjend found!"); } void list_mapobjs(dbref player, MAP * map) { mapobj *tmp; int i; notify(player, "X Y Type obj dc ds di"); notify(player, "--------------------------------------------"); for (i = 0; i < NUM_MAPOBJTYPES; i++) for (tmp = first_mapobj(map, i); tmp; tmp = next_mapobj(tmp)) { if (i == TYPE_BITS) notify(player, "--- MAP/HANGAR INFORMATION OBJECT ---"); else notify(player, tprintf("%-3d %-3d %-5s %-5d %-4d %-6d %d", tmp->x, tmp->y, map_types[i], (int) tmp->obj, tmp->datac, tmp->datas, tmp->datai)); } notify(player, "--------------------------------------------"); } void map_addfire(dbref player, void *data, char *buffer) { /* Entrance-checking code */ MAP *map = (MAP *) data; char *args[4]; int x, y, d; if (mech_parseattributes(buffer, args, 3) != 3) { notify(player, "Error: Invalid number of attributes to addfire command."); notify(player, "Excepted format: check damned HELP"); return; } x = atoi(args[0]); y = atoi(args[1]); d = atoi(args[2]); add_decoration(map, x, y, TYPE_FIRE, FIRE, d); notify(player, tprintf("Added: Fire at (%d,%d) with duration of %ds.", x, y, d)); } void map_addsmoke(dbref player, void *data, char *buffer) { MAP *map = (MAP *) data; char *args[4]; int x, y, d; if (mech_parseattributes(buffer, args, 3) != 3) { notify(player, "Error: Invalid number of attributes to addsmoke command."); notify(player, "Excepted format: check damned HELP"); return; } x = atoi(args[0]); y = atoi(args[1]); d = atoi(args[2]); add_decoration(map, x, y, TYPE_SMOKE, SMOKE, d); notify(player, tprintf("Added: Smoke at (%d,%d) with duration of %ds.", x, y, d)); } /* x y dist */ void map_add_block(dbref player, void *data, char *buffer) { char *args[4]; int argc; int x, y, str; MAP *map = (MAP *) data; mapobj foo; int team = 0; if (!map) return; #define READINT(from,to) \ DOCHECK(Readnum(to,from), "Invalid number!") argc = mech_parseattributes(buffer, args, 4); DOCHECK(argc < 2 || argc > 4, "Invalid arguments!"); READINT(args[0], x); READINT(args[1], y); READINT(args[2], str); if (argc == 4) READINT(args[3], team); bzero(&foo, sizeof(mapobj)); foo.x = x; foo.y = y; foo.datai = str; foo.obj = player; foo.datac = team; add_mapobj(map, &map->mapobj[TYPE_B_LZ], &foo, 1); notify(player, tprintf("Landingzone-block added to %d,%d (distance: %d)", x, y, str)); } int is_blocked_lz(MECH * mech, MAP * map, int x, int y) { mapobj *o; float fx, fy; float tx, ty; MapCoordToRealCoord(x, y, &fx, &fy); for (o = first_mapobj(map, TYPE_B_LZ); o; o = next_mapobj(o)) { if (abs(x - o->x) > o->datai || abs(y - o->y) > o->datai) continue; if (o->datac && o->datac == MechTeam(mech)) continue; MapCoordToRealCoord(o->x, o->y, &tx, &ty); if (FindHexRange(fx, fy, tx, ty) <= o->datai) return 1; } return 0; } void map_setlinked(dbref player, void *data, char *buffer) { MAP *map = (MAP *) data; mapobj foo; bzero(&foo, sizeof(mapobj)); foo.datac = 1; add_mapobj(map, &map->mapobj[TYPE_LINKED], &foo, 1); notify(player, tprintf("Map set to linked.")); } int mapobj_del(MAP * map, int x, int y, int tt) { int count = 0; mapobj *foo, *foo2; for (foo = first_mapobj(map, tt); foo; foo = foo2) { foo2 = next_mapobj(foo); if (foo->x == x && foo->y == y) { del_mapobj(map, foo, tt, 1); count++; } } return count; } void map_delobj(dbref player, void *data, char *buffer) { MAP *map = (MAP *) data; char *args[5]; mapobj *foo, *foo2; int tt, count = 0, mdel = 0; int x, y; switch (mech_parseattributes(buffer, args, 3)) { case 0: notify(player, "Error: Invalid number of attributes to delobj command."); notify(player, "Excepted format: check damned HELP"); return; case 1: DOCHECK((tt = listmatch(map_types, args[0])) < 0, "Invalid type!"); for (foo = map->mapobj[tt]; foo; foo = foo2) { foo2 = next_mapobj(foo); del_mapobj(map, foo, tt, 1); count++; } notify(player, tprintf("%d objects deleted!", count)); if (tt == TYPE_MINE) mdel = 1; break; case 2: x = atoi(args[0]); y = atoi(args[1]); for (tt = 0; tt < NUM_MAPOBJTYPES; tt++) for (foo = first_mapobj(map, tt); foo; foo = foo2) { foo2 = next_mapobj(foo); if (foo->x == x && foo->y == y) { if (tt == TYPE_MINE) mdel = 1; del_mapobj(map, foo, tt, 1); count++; } } notify(player, tprintf("%d objects at (%d,%d) deleted.", count, x, y)); break; case 3: DOCHECK((tt = listmatch(map_types, args[0])) < 0, "Invalid type!"); x = atoi(args[1]); y = atoi(args[2]); for (foo = first_mapobj(map, tt); foo; foo = foo2) { foo2 = next_mapobj(foo); if (foo->x == x && foo->y == y) { if (tt == TYPE_MINE) mdel = 1; del_mapobj(map, foo, tt, 1); count++; } } notify(player, tprintf("%d %s at (%d,%d) deleted.", count, map_types[tt], x, y)); break; default: notify(player, "Invalid number of arguments!"); return; } if (mdel) recalculate_minefields(map); } int update_stats[3]; /* Build / Leave / Entrance */ #define addstat(a) update_stats[(a)]++ struct { int x, y; char dir; } dirtable[4] = { { 1, 0, 'n'}, { 2, 1, 'e'}, { 1, 2, 's'}, { 0, 1, 'w'} }; void recursively_updatelinks(dbref from, dbref loc); int parse_coord(MAP * map, int dir, char *data, int *x, int *y) { int tx, ty, tox, toy; int doh; if (strchr(data, ',')) { if (sscanf(data, "%d,%d", x, y) == 2) return 1; return 0; } doh = atoi(data); if (doh < 0) return 0; tox = dirtable[dir].x; toy = dirtable[dir].y; tx = (map->map_width * tox) / 2; if (tx >= map->map_width) tx = map->map_width - 1; ty = (map->map_height * toy) / 2; if (ty >= map->map_height) ty = map->map_height - 1; if (tox == 1) ty += (toy > 1) ? (0 - doh) : (doh); if (toy == 1) tx += (tox > 1) ? (0 - doh) : (doh); if (tx < 0) tx = 0; if (ty < 0) ty = 0; if (tx >= map->map_width) tx = (map->map_width - 1); if (ty >= map->map_height) ty = (map->map_height - 1); *x = tx; *y = ty; return 1; } void add_entrances(dbref loc, MAP * map, char *data) { char *buf; char *args[4]; int x, y, i; mapobj foo; bzero(&foo, sizeof(mapobj)); buf = alloc_mbuf("add_entrances"); strcpy(buf, data); if (mech_parseattributes(buf, args, 4) == 4) { for (i = 0; i < 4; i++) if ((parse_coord(map, i, args[i], &x, &y))) { foo.datac = dirtable[i].dir; foo.x = x; foo.y = y; add_mapobj(map, &map->mapobj[TYPE_ENTRANCE], &foo, 1); addstat(2); } } free_mbuf(buf); } void add_links(dbref loc, MAP * map, char *data) { char *buf; char *args[500]; int i, found, targ; char *tmps; int x, y; mapobj foo; bzero(&foo, sizeof(mapobj)); buf = alloc_lbuf("add_links"); strcpy(buf, data); if ((found = mech_parseattributes(buf, args, 500)) > 0) for (i = 0; i < found; i++) { targ = atoi(args[i]); if (targ < 0 || !(FindObjectsData(targ)) || targ == loc) continue; tmps = silly_atr_get(targ, A_BUILDCOORD); if (!tmps) continue; if (sscanf(tmps, "%d,%d", &x, &y) != 2) continue; if (x < 0 || x >= map->map_width || y < 0 || y >= map->map_height) continue; set_hex_enterable(map, x, y); foo.x = x; foo.y = y; foo.obj = targ; add_mapobj(map, &map->mapobj[TYPE_BUILD], &foo, 1); addstat(0); recursively_updatelinks(loc, targ); } free_lbuf(buf); } void recursively_updatelinks(dbref from, dbref loc) { MAP *map; mapobj foo; char *tmps; bzero(&foo, sizeof(mapobj)); if (!(map = getMap(loc))) return; clear_hex_bits(map, 2); if (from >= 0) { map->onmap = from; /* Update leave exit */ del_mapobjst(map, TYPE_LEAVE); addstat(1); foo.obj = from; add_mapobj(map, &map->mapobj[TYPE_LEAVE], &foo, 0); del_mapobjst(map, TYPE_ENTRANCE); /* Places you can enter this place from.. it's more or less directly taken from BUILDENTRANCE */ tmps = silly_atr_get(loc, A_BUILDENTRANCE); if (tmps) { /* number number number number or x,y x,y x,y x,y */ add_entrances(loc, map, tmps); } } del_mapobjst(map, TYPE_BUILD); tmps = silly_atr_get(loc, A_BUILDLINKS); if (tmps) add_links(loc, map, tmps); } void map_updatelinks(dbref player, void *data, char *buffer) { dbref ourloc; ourloc = Location(player); bzero(update_stats, sizeof(update_stats)); recursively_updatelinks(NOTHING, ourloc); notify(player, tprintf("Updated %d BUILD objs, %d LEAVE objs, %d ENTRANCE objs.", update_stats[0], update_stats[1], update_stats[2])); } int map_linked(dbref mapobj) { MAP *map = getMap(mapobj); if (!map) return 0; return (first_mapobj(map, TYPE_LINKED)) ? 1 : 0; } static int get_building_cf(dbref d, int *i1, int *i2) { MAP *map; if (!(map = getMap(d))) return 0; *i1 = map->cf; *i2 = map->cfmax; return map->cf; } int get_cf(dbref d) { int cf, max = 0; if (!(get_building_cf(d, &cf, &max))) if (max <= 0) return -1; return cf; } static void set_building_cf(dbref obj, int i1, int i2) { MAP *map; if (!(map = getMap(obj))) return; map->cf = i1; map->cfmax = i2; } static void building_regen_event(MUXEVENT * e) { #ifdef BUILDINGS_REPAIR_THEMSELVES dbref d = (dbref) e->data; int cf, max; if (!get_building_cf(d, &cf, &max)) return; cf = MIN(cf + BUILDING_REPAIR_AMOUNT, max); set_building_cf(d, cf, max); if (cf != max) OBJEVENT(d, EVENT_BREGEN, building_regen_event, BUILDING_REPAIR_DELAY, NULL); #endif } static void building_rebuild_event(MUXEVENT * e) { #ifdef BUILDINGS_REBUILD_FROM_DESTRUCTION dbref d = (dbref) e->data; int cf = 0, max = 0; if (get_building_cf(d, &cf, &max)) return; if (max <= 0) return; set_building_cf(d, 1, max); #endif } void possibly_start_building_regen(dbref obj) { int f, t; if (!get_building_cf(obj, &f, &t)) return; if (f == t) return; if (!f) OBJEVENT(obj, EVENT_BREBUILD, building_rebuild_event, BUILDING_DREBUILD_DELAY, NULL); else OBJEVENT(obj, EVENT_BREGEN, building_regen_event, BUILDING_REPAIR_DELAY, NULL); } static void damage_cf(MECH * mech, mapobj * o, int from, int to, int damage) { int destroy = 0; int start_regen = 0; if (from == to) start_regen = 1; damage = MIN(from, damage); if (from == damage) destroy = 1; from -= damage; set_building_cf(o->obj, from, to); scen_see_base(FindObjectsData(mech->mapindex), mech, o); if (destroy) { mech_notify(mech, MECHALL, tprintf("You hit %s for %d points of damage, destroying it!", structure_name(o), damage)); notify_except(o->obj, NOTHING, o->obj, tprintf ("%s is hit for %d more points of damage, destroying it!", MyToUpper(structure_name(o)), damage)); MechLOSBroadcast(mech, tprintf("hits %s, destroying it!", structure_name(o), damage)); scen_destroy_base(FindObjectsData(mech->mapindex), mech, o); start_regen = 2; } else { mech_notify(mech, MECHALL, tprintf("You hit %s for %d points of damage.", structure_name(o), damage)); notify_except(o->obj, NOTHING, o->obj, tprintf("%s is hit for %d points of damage.", MyToUpper(structure_name(o)), damage)); scen_damage_base(FindObjectsData(mech->mapindex), mech, o); } if (start_regen) possibly_start_building_regen(o->obj); } void hit_building(MECH * mech, int x, int y, int weapindx, int damage) { mapobj *o; MAP *map; MAP *nmap; int loop, num_missiles_hit, hit_roll; int i1, i2; if (!(map = getMap(mech->mapindex))) return; if (!(o = find_entrance_by_xy(map, x, y))) return; if (!(nmap = getMap(o->obj))) return; if (!damage) { if (!IsMissile(weapindx)) damage = MechWeapons[weapindx].damage; else { /* Missile weapon. Multiple Hit locations... */ for (loop = 0; MissileHitTable[loop].key != -1; loop++) if (MissileHitTable[loop].key == weapindx) break; if (!(MissileHitTable[loop].key == weapindx)) return; if ((MechWeapons[weapindx].type == STREAK) && (!AngelECMDisturbed(mech))) num_missiles_hit = MissileHitTable[loop].num_missiles[10]; else { hit_roll = Roll() - 2; num_missiles_hit = MissileHitTable[loop].num_missiles[hit_roll]; } damage = num_missiles_hit * MechWeapons[weapindx].damage; } } if (!damage) return; if (MapIsCS(map) || BuildIsCS(nmap)) { mech_notify(mech, MECHALL, "Your shot only scratches the paint!"); return; } if (!get_building_cf(o->obj, &i1, &i2)) return; damage_cf(mech, o, i1, i2, damage); } void fire_hex(MECH * mech, int x, int y, int meant) { MAP *map; if (!(map = getMap(mech->mapindex))) return; switch (GetTerrain(map, x, y)) { case HEAVY_FOREST: break; case LIGHT_FOREST: break; default: return; } if (meant) { MechLOSBroadcast(mech, tprintf("'s shot ignites %d,%d!", x, y)); mech_notify(mech, MECHALL, tprintf("You ignite %d,%d.", x, y)); } else { MechLOSBroadcast(mech, tprintf("'s stray shot ignites %d,%d!", x, y)); mech_notify(mech, MECHALL, tprintf("You accidentally ignite %d,%d!", x, y)); } add_decoration(map, x, y, TYPE_FIRE, FIRE, FIRE_DURATION); } void steppable_base_check(MECH * mech, int x, int y) { mapobj *o; MAP *map; MAP *nmap; map = getMap(mech->mapindex); if (!map) return; if (MechZ(mech) != Elevation(map, x, y)) return; if (!(is_hangar_hex(map, x, y))) return; if (!(o = find_entrance_by_xy(map, x, y))) return; if (!(nmap = getMap(o->obj))) return; if (BuildIsInvis(nmap)) return; if (BuildIsHidden(nmap) && !MadePerceptionRoll(mech, 0)) return; mech_notify(mech, MECHALL, tprintf("%s has CF of %d.", MyToUpper(structure_name(o)), nmap->cf)); scen_see_base(map, mech, o); } void show_building_in_hex(MECH * mech, int x, int y) { mapobj *o; MAP *map; MAP *nmap; if (!(map = getMap(mech->mapindex))) { mech_notify(mech, MECHALL, "The sensors detect no building in the hex!"); return; } if (!(o = find_entrance_by_xy(map, x, y))) { mech_notify(mech, MECHALL, "The sensors detect no building in the hex!"); return; } if (!(nmap = getMap(o->obj))) { mech_notify(mech, MECHALL, "The sensors detect no building in the hex!"); return; } if (BuildIsInvis(nmap) || (BuildIsHidden(nmap) && !MadePerceptionRoll(mech, (int) (FindRange(MechX(mech), MechY(mech), MechZ(mech), x, y, 0) + 0.95)))) { mech_notify(mech, MECHALL, "The sensors detect no building in the hex!"); return; } mech_notify(mech, MECHALL, tprintf("%s's CF is %d.", MyToUpper(structure_name(o)), nmap->cf)); scen_see_base(map, mech, o); } int obj_size(MAP * map) { int s = 0; mapobj *m; int i; for (i = 0; i < NUM_MAPOBJTYPES; i++) if (map->mapobj[i]) for (m = first_mapobj(map, i); m; m = next_mapobj(m)) s += sizeof(mapobj); return s; } int map_underlying_terrain(MAP * map, int x, int y) { char c; if (!map) return 0; c = find_decorations(map, x, y); if (c) return c; return GetTerrain(map, x, y); } int mech_underlying_terrain(MECH * mech) { char c; MAP *map = FindObjectsData(mech->mapindex); if (!map) return MechTerrain(mech); c = find_decorations(map, MechX(mech), MechY(mech)); if (c) return c; return MechTerrain(mech); }