WarmReception

Table of Contents

{ "old_version": "0.4.0" }

1. About

WarmReception is a minimod for UZDoom that alters enemy behavior on level start.

With this mod, you can either make your life harder by aggravating every enemy from the start or disable hot starts.

WarmReception is a part of DoomToolbox.

Options:

  • Wake every enemy on a level (optionally even enemies in ambush), or
  • Don't change original behavior, or
  • Turn away enemies that look at you at level start, or
  • Turn enemies to you at level start.

Known issues:

2. Changelog

v0.4.0

  • made more multiplayer-friendly
  • add separate switches for enemies at start, in ambush, and others
  • ignore visibility for checks
  • add random turn option

v0.3.1

  • fix Warm Reception affecting summoned actors
  • update build script
  • add Downloads shield to Readme

v0.3

  • add an option to kill monsters at start
  • add an option to remove enemies at start
  • add description to build.sh and fix shellcheck warnings

v0.2.1

  • fix modifying behavior of modded enemies

v0.2

  • add an option to imitate hot starts
  • add an option to wake even enemies in ambush
  • fix turning away monsters
  • lower GZDoom version requirement

v0.1: initial release

3. License

GPL-3.0-only

SPDX-FileCopyrightText: © 2020 Alexander Kromm (m8f) <mmaulwurff@gmail.com>
SPDX-License-Identifier: GPL-3.0-only

4. Menu

TODO: use PlainTranslator?

AddOptionMenu OptionsMenu       { Submenu "$wr_Title", wr_Menu }
AddOptionMenu OptionsMenuSimple { Submenu "$wr_Title", wr_Menu }

OptionMenu wr_Menu
{
  Title "$wr_Title"

  Option "$wr_Start",  wr_start,  wr_Actions
  Option "$wr_Ambush", wr_ambush, wr_SafeActions
  Option "$wr_Other",  wr_other,  wr_SafeActions
}

OptionValue wr_Actions
{
  0, "$wr_Keep"
  1, "$wr_Wake"
  2, "$wr_TurnAway"
  3, "$wr_TurnTowards"
  4, "$wr_TurnRandomly"
  5, "$wr_Kill"
  6, "$wr_Remove"
}

OptionValue wr_SafeActions
{
  0, "$wr_Keep"
  1, "$wr_Wake"
  2, "$wr_TurnAway"
  3, "$wr_TurnTowards"
  4, "$wr_TurnRandomly"
}
[enu default]

wr_Title       = "WarmReception \ci♨";

wr_Keep        = "Keep as is";
wr_Wake        = "Wake up (may wake up others)";
wr_TurnAway    = "Turn away from player";
wr_TurnTowards = "Turn towards player";
wr_TurnRandomly = "Turn to a random direction";
wr_Kill        = "Kill (when alerted)";
wr_Remove      = "Remove (may break scripts)";

wr_Start       = "Enemies at start";
wr_Ambush      = "Enemies in ambush";
wr_Other       = "Other enemies";

5. Source

// See wr_EventHandler.Mode enum for values.
server int wr_start  = 2;
server int wr_other  = 0;
server int wr_ambush = 0;
class wr_EventHandler : EventHandler
{
  override void worldTick()
  {
    if (level.mapName ~== "titlemap" || level.mapTime > 4) destroy();
  }

  override void worldThingSpawned(WorldEvent event)
  {
    if (players[Net_Arbitrator].mo == NULL) return;
    if (event.thing == NULL || !event.thing.bIsMonster) return;

    if (isAtStart(event.thing))   act(event.thing, wr_start);
    else if (event.thing.bAmbush) act(event.thing, wr_ambush);
    else                          act(event.thing, wr_other);
  }

  private void act(Actor monster, int anAction)
  {
    switch (anAction)
    {
    case Keep: return;

    case Wake:
      monster.bAmbush = false;
      monster.soundAlert(players[Net_Arbitrator].mo);
      return;

    case TurnAway:
      monster.a_SetAngle(monster.angleTo(players[Net_Arbitrator].mo) + 180.0);
      return;

    case TurnTowards:
      monster.a_SetAngle(monster.angleTo(players[Net_Arbitrator].mo));
      return;

    case TurnRandomly:
      monster.a_SetAngle(random[WarmReception](0, 359));
      return;

    case Kill:
      wr_Killer(Actor.spawn("wr_Killer", (0, 0, 0))).init(monster);
      return;

    case Remove:
      level.total_monsters -= monster.bCountKill;
      monster.destroy();
      return;
    }
  }

  enum Mode
  {
    Keep,
    Wake,
    TurnAway,
    TurnTowards,
    TurnRandomly,
    Kill,
    Remove,
  }

  private static bool isAtStart(Actor monster)
  {
    for (int i = 0; i < MAXPLAYERS; ++i)
    {
      if (players[i].mo && monster.checkSight(players[i].mo, SF_IGNOREVISIBILITY))
        return true;
    }

    return false;
  }
}

class wr_Killer : Actor
{
  Default
  {
    +NoBlockmap;
    +NoGravity;
    +DontSplash;
    +NotOnAutomap;
  }

  States
  {
  Spawn:
    TNT1 A -1;
    Stop;
  }

  override void tick()
  {
    Super.tick();

    if (mWatched == NULL)
    {
      destroy();
      return;
    }

    if (mWatched.health > 0 && mWatched.target == NULL) return;

    mWatched.a_Die();
    destroy();
  }

  void init(Actor watched) { mWatched = watched; }

  private Actor mWatched;
}

6. Project setup

GameInfo
{
  EventHandlers = "wr_EventHandler"
}
version 4.14.3

#include "zscript/wr_EventHandler.zs"

7. Tests

Basic check: the mod can be loaded without errors.

wait 2; map map01; wait 2; quit

Created: 2026-08-05 Wed 12:54