/* * $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); }