btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * $Id: scen.c,v 1.1.1.1 2005/01/11 21:18:32 kstevens Exp $
 *
 * Author: Markus Stenberg <fingon@iki.fi>
 *
 *  Copyright (c) 1997 Markus Stenberg
 *  Copyright (c) 1998-2002 Thomas Wouters
 *  Copyright (c) 2000-2002 Cord Awtry 
 *       All rights reserved
 *
 * Created: Sun Oct 19 19:44:29 1997 fingon
 * Last modified: Sat Jun  6 22:25:54 1998 fingon
 *
 */

#include "create.h"
#include "mech.h"
#include "glue.h"
#include "scen.h"

#include "coolmenu.h"
#include "mycool.h"
#include "p.mech.utils.h"

void do_destroy(dbref player, dbref cause, int key, char *what);
dbref match_thing(dbref player, char *name);
char *get_uptime_to_string(int uptime);

dbref scen_map_ref(SCEN * s)
{
    char buf3[LBUF_SIZE];
    dbref d;

    if (!bt_get_attr(buf3, s->mynum, "MAP_REF"))
	return -1;
    d = match_thing(GOD, buf3);
    return d;

}

dbref scen_weather_ref(SCEN * s)
{
    char buf3[LBUF_SIZE];
    dbref d;

    if (!bt_get_attr(buf3, s->mynum, "WEATHER_REF"))
	return -1;
    d = match_thing(GOD, buf3);
    return d;

}

MAP *scen_map(SCEN * s)
{
    return FindObjectsData(scen_map_ref(s));
}

#define MySafe(i) (Flags((i)) & SAFE)

void newfreescen(dbref key, void **data, int sel)
{
    SCEN *new;
    SSIDE *si;
    SSOBJ *ob;
    SSINS *in;
    SSEXT *ex;
    MAP *map, *ma;
    mapobj *o;
    MECH *mech, *tm;

    int d, d1, d2, d3, d4;

    /* Make things go *bang* ;-) */

    if (sel == SPECIAL_FREE) {
	new = *data;

	if ((map = scen_map(new))) {
	    /* Destroy everything on map, and (try to) destroy hangars
	       involved as well. Therefore marking non-stupid hangars
	       'safe' is a wise move ;-) */
	    LOOP_MAP_MECHS(mech, map, d4) {
		if (!MySafe(mech->mynum)) {
		    LOOP_DS_BAYS(d, mech, d2) {
			ma = FindObjectsData(d);
			LOOP_MAP_MECHS(tm, ma, d3)
			    do_destroy(GOD, GOD, 0, tprintf("#%d",
				tm->mynum));
			do_destroy(GOD, GOD, 0, tprintf("#%d", ma->mynum));
		    }
		    do_destroy(GOD, GOD, 0, tprintf("#%d", mech->mynum));
		}
	    }

	    LOOP_MAP_MAPLINKS_REF(d3, map, o) {
		if (!MySafe(d3)) {
		    ma = FindObjectsData(d3);
		    LOOP_MAP_MECHS(mech, ma, d4)
			do_destroy(GOD, GOD, 0, tprintf("#%d",
			    mech->mynum));
		    do_destroy(GOD, GOD, 0, tprintf("#%d", d3));
		}
	    }
	    do_destroy(GOD, GOD, 0, tprintf("#%d", map->mynum));
	}
	if ((d = scen_weather_ref(new)))
	    do_destroy(GOD, GOD, 0, tprintf("#%d", d));
	LOOP_THRU_SIDES(si, new, d1) {
	    LOOP_THRU_OBJECTIVES(ob, si, d2)
		do_destroy(GOD, GOD, 0, tprintf("#%d", ob->mynum));
	    LOOP_THRU_INSERTIONS(in, si, d2)
		do_destroy(GOD, GOD, 0, tprintf("#%d", in->mynum));
	    LOOP_THRU_EXTRACTIONS(ex, si, d2)
		do_destroy(GOD, GOD, 0, tprintf("#%d", ex->mynum));
	    do_destroy(GOD, GOD, 0, tprintf("#%d", si->mynum));
	}
    }
}

SCEN *Map_in_Valid_SO(MAP * map)
{
    dbref d;
    SCEN *s;

    if (!map)
	return NULL;
    d = Location(map->mynum);
    if (Hardcode(d))
	if (WhichSpecial(d) == GTYPE_SCEN) {
	    s = FindObjectsData(d);
	    if (s->state != 1)
		return NULL;
	    return s;
	}
    return NULL;
}


void scen_set_osucc(SSOBJ * o, int val)
{
    char buf[LBUF_SIZE];
    char buf2[LBUF_SIZE];

    if (o->state != val) {
	strcpy(buf, Name(Location(Location(o->mynum))));
	strcpy(buf2, Name(Location(o->mynum)));
	ScenStatus("In %s/%s/%s - %d => %d", buf, buf2, Name(o->mynum),
	    o->state, val);
	o->state = val;
    }
}

static int location_matches_xy(SSOBJ * ob, int x, int y)
{
    char buf[LBUF_SIZE];
    int myx, myy;

    if (bt_get_attr(buf, ob->mynum, "LOCATION"))
	if (sscanf(buf, "%d %d", &myx, &myy) >= 2)
	    if (myx == x && myy == y)
		return 1;
    return 0;
}


void scen_trigger_mine(MAP * map, MECH * mech, int x, int y)
{
    SCEN *s;
    SSIDE *si;
    SSOBJ *ob;
    char buf[LBUF_SIZE];
    dbref d1, d2;

    if (!(s = Map_in_Valid_SO(map)))
	return;
    LOOP_THRU_SIDES(si, s, d1)
	LOOP_THRU_OBJECTIVES(ob, si, d2) {
	if (!bt_get_attr(buf, ob->mynum, "TYPE"))
	    continue;
	if (strcmp(buf, "hex"))
	    continue;
	if (!location_matches_xy(ob, x, y))
	    continue;
	if (!bt_get_attr(buf, ob->mynum, "GOAL"))
	    continue;
	if (!strcmp(buf, "recon"))
	    if (scen_mech_in_side(mech, si))
		scen_set_osucc(ob, 100);
	if (!strcmp(buf, "capture"))
	    scen_set_osucc(ob, scen_mech_in_side(mech, si) ? 100 : 0);
	if (!strcmp(buf, "defend"))
	    if (!scen_mech_in_side(mech, si))
		scen_set_osucc(ob, 0);

    }
}

void scen_base_generic(MAP * map, MECH * mech, mapobj * o, char *type,
    int val, int sside)
{
    SCEN *s;
    SSIDE *si;
    SSOBJ *ob;
    char buf[LBUF_SIZE];
    dbref d1, d2;

    if (!(s = Map_in_Valid_SO(map)))
	return;
    LOOP_THRU_SIDES(si, s, d1)
	LOOP_THRU_OBJECTIVES(ob, si, d2) {
	if (!bt_get_attr(buf, ob->mynum, "TYPE"))
	    continue;
	if (strcmp(buf, "base"))
	    continue;
	if (!location_matches_xy(ob, o->x, o->y))
	    continue;
	if (!bt_get_attr(buf, ob->mynum, "GOAL"))
	    continue;
	if (!strcmp(buf, type))
	    if (!sside || scen_mech_in_side(mech, si))
		scen_set_osucc(ob, val);
    }
}

void scen_see_base(MAP * map, MECH * mech, mapobj * o)
{
    scen_base_generic(map, mech, o, "recon", 100, 1);
}

void scen_damage_base(MAP * map, MECH * mech, mapobj * o)
{
    scen_base_generic(map, mech, o, "damage", 100, 1);
}

void scen_destroy_base(MAP * map, MECH * mech, mapobj * o)
{
    scen_base_generic(map, mech, o, "destroy", 100, 1);
    scen_base_generic(map, mech, o, "defend", 0, 0);
}


/* Unimplemented or unfinished */

void scen_start_oods(SCEN * s)
{

}

void scen_update_enemy(int *now, int *best, int mode, MECH * ds,
    MECH * mech)
{
    /* For now, we just handle the 0 = damage, 1 = destroy */
    /* 0 scores are calculated by present / maximum int+armor (if not dest'ed, otherwise max int+armor for both) */
    int i, j, k;

    if (mode == 0) {
	for (i = 0; i < NUM_SECTIONS; i++) {
	    j = GetSectOArmor(mech, i) + GetSectORArmor(mech,
		i) + GetSectOInt(mech, i);
	    k = GetSectArmor(mech, i) + GetSectRArmor(mech,
		i) + GetSectInt(mech, i);
	    if (Destroyed(mech))
		k = j;
	    else
		k = j - k;
	    *best += j;
	    *now += k;
	}
	return;
    }
    if (mode == 1) {
	(*best)++;
	if (Destroyed(mech))
	    (*now)++;
	return;
    }
}

int scen_update_enemies(SSIDE * si, MAP * map, int dest)
{
    int i, i2, i3;
    dbref d;
    MECH *mech, *tm;
    int score_n = 0, score_m = 0;
    MAP *ma;
    mapobj *o;

    if (!map)
	return 1;
    LOOP_MAP_MECHS(mech, map, i) {
	if (IsDS(mech)) {
	    /* Do not count DS itself, but count stuff inside DS */
	    LOOP_DS_BAYS(d, mech, i2) {
		ma = FindObjectsData(d);
		LOOP_MAP_MECHS(tm, ma, i3)
		    scen_update_enemy(&score_n, &score_m, dest, mech, tm);
	    }
	}
    }
    LOOP_MAP_MAPLINKS_REF(d, map, o) {
	ma = FindObjectsData(d);
	LOOP_MAP_MECHS(tm, ma, i3)
	    scen_update_enemy(&score_n, &score_m, dest, NULL, tm);
    }
    if (!score_m)
	return 100;
    return 100 * score_n / score_m;
}

void scen_update_goal(SCEN * s, SSIDE * si, SSOBJ * ob)
{
    char buf[LBUF_SIZE];
    char buf2[LBUF_SIZE];
    char buf3[LBUF_SIZE];
    dbref d;
    MECH *mech;
    int i, j;

    if (!bt_get_attr(buf, ob->mynum, "TYPE"))
	return;
    if (!bt_get_attr(buf2, ob->mynum, "GOAL"))
	return;
    if (!strcmp(buf, "unit") || !strcmp(buf, "existing unit")) {
	/* Base success on what has happened to the unit */
	/* Note: You HAVE to !claim mech for capture objective to work */
	if (!bt_get_attr(buf3, s->mynum, "REF"))
	    return;
	d = match_thing(GOD, buf3);
	if (d <= 0)
	    return;
	if (!(mech = getMech(d)))
	    return;
	if (!strcmp(buf2, "capture")) {
	    if (!Destroyed(mech))
		scen_set_osucc(ob, scen_mech_in_side(mech, si) ? 100 : 0);
	    return;
	}
	if (!strcmp(buf2, "damage")) {
	    i = j = 0;
	    scen_update_enemy(&i, &j, 0, NULL, mech);
	    scen_set_osucc(ob, j > 0 ? 100 * i / j : 0);
	    return;
	}
	if (!strcmp(buf2, "destroy")) {
	    if (Destroyed(mech))
		scen_set_osucc(ob, 100);
	    return;
	}
	if (!strcmp(buf2, "defend")) {
	    if (Destroyed(mech))
		scen_set_osucc(ob, 0);
	    return;
	}
	return;
    }
    if (!strcmp(buf, "enemies")) {
	/* Enemy 'location' :
	   on main map
	   in any hangar on map
	   in any DS on map
	 */

	if ((d = scen_map_ref(s)) <= 0)
	    return;
	if (!strcmp(buf2, "capture"))
	    scen_set_osucc(ob, scen_update_enemies(si, FindObjectsData(d),
		    -1));
	if (!strcmp(buf2, "damage"))
	    scen_set_osucc(ob, scen_update_enemies(si, FindObjectsData(d),
		    0));
	if (!strcmp(buf2, "destroy"))
	    scen_set_osucc(ob, scen_update_enemies(si, FindObjectsData(d),
		    1));
    }
}



void scen_start(dbref player, void *data, char *buffer)
{
    SCEN *s = (SCEN *) data;

    if (!s)
	return;
    DOCHECK(s->state > 0, "This scenario has been already started.");
    ScenStatus("Scenario #%d (%s) has been engaged by #%d", s->mynum,
	Name(s->mynum), player);
    s->state = 1;
    s->start_t = mudstate.now;
    scen_start_oods(s);
}

void scen_tport_players(dbref from, int death)
{
    dbref i, tmpnext;
    int to;

    SAFE_DOLIST(i, tmpnext, Contents(from))
	if (!Wiz(i))
	if (isPlayer(i)) {
	    to = death ? mudconf.afterlife_dbref : mudconf.afterscen_dbref;
	    hush_teleport(i, to);
	}
}

void scen_handle_mech_extraction(SCEN * s, MAP * map, MECH * mech)
{
    SSIDE *si;
    dbref d;
    int d1, d2, d3, d4;
    int succ = 0;
    char buf[LBUF_SIZE];
    MECH *ds;
    float x1, y1;
    int x, y, r;
    SSEXT *ex;

    /* First off, figure side we're on */
    LOOP_THRU_SIDES(si, s, d1)
	if (scen_mech_in_side(mech, si)) {
	/* Extraction blues */
	LOOP_THRU_EXTRACTIONS(ex, si, d2) {
	    if (bt_get_attr(buf, ex->mynum, "TYPE")) {
		if (!strcmp(buf, "dropship pickup")) {
		    /* Basically, we should be onboard a DS */
		    if (bt_get_attr(buf, ex->mynum, "DBREF")) {
			d = match_thing(GOD, buf);
			if (d >= 0 && (ds = FindObjectsData(d))) {
			    LOOP_DS_BAYS(d3, ds, d4) {
				if (d3 == mech->mapindex)
				    succ = 1;
				break;
			    }
			}
		    }
		} else if (!strcmp(buf, "base")) {
		    if (bt_get_attr(buf, ex->mynum, "DBREF")) {
			d = match_thing(GOD, buf);
			if (mech->mapindex == d)
			    succ = 1;
		    }
		} else if (!strcmp(buf, "leaving map")) {
		    /* Determine whether we're on the main map or not */
		    if (scen_map_ref(s) == mech->mapindex) {
			if (bt_get_attr(buf, ex->mynum, "LOCATION"))
			    if (sscanf(buf, "%d %d %d", &x, &y, &r) == 3) {
				/* Hm, calculate distance to the hex,
				   and judge succ by it */
				MapCoordToRealCoord(x, y, &x1, &y1);
				if (FindRange(MechFX(mech), MechFY(mech),
					MechFZ(mech), x1, y1, 0) < r)
				    succ = 1;
			    }
		    }
		}
	    }
	    if (succ)
		break;
	}
	break;
    }
    /* Hm, for now we don't do a thing to mechs with failed extraction
       (except for sending the pilots to limbo, muah) */
    scen_tport_players(mech->mynum, !succ);
}

static void ext_check(SCEN * s)
{
    MAP *map = scen_map(s), *ma;
    MECH *mech, *tm;
    dbref d;
    int i1, i2, i3;
    mapobj *o;

    if (!map)
	return;
    LOOP_MAP_MECHS(mech, map, i1) {
	if (IsDS(mech)) {
	    LOOP_DS_BAYS(d, mech, i2) {
		ma = FindObjectsData(d);
		LOOP_MAP_MECHS(tm, ma, i3)
		    scen_handle_mech_extraction(s, ma, tm);
		scen_tport_players(d, 0);
	    }
	    scen_tport_players(mech->mynum, 0);
	    s_Zombie(mech->mynum);
	} else
	    scen_handle_mech_extraction(s, map, mech);
    }
    LOOP_MAP_MAPLINKS_REF(d, map, o) {
	ma = FindObjectsData(d);
	LOOP_MAP_MECHS(tm, ma, i3)
	    scen_handle_mech_extraction(s, ma, tm);
	scen_tport_players(d, 0);
    }
}

void scen_end(dbref player, void *data, char *buffer)
{
    SCEN *s = (SCEN *) data;
    SSIDE *si;
    SSOBJ *ob;
    dbref d1, d2;

    if (!s)
	return;
    DOCHECK(!s->state, "This scenario hasn't been even started yet.");
    DOCHECK(s->state == 2, "This scenario has already ended.");
    ScenStatus("Scenario #%d (%s) has been ended by #%d", s->mynum,
	Name(s->mynum), player);
    ext_check(s);
    LOOP_THRU_SIDES(si, s, d1)
	LOOP_THRU_OBJECTIVES(ob, si, d2)
	scen_update_goal(s, si, ob);
    s->end_t = mudstate.now;
    s->state = 2;
}

void show_goals_side(coolmenu * c, SCEN * s, SSIDE * si)
{
    SSOBJ *ob;
    dbref d2;
    char buf[LBUF_SIZE];
    int wscore = 0, score = 0, wgoals = 0, goals = 0, pri, iswin;

    LOOP_THRU_OBJECTIVES(ob, si, d2) {
	scen_update_goal(s, si, ob);
	if (!bt_get_attr(buf, ob->mynum, "TYPE"))
	    continue;
	if (!goals)
	    vsi(tprintf("Objective status for side %s",
		    si->slet ? si->slet : "?"));
	addmenu4(tprintf(" %s", buf));
	bt_get_attr(buf, ob->mynum, "GOAL");
	addmenu4(buf);
	bt_get_attr(buf, ob->mynum, "LOCATION");
	addmenu4(buf);
	addmenu4(tprintf("%d", s->state));

	goals++;
	bt_get_attr(buf, ob->mynum, "PRIORITY");
	pri = 1;
	iswin = 1;
	if (!strcmp(buf, "secondary"))
	    pri = 2;
	else if (!strcmp(buf, "optional")) {
	    pri = 3;
	    iswin = 0;
	}
	if (iswin) {
	    wgoals++;
	    wscore += s->state / pri;
	}
	score += s->state / pri;
    }
    if (wgoals) {
	addmenu4(tprintf("WSc:%d(%d)", wscore, wgoals));
	addmenu4(tprintf("WScW:%d", wscore / wgoals));
    }
    if (goals && wgoals != goals) {
	addmenu4(tprintf("Sc:%d(%d)", score, goals));
	addmenu4(tprintf("ScW:%d", score / goals));
    }
}

void show_goals(coolmenu * c, SCEN * s, char *side)
{
    SSIDE *si;
    dbref d1;

    LOOP_THRU_SIDES(si, s, d1) {
	if (side && *side) {
	    if (!strcmp(side, si->slet))
		show_goals_side(c, s, si);
	} else
	    show_goals_side(c, s, si);
    }
}

void scen_status(dbref player, void *data, char *buffer)
{
    SCEN *s = (SCEN *) data;
    char *temp;
    char *scen_states[] = { "Initialized", "Running", "Ended" };
    coolmenu *c = NULL;

    if (!s)
	return;
    addline();
    cent(tprintf("Status for %s", Name(s->mynum)));
    addline();
    vsi(tprintf("State of this scenario: %s", scen_states[s->state]));
    if (s->state == 1)
	vsi(tprintf("Uptime: %s",
		get_uptime_to_string(mudstate.now - s->start_t)));
    if (s->state == 2) {
	temp = (char *) ctime(&s->start_t);
	temp[strlen(temp) - 1] = '\0';
	addmenu(tprintf("Started: %s", temp));
	temp = (char *) ctime(&s->end_t);
	temp[strlen(temp) - 1] = '\0';
	addmenu(tprintf("Ended: %s", temp));
	vsi(tprintf("Duration: %s",
		get_uptime_to_string(s->end_t - s->start_t)));
    }
    addline();
    if (*buffer)
	show_goals(c, s, buffer);
    else
	show_goals(c, s, NULL);
    addline();
    ShowCoolMenu(player, c);
    KillCoolMenu(c);
}