From 940f49bc97236a1e44d6e4af199fe6f897111ce8 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Tue, 29 Mar 2016 16:22:47 +0300 Subject: [PATCH] trap switches --- d2dmap.d | 2 +- data/scripts/ai/item.dacs | 2 +- data/scripts/api/actor.dacs | 23 ++++++-- data/scripts/api/monster.dacs | 97 ++++++++++++++++++++++++++++++++++ data/scripts/api/move.dacs | 38 +++++++++++++- data/scripts/api/player.dacs | 102 +++++++++++++++++++++++++++++++++++ data/scripts/api/switch.dacs | 50 +++++++++++++++++- data/scripts/d2dswitches.dacs | 4 +- data/scripts/item/stimpack.dacs | 2 +- data/scripts/switch/dooropen.dacs | 105 +++++++++++-------------------------- data/scripts/switch/trap.dacs | 44 ++++++++++++++++ data/scripts/switch/trapclose.dacs | 26 +++++++++ dengapi.d | 64 +++++++++++++++++++--- 13 files changed, 467 insertions(+), 92 deletions(-) create mode 100644 data/scripts/api/monster.dacs create mode 100644 data/scripts/api/player.dacs rewrite data/scripts/switch/dooropen.dacs (70%) create mode 100644 data/scripts/switch/trap.dacs create mode 100644 data/scripts/switch/trapclose.dacs diff --git a/d2dmap.d b/d2dmap.d index f33eef8..1f38ffa 100644 --- a/d2dmap.d +++ b/d2dmap.d @@ -231,7 +231,7 @@ public: if (type == LightMask) { // in the lightmask texture, we should have only occluders' pixels auto tt = tiles.ptr[Type].ptr[y*MapSize+x]; - if (tt == TILE_WALL || tt == TILE_DOORC) { + if ((tt&0x80) == 0 && (tt == TILE_WALL || tt == TILE_DOORC)) { img.putTile(x*8, y*8, textures.ptr[tiles.ptr[Back].ptr[y*MapSize+x]]); img.putTile(x*8, y*8, textures.ptr[tiles.ptr[Front].ptr[y*MapSize+x]]); } /*else if (tt != TILE_LIFTU && tt != TILE_LIFTD) { diff --git a/data/scripts/ai/item.dacs b/data/scripts/ai/item.dacs index 67ad639..8a3fc27 100644 --- a/data/scripts/ai/item.dacs +++ b/data/scripts/ai/item.dacs @@ -41,7 +41,7 @@ public void itemThinkKey (Actor me) { if (me.classname == "KeyRed") { if (!plr.hasRedKey) { plr.giveRedKey; addMessage("Player picked up red key"); } } if (me.classname == "KeyBlue") { if (!plr.hasBlueKey) { plr.giveBlueKey; addMessage("Player picked up blue key"); } } if (me.classname == "KeyGreen") { if (!plr.hasGreenKey) { plr.giveGreenKey; addMessage("Player picked up green key"); } } - me.actorRemove(); + me.actorMarkDead(); return; } } diff --git a/data/scripts/api/actor.dacs b/data/scripts/api/actor.dacs index fcd4817..0bf7391 100644 --- a/data/scripts/api/actor.dacs +++ b/data/scripts/api/actor.dacs @@ -4,7 +4,7 @@ import apiMap; // for flags // actor declaration -public extern field(Actor) string classtype; +public extern field(Actor) string classtype; // set to "X_X" to schedule actor death public extern field(Actor) string classname; public extern field(Actor) string state; // used in action scripts; also, defines animation public extern field(Actor) int x, y; // coordinates @@ -24,7 +24,7 @@ public field(Actor) uint plrnum; // >0: player public field(Actor) uint invitems; // see INV_ITEM_xxx // for d2d switches -public field(Actor) uint switchabf; // (a<<16)|(b<<8)|flags +public field(Actor) uint switchabf; // (d<<24)|(a<<16)|(b<<8)|flags public /*extern*/ field(Actor) uint tag; // userdata public /*extern*/ field(Actor) int xv, yv; // current velocity @@ -57,6 +57,8 @@ public /*extern*/ field(Actor) int ammo; public /*extern*/ field(Actor) int atm; // anger time for monster (decreasing counter); cooldown time for switch +public void actorMarkDead (Actor me) { me.classtype = "X_X"; } + public auto isPlayer (Actor me) { return (me.plrnum > 0); } public auto isMonster (Actor me) { return (me.classtype == "monster" && me.classname != "Player"); } @@ -212,13 +214,28 @@ public const AF_NOANIMATE = BIT(6); // don't do animation public const AF_CAMERACHICK = BIT(7); // camera will follow this actor; if we have more than one camera chick... well, who knows +// hit types +public const HIT_SOME = BIT(0); +public const HIT_ROCKET = BIT(1); +public const HIT_BFG = BIT(2); +public const HIT_TRAP = BIT(3); +public const HIT_WATER = BIT(4); +public const HIT_ELECTRO = BIT(5); +public const HIT_FLAME = BIT(6); + + public extern int actorsOverlap (Actor a, Actor b) pure; -/// remove actor from scene immediately +/// remove actor from scene immediately; use `actorMarkDead()` instead +/// if you will use this in `*List*()`, everything will break! public extern void actorRemove (Actor me); //TODO: actormarkdead +public extern void actorListRewind (); +public extern Actor actorListNext (); + + // return number of items in touchlist //public extern int actorSetupPossibleTouchList (Actor me); diff --git a/data/scripts/api/monster.dacs b/data/scripts/api/monster.dacs new file mode 100644 index 0000000..69bb477 --- /dev/null +++ b/data/scripts/api/monster.dacs @@ -0,0 +1,97 @@ +module apiMonster; + +import apiActor; +import stdlib; + + +public int MN_hit (Actor me, int damage, Actor owner, int hittype) { + if (!me.isMonster) return false; + writeln("Monster hit by ", damage, "; hittype=", hittype); +/+ + int i; + // + if (mn[n].st == MNST_DEAD || mn[n].st == MNST_DIE) return 0; + if (o == n) { + if (t != HIT_ROCKET && t != HIT_ELECTRO) return 0; + if (mn[n].t == MN_CYBER || mn[n].t == MN_BARREL) return 1; + } + if (o >= 0) { + if (mn[o].t == MN_SOUL && mn[n].t == MN_PAIN) return 0; + if (mn[o].t == mn[n].t) { + switch (mn[n].t) { + case MN_IMP: case MN_DEMON: + case MN_BARON: case MN_KNIGHT: + case MN_CACO: case MN_SOUL: + case MN_MANCUB: case MN_SKEL: + case MN_FISH: + return 0; + } + } + } + if (t == HIT_FLAME) { + if (mn[n].ftime && mn[n].fobj == o) { + if (g_time&31) return 1; + } else { + mn[n].ftime = 255; + mn[n].fobj = o; + } + } + if (t == HIT_ELECTRO && mn[n].t == MN_FISH) { + setst(n, MNST_RUN); + mn[n].s = 20; + mn[n].d = myrandbit(); + return 1; + } + if (t == HIT_TRAP) mn[n].life = -100; + if (mn[n].t == MN_ROBO) d = 0; + if ((mn[n].life -= d) <= 0) --mnum; + if (!mn[n].pain) mn[n].pain = 3; + mn[n].pain += d; + if (mn[n].st != MNST_PAIN && mn[n].pain >= mnsz[mn[n].t].minp) setst(n, MNST_PAIN); + if (mn[n].t != MN_BARREL) DOT_blood(mn[n].o.x, mn[n].o.y-mn[n].o.h/2, hit_xv, hit_yv, d*2); + mn[n].aim = o; + mn[n].atm = 0; + if (mn[n].life <= 0) { + if (mn[n].t != MN_BARREL) { + if (o < 0 && -o >= g_plrcount) ++(pl[(-o)-1].kills); + } + setst(n, MNST_DIE); + switch (mn[n].t) { + case MN_ZOMBY: i = I_CLIP;break; + case MN_SERG: i = I_SGUN;break; + case MN_CGUN: i = I_MGUN;break; + case MN_MAN: i = I_KEYR;break; + default: i = 0; + } + if (i) IT_spawn(mn[n].o.x, mn[n].o.y, i); + mn[n].o.xv = 0; + mn[n].o.h = 6; + if (mn[n].life <= -mnsz[mn[n].t].sp) { + switch (mn[n].t) { + case MN_IMP: + case MN_ZOMBY: + case MN_SERG: + case MN_CGUN: + case MN_MAN: + mn[n].ap = slopanim[mn[n].t-1]; + Z_sound(slopsnd, 128); + break; + case MN_BSP: + if (g_map == 9) break; + // fallthru + default: + Z_sound(dthsnd(mn[n].t), 128); + break; + } + } else if (mn[n].t != MN_BSP || g_map != 9) { + Z_sound(dthsnd(mn[n].t), 128); + } + mn[n].life = 0; + } else if (mn[n].st == MNST_SLEEP) { + setst(n, MNST_GO); + mn[n].pain = mnsz[mn[n].t].mp; + } + // ++/ + return true; +} diff --git a/data/scripts/api/move.dacs b/data/scripts/api/move.dacs index 6aeb6cc..9b8ef03 100644 --- a/data/scripts/api/move.dacs +++ b/data/scripts/api/move.dacs @@ -1,6 +1,7 @@ module apiMove; import apiActor, apiMap, stdlib; +import apiPlayer, apiMonster; const MAX_YV = 30; @@ -355,7 +356,7 @@ public void Z_splash (Actor me, int n, int st) { public void Z_simpleGravity (Actor me) { if (me.flags&AF_NOGRAVITY) return; auto st = Z_moveobj(me); - if (st&Z_FALLOUT) { me.actorRemove; return; } + if (st&Z_FALLOUT) { me.actorMarkDead(); return; } if (st&Z_HITWATER) Z_splash(me, me.radius+me.height, st); } @@ -368,3 +369,38 @@ public void Z_teleobj (Actor me, int x, int y) { me.x = x; me.y = y; } + + +// ////////////////////////////////////////////////////////////////////////// // +public int Z_chktrap (int deadlyTrap, int damage, Actor owner, int hittype) { + int res = 0; + Actor act; + //hit_xv = hit_yv = 0; + + // check players + int pcount = getPlayerCount(); + for (int pnum = 1; pnum <= pcount; ++pnum) { + act = getPlayerActor(pnum); + if (!act.isPlayer || !act) continue; // this player is dead + if (Z_istrapped(act.x, act.y, act.radius, act.height)) { + ++res; + if (!deadlyTrap) return true; + if (deadlyTrap) PL_hit(act, damage, owner, hittype); + } + } + + // check monsters + actorListRewind(); + while ((act = actorListNext())) { + if (!act.isMonster) continue; + if (/*act.t??? &&*/ act.animname != MNST_DEAD) { + if (Z_istrapped(act.x, act.y, act.radius, act.height)) { + ++res; + if (!deadlyTrap) return true; + if (deadlyTrap) MN_hit(act, damage, owner, hittype); + } + } + } + + return res; +} diff --git a/data/scripts/api/player.dacs b/data/scripts/api/player.dacs new file mode 100644 index 0000000..9f71f22 --- /dev/null +++ b/data/scripts/api/player.dacs @@ -0,0 +1,102 @@ +module apiPlayer; + +import apiActor; +import stdlib; + + +public int PL_hit (Actor me, int damage, Actor owner, int hittype) { + if (!me.isPlayer) return false; + writeln("Player hit by ", damage, "; hittype=", hittype); + return true; +} + +/+ +int PL_hit (player_t *p, int d, int o, int t) { + return PL_hit_lc(p, &p->o, d, o, t); + + +int PL_hit_lc (player_t *p, const obj_t *obj, int d, int o, int t) { + if (!d) return 0; + // + if (PL_isinactive(p)) return 0; + // + if (t == HIT_TRAP) { + if (!p_immortal) { + p->armor = 0; + p->life = -100; + } + } else if (t != HIT_ROCKET && t != HIT_ELECTRO) { + if (p->id == -1) { + if (o == -1) return 0; + } else if (o == -2) { + return 0; + } + } + // + if (t != HIT_WATER && t != HIT_ELECTRO) DOT_blood(obj->x, obj->y-15, hit_xv, hit_yv, d*2); + else if (t == HIT_WATER) FX_bubble(obj->x, obj->y-20, 0, 0, d/2); + // + if (p_immortal || p->invl) return 1; + // + p->hit += d; + p->hito = o; + return 1; +} + + +void PL_damage (player_t *p) { + int i; + // + if ((!p->hit && p->life > 0) || PL_isinactive(p)) return; + // + i = p->hit*p->life/nonz(p->armor*3/4+p->life); + p->pain += p->hit; + // + if ((p->armor -= p->hit-i) < 0) { + p->life += p->armor; + p->armor = 0; + } + // + if ((p->life -= i) <= 0) { + if (pl_dies_cb != NULL) pl_dies_cb(p); + // + if (p->life > -30) { + p->st = PLST_DIE; + p->s = 0; + Z_sound(pdsnd[myrand(5)], 128); + } else { + p->st = PLST_SLOP; + p->s = 0; + Z_sound(snd[3], 128); + } + // drop items + if (p->amul > 1) IT_spawn(p->o.x, p->o.y, I_BPACK); + if (!g_dm) { + if (p->keys&0x10) IT_spawn(p->o.x, p->o.y, I_KEYR); + if (p->keys&0x20) IT_spawn(p->o.x, p->o.y, I_KEYG); + if (p->keys&0x40) IT_spawn(p->o.x, p->o.y, I_KEYB); + } + for (i = 1, p->wpns >>= 1; i < 11; ++i, p->wpns >>= 1) { + if (i != 2 && (p->wpns&1)) IT_spawn(p->o.x, p->o.y, wp_it[i]); + } + p->wpns = 5; + p->wpn = PWPN_PISTOL; + p->f |= PLF_PNSND; + // + if (g_dm && g_plrcount > 1) { + if (p->id < 0 && p->hito < 0) { + if (p->id == p->hito) { + // suicide + --pl[(-p->id)+1].frag; + } else { + // frag + ++pl[(-p->hito)+1].kills; + ++pl[(-p->hito)+1].frag; + } + } + } + // + p->life = 0; + } +} ++/ diff --git a/data/scripts/api/switch.dacs b/data/scripts/api/switch.dacs index dd01727..25af97c 100644 --- a/data/scripts/api/switch.dacs +++ b/data/scripts/api/switch.dacs @@ -2,6 +2,7 @@ module apiSwitch; import apiActor; import apiMap; +import apiMove; import stdlib; @@ -14,6 +15,8 @@ public const SW_KEY_G = BIT(5); public const SW_KEY_B = BIT(6); +public int switchGetD (Actor me) { return (me.switchabf>>24)&0xff; } +public void switchSetD (Actor me, int d) { me.switchabf = (me.switchabf&0x00ffffffU)|((d&0xff)<<24); } public int switchGetA (Actor me) { return (me.switchabf>>16)&0xff; } public int switchGetB (Actor me) { return (me.switchabf>>8)&0xff; } public int switchGetFlags (Actor me) { return (me.switchabf&0xff); } @@ -82,11 +85,56 @@ public void switchOpenDoor (Actor me) { //chto = 3; //chf = 0; //f_ch = 1; - processDoor(a, b, TILE_DOORC, TILE_DOORO, 0, 1); + processDoor(a, b, TILE_DOORC, TILE_DOORO, 0, true); mapSetTile(LAYER_FRONT, a, b, j); } +public int switchShutDoor (Actor me) { + int a = me.switchGetA(); + int b = me.switchGetB(); + //int cht = TILE_DOORO; + //int chto = TILE_ACTTRAP; + int chf = mapGetTile(LAYER_FRONT, a, b); + //int f_ch = 1; + processDoor(a, b, TILE_DOORO, TILE_ACTTRAP, chf, true); + //cht = TILE_ACTTRAP; + if (Z_chktrap(false, 0, null, HIT_SOME)) { + int j = mapGetTile(LAYER_FRONT, a, b); + //chto = 3; + //chf = 0; + //f_ch = 1; + processDoor(a, b, TILE_ACTTRAP, TILE_DOORO, 0, true); + mapSetTile(LAYER_FRONT, a, b, j); + return false; + } + //chto = 2; + processDoor(a, b, TILE_ACTTRAP, TILE_DOORC, chf, true); + //swsnd = Z_sound(sndbdc, 128); + return true; +} + + +public int switchShutTrap (Actor me) { + int a = me.switchGetA(); + int b = me.switchGetB(); + if (mapGetTypeTile(a, b) != TILE_DOORO) return false; + //cht = TILE_DOORO; + //chto = TILE_ACTTRAP; + int chf = mapGetTile(LAYER_FRONT, a, b); + //f_ch = 1; + processDoor(a, b, TILE_DOORO, TILE_ACTTRAP, chf, true); + Z_chktrap(true, 100, null, HIT_TRAP); + //cht = TILE_ACTTRAP; + //chto = TILE_DOORC; + processDoor(a, b, TILE_ACTTRAP, TILE_DOORC|0x80, chf, true); + //swsnd = Z_sound(sndswn, 128); + me.atm = 1; + me.switchSetD(20); + return true; +} + + // `x` and `y` in tiles void processDoor (int x, int y, int cht, int chto, int chf, int f_ch) { if (x < 0 || y < 0 || x >= FLDW || y >= FLDH) return; diff --git a/data/scripts/d2dswitches.dacs b/data/scripts/d2dswitches.dacs index 453e4d2..2b995f6 100644 --- a/data/scripts/d2dswitches.dacs +++ b/data/scripts/d2dswitches.dacs @@ -4,7 +4,7 @@ module d2dswitches; //import switchExitsecret; // SW_EXITS import switchDooropen; // SW_OPENDOOR //import switchDoorclose; // SW_SHUTDOOR -//import switchTrapclose; // SW_SHUTTRAP +import switchTrapclose; // SW_SHUTTRAP //import switchDoor; // SW_DOOR //import switchDoor5; // SW_DOOR5 //import switchPress; // SW_PRESS @@ -12,6 +12,6 @@ import switchTeleport; // SW_TELE //import switchSecret; // SW_SECRET //import switchLiftup; // SW_LIFTUP //import switchLiftdown; // SW_LIFTDOWN -//import switchTrap; // SW_TRAP +import switchTrap; // SW_TRAP //import switchLift; // SW_LIFT //import switchWingame; // SW_WINGAME diff --git a/data/scripts/item/stimpack.dacs b/data/scripts/item/stimpack.dacs index 9a011a8..2d330d1 100644 --- a/data/scripts/item/stimpack.dacs +++ b/data/scripts/item/stimpack.dacs @@ -48,7 +48,7 @@ public void think (Actor me) { if (other.isPlayer) { writeln("actor took medkit!"); addMessage("actor took medkit!"); - me.actorRemove; + me.actorMarkDead(); return; } } diff --git a/data/scripts/switch/dooropen.dacs b/data/scripts/switch/dooropen.dacs dissimilarity index 70% index c95d6fa..000678c 100644 --- a/data/scripts/switch/dooropen.dacs +++ b/data/scripts/switch/dooropen.dacs @@ -1,75 +1,30 @@ -module switchDooropen is "switch" "DoorOpen"; - -import apiActor; -import apiMap; -import apiSwitch; -import stdlib; - - -// setup actor properties -public void initialize (Actor me) { - //me.radius = 10; - //me.height = 8; -} - - -// thinker -public void think (Actor me) { - // we can directly check for player overlap, but i want to test hitlists - //writeln("stimpack: think"); - /* - rewindTouchList(); - for (Actor other = getNextTouchListItem; other; other = getNextTouchListItem) { - //if (me.x < 32) writeln("stimpack: other=", other.classname); - if (other.isPlayer) { - writeln("actor took medkit!"); - addMessage("actor took medkit!"); - me.actorRemove; - return; - } - } - */ - - if (me.atm > 0) { - --me.atm; - return; - } - - me.atm = 0; // just in case - - auto toucher = me.switchWhoTouched(); - if (toucher && toucher.isPlayer) { - me.atm = 9; // cooldown time - switchOpenDoor(me); - } - -/+ - int pcount = getPlayerCount(); - for (int pnum = 1; pnum <= pcount; ++pnum) { - auto btn = getPlayerButtons(pnum); - bool press = ((btn&PLK_USE) != 0); - - auto plr = getPlayerActor(pnum); - if (!me.switchTouch(plr, press)) return; - - /+ - int x = plr.x, y = plr.y; - int sx = (x-plr.radius)/CELW; - int sy = (y-plr.height+1)/CELH; - x = (x+plr.radius)/CELW; - y /= CELH; - - int myx = me.x/CELW; - int myy = me.y/CELH; - - if (myx >= sx && myx <= x && myy >= sy && myy <= y /*&& ((sw[i].f&0x8F)&t)*/) { - //writeln("duropen by player ", pnum); - me.atm = 9; // cooldown time - switchOpenDoor(me); - } - +/ - me.atm = 9; // cooldown time - me.switchOpenDoor; - } -+/ -} +module switchDooropen is "switch" "DoorOpen"; + +import apiActor; +import apiMap; +import apiSwitch; +import stdlib; + + +// setup actor properties +public void initialize (Actor me) { + //me.radius = 10; + //me.height = 8; +} + + +// thinker +public void think (Actor me) { + if (me.atm > 0) { + --me.atm; + return; + } + + me.atm = 0; // just in case + + auto toucher = me.switchWhoTouched(); + if (toucher && toucher.isPlayer) { + me.atm = 9; // cooldown time + switchOpenDoor(me); + } +} diff --git a/data/scripts/switch/trap.dacs b/data/scripts/switch/trap.dacs new file mode 100644 index 0000000..c54003c --- /dev/null +++ b/data/scripts/switch/trap.dacs @@ -0,0 +1,44 @@ +module switchTrap is "switch" "Trap"; + +import apiActor; +import apiMap; +import apiMove; +import apiSwitch; +import stdlib; + + +// setup actor properties +public void initialize (Actor me) { +} + + +void doThink (Actor me) { + int d = me.switchGetD(); + if (!d) return; + int a = me.switchGetA(); + int b = me.switchGetB(); + if (mapGetTypeTile(a, b) != TILE_DOORC) { + me.switchSetD(0); + return; + } + if (--d == 0) { + switchOpenDoor(me); + me.atm = 18; + } + me.switchSetD(d); +} + + +// thinker +public void think (Actor me) { + if (me.atm > 0) { + --me.atm; + return; + } + + me.atm = 0; // just in case + doThink(me); + + auto toucher = me.switchWhoTouched(); + if (toucher) switchShutTrap(me); +} diff --git a/data/scripts/switch/trapclose.dacs b/data/scripts/switch/trapclose.dacs new file mode 100644 index 0000000..b202de8 --- /dev/null +++ b/data/scripts/switch/trapclose.dacs @@ -0,0 +1,26 @@ +module switchTrapclose is "switch" "TrapClose"; + +import apiActor; +import apiMap; +import apiMove; +import apiSwitch; +import stdlib; + + +// setup actor properties +public void initialize (Actor me) { +} + + +// thinker +public void think (Actor me) { + if (me.atm > 0) { + --me.atm; + return; + } + + me.atm = 0; // just in case + + auto toucher = me.switchWhoTouched(); + if (toucher) switchShutTrap(me); +} diff --git a/dengapi.d b/dengapi.d index 870801e..aa91475 100644 --- a/dengapi.d +++ b/dengapi.d @@ -348,7 +348,12 @@ void setupDAPI () { FuncPool["getPlayerButtons"] = function uint (uint pidx) { return (pidx == 1 ? plrKeysLast : 0); }; FuncPool["mapGetTypeTile"] = function int (int x, int y) { - return (map !is null && x >= 0 && y >= 0 && x < map.width && y < map.height ? map.tiles.ptr[LevelMap.Type].ptr[y*map.width+x] : 0); + int res = 0; + if (map !is null && x >= 0 && y >= 0 && x < map.width && y < map.height) { + res = map.tiles.ptr[LevelMap.Type].ptr[y*map.width+x]; + if (res != LevelMap.TILE_ACTTRAP) res &= 0x7f; + } + return res; }; FuncPool["mapGetTile"] = function int (uint layer, int x, int y) { @@ -404,11 +409,19 @@ void setupDAPI () { FuncPool["actorsOverlap"] = function int (ActorId a, ActorId b) { return (actorsOverlap(a, b) ? 1 : 0); }; - FuncPool["actorRemove"] = function void (ActorId me) { Actor.remove(me); }; + FuncPool["actorRemove"] = function void (ActorId me) { + if (me.valid) { + if ((me.flags!uint&AF_NOCOLLISION) == 0) ugActorModify!false(me); // remove from grid + Actor.remove(me); + } + }; FuncPool["rewindTouchList"] = &rewindTouchList; FuncPool["getNextTouchListItem"] = &getNextTouchListItem; + FuncPool["actorListRewind"] = &xactorListRewind; + FuncPool["actorListNext"] = &xactorListNext; + FuncPool["getCheatNoDoors"] = function int () { import render : cheatNoDoors; return (cheatNoDoors ? 1 : 0); }; FuncPool["getCheatNoWallClip"] = function int () { import render : cheatNoWallClip; return (cheatNoWallClip ? 1 : 0); }; FuncPool["getCheatNoCeilClip"] = function int () { return 0; }; @@ -593,6 +606,35 @@ public void loadMapMonsters () { // ////////////////////////////////////////////////////////////////////////// // +__gshared ActorId[65536] xactorList; // aids +__gshared uint xactorListCount, xactorListIndex = uint.max; + + +// dacs API +void xactorListRewind () { + if (!touchListAllowed) return; // it's ok to reuse it here + xactorListCount = xactorListIndex = 0; + Actor.forEach((ActorId me) { + if (me.fget_classtype != StrPool.X_X) xactorList.ptr[xactorListCount++] = me; + }); +} + + +// dacs API +ActorId xactorListNext () { + if (!touchListAllowed) return ActorId(0); // it's ok to reuse it here + if (xactorListIndex == uint.max) xactorListRewind(); + while (xactorListIndex < xactorListCount) { + auto aid = xactorList.ptr[xactorListIndex]; + ++xactorListIndex; + if (aid.fget_classtype == StrPool.X_X) continue; + return aid; + } + return ActorId(0); +} + + +// ////////////////////////////////////////////////////////////////////////// // __gshared uint[65536] touchList; // aids __gshared uint[] realTouchList; __gshared uint realTouchListIndex = uint.max; @@ -615,34 +657,37 @@ ActorId getNextTouchListItem () { while (realTouchListIndex < realTouchList.length) { auto aid = ActorId(realTouchList.ptr[realTouchListIndex]); ++realTouchListIndex; - if (aid.valid && (aid.flags!uint&AF_NOONTOUCH) == 0) return aid; + if (aid.fget_classtype == StrPool.X_X) continue; + if (aid.valid && (aid.fget_flags&AF_NOONTOUCH) == 0) return aid; } return ActorId(0); } public void doActorsThink () { - //FIXME - //static uint fflags = uint.max; - //if (fflags == uint.max) fflags = Actor.fields["flags"].ofs; - // we have too much memory! __gshared uint[65536] validActorsList; + __gshared ActorId[65536] postponedDeath; + __gshared uint pdcount; touchListAllowed = true; scope(exit) touchListAllowed = false; + pdcount = 0; foreach (uint xid; Actor.getValidList(validActorsList[])) { auto me = ActorId(xid); if (me.valid) { + if (me.fget_classtype == StrPool.X_X) { postponedDeath.ptr[pdcount++] = me; continue; } auto flags = me.fget_flags; if ((flags&AF_NOCOLLISION) == 0) ugActorModify!false(me); // remove from grid if (auto adef = findActorDef(me)) { if ((flags&AF_NOTHINK) == 0) { realTouchListIndex = uint.max; + xactorListIndex = uint.max; curThinkingActor = me; adef.callThink(me); //if (me.x!int < 32) conwriteln("actor: ", me.id, "; attLightRGBX=", me.attLightRGBX!uint); if (!me.valid) continue; // we are dead + if (me.fget_classtype == StrPool.X_X) { postponedDeath.ptr[pdcount++] = me; continue; } flags = me.fget_flags; // in case script updated flags } if ((flags&AF_NOANIMATE) == 0) { @@ -657,6 +702,11 @@ public void doActorsThink () { } } } + // process scheduled death + foreach (ActorId aid; postponedDeath[0..pdcount]) { + Actor.remove(aid); + } + // reset player keys plrKeysFix(0); //{ import std.stdio : stdout; stdout.writeln("========================================="); } //Actor.dumpActors(); -- 2.11.4.GIT