aradar.pk3

PK3 141 KiB 0 map(s)

Counts

endoom0
graphics0
lumps21
maps0
palettes0

Totals (across maps)

Things0
Linedefs0
Sectors0
Monsters0
Items0
Raw model (for completeness)
{
  "meta": {
    "id": "0190dd3f-5ad0-4187-a744-4af0766f2f94",
    "sha1": "c25db0efdc6ec11fbfd3041d18262f89278b85fd",
    "sha256": "fe46fdca1ea28c95ed29eeae7d1582188bd45ccee65fb6352c7e2cf979f1da30",
    "filenames": [
      "aradar.pk3"
    ],
    "additional": {
      "engines": [],
      "iwad": [],
      "filename": null,
      "added": "2021/12/12 23:16:15",
      "locked": false,
      "canDownload": true,
      "adult": false,
      "hidden": false,
      "name": null,
      "description": null,
      "maps": null,
      "graphicOverrides": null,
      "screenshots": null,
      "palettes": null,
      "categories": null
    },
    "flags": {
      "locked": false,
      "canDownload": true,
      "adult": false,
      "hidden": false
    },
    "added": "2021/12/12 23:16:15",
    "file": {
      "type": "PK3",
      "size": 144658,
      "url": "https://wadarchive2.nyc3.digitaloceanspaces.com/c25db0efdc6ec11fbfd3041d18262f89278b85fd/c25db0efdc6ec11fbfd3041d18262f89278b85fd.pk3.gz",
      "corrupt": false
    },
    "content": {
      "counts": {
        "endoom": 0,
        "graphics": 0,
        "lumps": 21,
        "maps": 0,
        "palettes": 0
      }
    },
    "text_files": [
      {
        "source": "pk3",
        "name": "cvarinfo.txt",
        "contents": "//\n// This file is part of ARADAR.\n// See README and LICENSE for details.\n//\n\n// -------------------------------------------------------------------------- //\n\nnosave int        aradar_anchor     = 1;\nnosave int        aradar_order      = 0;\nnosave int        aradar_offset_x   = 30;\nnosave int        aradar_offset_y   = 30;\nnosave float      aradar_scale      = 0.70;\nnosave bool       aradar_altitude   = false;\nnosave bool       aradar_respawn    = false;\nnosave float      aradar_volume     = 1.0;\nserver cheat bool aradar_deathmatch = false;\n\n// -------------------------------------------------------------------------- //"
      },
      {
        "source": "pk3",
        "name": "LICENSE.md",
        "contents": "BSD 3-Clause License\n\nCopyright (c) 2021, arookas\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
      },
      {
        "source": "pk3",
        "name": "mapinfo.txt",
        "contents": "//\n// This file is part of ARADAR.\n// See README and LICENSE for details.\n//\n\n// -------------------------------------------------------------------------- //\n\ngameinfo {\n\n  AddEventHandlers = \"ARadarManager\"\n\n}\n\n// -------------------------------------------------------------------------- //"
      },
      {
        "source": "pk3",
        "name": "menudef.txt",
        "contents": "//\n// This file is part of ARADAR.\n// See README and LICENSE for details.\n//\n\n// -------------------------------------------------------------------------- //\n\nOptionValue \"ARadarAnchor\" {\n\n  0, \"None\"\n  1, \"Top right\"\n  2, \"Top left\"\n  3, \"Bottom right\"\n  4, \"Bottom left\"\n\n}\n\nOptionValue \"ARadarOrder\" {\n\n  0, \"Under HUD\"\n  1, \"Over HUD\"\n\n}\n\nAddOptionMenu \"HUDOptions\" after \"ScoreboardOptions\" {\n  Submenu \"Radar Options\", \"ARadarOptions\"\n}\n\nOptionMenu \"ARadarOptions\" {\n\n  Title \"Radar Options\"\n  Option \"Display position\", \"aradar_anchor\", \"ARadarAnchor\"\n  Option \"Enable in deathmatch\", \"aradar_deathmatch\", \"YesNo\"\n  Option \"Draw under HUD\", \"aradar_order\", \"NoYes\", \"aradar_anchor\"\n  StaticText \"\"\n  Slider \"Radar scale\", \"aradar_scale\", 0.25, 2.0, 0.05, 2, \"aradar_anchor\"\n  Slider \"Radar X offset\", \"aradar_offset_x\", -200, 200, 5, 0, \"aradar_anchor\"\n  Slider \"Radar Y offset\", \"aradar_offset_y\", -200, 200, 5, 0, \"aradar_anchor\"\n  StaticText \"\"\n  Option \"Show blip altitude\", \"aradar_altitude\", \"NoYes\", \"aradar_anchor\"\n  Option \"Show respawned items\", \"aradar_respawn\", \"NoYes\", \"aradar_anchor\"\n  StaticText \"\"\n  Slider \"Alert volume\", \"aradar_volume\", 0.0, 1.0, 0.05, 2, \"aradar_anchor\"\n\n}\n\n// -------------------------------------------------------------------------- //"
      },
      {
        "source": "pk3",
        "name": "README.md",
        "contents": "# aradar v1.0\n\n## Description\n\nThis addon for [GZDOOM](https://zdoom.org/index) provides an onscreen radar.\nThe radar is a recreation combining the features of _Earth Defense Force 4.1_, _Earth Defense Force 5_, and _Earth Defense Force: Iron Rain_.\n\nThe mod is designed to be universal, so simply load it alongside any other mods to begin using it.\n\n## Credits\n\n- All code in this mod falls under the attached [LICENSE](./LICENSE.md).\n- All images in the _graphics/_ directory are by arookas.\n- _alert.flac_ is by Yuke's and ripped from _Earth Defense Force: Iron Rain_.\n\nThis mod wouldn't be possible without these wonderful folks:\n\n| **Greyfalll** | **Accensus** • **phantombeta** |\n|:-:|:-:|\n| support / testing | scripting help |\n\n## Features\n\nThe radar provides various indicators and displays them relative to the player's view.\nThe player's position is at the center of the radar, with north in front of the player.\n\n### Blips\n\nA _blip_ is a colored circle representing a particular actor.\n_Blips_ will usually appear once they enter line of sight for the first time;\nfor monsters, they also appear once the monster has woken up from gunfire.\nIf a _blip_ is beyond the visible distance of the radar, it will change into a pointed arrow along the edge.\n\nThe table below describes the various colors of _blips_:\n\n| Color  | Target | Technical |\n|-------:|:-------|-----------|\n| Red    | Living monsters | Has `ISMONSTER` and `COUNTKILL` flags. |\n| Blue   | Living allies  | Has `FRIENDLY` and `SHOOTABLE` flags. |\n| Yellow | Key items / interactive objects | Derived from `Powerup` or `Key`, or has `USEPSECIAL` or `BUMPSECIAL` flags. |\n| Green  | Regular items | Derived from `Inventory` or has `COUNTITEM` flag. |\n| White  | Objects | Has either `SHOOTABLE` or `FRIENDLY` flag (but not both). |\n\n### Pips\n\nIn multiplayer, other players will be represented by _pips_ (**p**layer bl**ips**).\nThese are larger circles marked with the first letter of the player's name.\nA _pip_ will display in the respective player's profile color.\n\n### Blots\n\nWhen a player dies, a light-red _blot_ will appear for a few seconds in the area where he or she died.\n\n### Field of View\n\nThe bright region in the radar indicates the player's current field of view.\nAny indicators such as _blips_ inside this region will be in front of the player in the 3D view.\n\n### Altitude\n\nWhen a particular indicator (_blip_, _pip_, or _blot_) is above or below the player, it will display higher or lower on the radar.\nFor _blips_ and _pips_, a vertical line will indicate the relative altitude.\nThis feature can be turned off in the [settings](#customization).\n\n### Map Area\n\nThe edges of the map will be displayed as an outlined red box on the radar.\n\n### Alert\n\nWhen a notable amount of red _blips_ (monsters) appear in a short period of time, an audio indicator will play.\nThis indicator can be turned off and the volume adjusted in the [settings](#customization).\n\n## Customization\n\nThis addon provides many options.\nThe settings are located in a dedicated submenu under _HUD Options_>_Radar Options_.\nYou can turn the radar on/off, change the appearance, and control specific features:\n\n| Option | Description |\n|-------:|-------------|\n| _Display position_ | Controls which corner of the screen to display the radar, or turn off the radar entirely. |\n| _Enable in deathmatch_ | Enables players to see the radar even in deathmatch. This is a host setting and cheats must be enabled to turn this on. |\n| _Draw under HUD_ | Whether the radar displays under or over existing HUD elements. |\n| _Radar scale_ | Global display scale of the radar and indicators. |\n| _Radar X offset_ | Horizontal offset of the radar display, in screen pixels. Positive values move radar towards the center of the screen. |\n| _Radar Y offset_ | Vertical offset of the radar display, in screen pixels. Positive values move radar towards the center of the screen. |\n| _Show blip altitude_ | Turn this off to hide [altitude indicators](#altitude). This is useful for smaller screens. |\n| _Show respawned items_ | If `sv_itemrespawn` is enabled, items are allowed to reappear on the radar after respawning. Turning this off will keep the item's _blip_ hidden after being picked up the first time. This option can help clean up the radar for larger maps with lots of items. |\n| _Alert volume_ | Changes the volume of the [alert sound](#alert). Set to zero to turn the feature off entirely. |"
      },
      {
        "source": "pk3",
        "name": "sndinfo.txt",
        "contents": "//\n// This file is part of ARADAR.\n// See README and LICENSE for details.\n//\n\n// -------------------------------------------------------------------------- //\n\narookas/radar/alert \"sounds/arookas/radar/alert.flac\"\n\n$pitchshift  arookas/radar/alert 0\n$attenuation arookas/radar/alert 0.0\n$volume      arookas/radar/alert 0.35\n\n// -------------------------------------------------------------------------- //"
      },
      {
        "source": "pk3",
        "name": "zscript.txt",
        "contents": "//\n// This file is part of ARADAR.\n// See README and LICENSE for details.\n//\n\n// -------------------------------------------------------------------------- //\n\nversion \"4.5\"\n\n#include \"zscript/arookas/radar/data.txt\"\n#include \"zscript/arookas/radar/manager.txt\"\n#include \"zscript/arookas/radar/renderer.txt\"\n\n// -------------------------------------------------------------------------- //"
      },
      {
        "source": "pk3",
        "name": "zscript/arookas/radar/data.txt",
        "contents": "//\n// This file is part of ARADAR.\n// See README and LICENSE for details.\n//\n\n// -------------------------------------------------------------------------- //\n\nenum ARadarBlipType {\n\n  // these are in order drawn\n  ARADAR_BLIP_WHITE = 0,\n  ARADAR_BLIP_GREEN,\n  ARADAR_BLIP_YELLOW,\n  ARADAR_BLIP_BLUE,\n  ARADAR_BLIP_RED,\n\n  ARADAR_NUM_BLIPS\n\n}\n\nenum ARadarBlipFlag {\n\n  ARADAR_BLIPF_VISIBLE   = 1,\n  ARADAR_BLIPF_RESPAWNED = 2\n\n}\n\nclass ARadarBlip {\n\n  Actor mo;\n  ARadarBlipType type;\n  uint flags;\n\n  static ARadarBlip Create(Actor mo) {\n    ARadarBlipType type = DeduceType(mo);\n\n    if (type < 0) {\n      return null;\n    }\n\n    ARadarBlip blip = new('ARadarBlip');\n\n    if (blip != null) {\n      blip.mo    = mo;\n      blip.type  = type;\n      blip.flags = 0;\n    }\n\n    return blip;\n  }\n\n  static ARadarBlipType DeduceType(Actor mo) {\n    if (mo != null && !(mo is 'PlayerPawn')) {\n      if ((mo is 'Powerup') || (mo is 'Key')) {\n        return ARADAR_BLIP_YELLOW;\n      }\n\n      if ((mo is 'Inventory') || mo.bCOUNTITEM) {\n        return ARADAR_BLIP_GREEN;\n      }\n\n      if (mo.bFRIENDLY) {\n        if (mo.bSHOOTABLE) {\n          return ARADAR_BLIP_BLUE;\n        }\n\n        return ARADAR_BLIP_WHITE;\n      }\n\n      if (mo.bISMONSTER && mo.bCOUNTKILL) {\n        return ARADAR_BLIP_RED;\n      }\n\n      if (mo.bUSESPECIAL || mo.bBUMPSPECIAL) {\n        return ARADAR_BLIP_YELLOW;\n      }\n\n      if (mo.bSHOOTABLE) {\n        return ARADAR_BLIP_WHITE;\n      }\n    }\n\n    return -1;\n  }\n\n}\n\n// -------------------------------------------------------------------------- //\n\nenum ARadarBlotType {\n\n  ARADAR_BLOT_RED,\n  ARADAR_BLOT_BLUE,\n  ARADAR_BLOT_YELLOW,\n\n  ARADAR_NUM_BLOTS\n\n}\n\nclass ARadarBlot {\n\n  vector3 pos;\n  ARadarBlipType type;\n  int life;\n\n  static ARadarBlot Create(vector3 pos, ARadarBlotType type, double secs) {\n    if (type < 0 || type >= ARADAR_NUM_BLOTS || secs <= 0) {\n      return null;\n    }\n\n    ARadarBlot blot = new('ARadarBlot');\n\n    if (blot != null) {\n      blot.pos  = pos;\n      blot.type = type;\n      blot.life = (GameTicRate * secs);\n    }\n\n    return blot;\n  }\n\n}\n\n// -------------------------------------------------------------------------- //\n\nstruct ARadarData {\n\n  Array<ARadarBlip> blips;\n  uint counts[ARADAR_NUM_BLIPS];\n  Array<ARadarBlot> blots;\n\n  void Init() {\n    self.blips.Clear();\n\n    for (int i = 0; i < ARADAR_NUM_BLIPS; ++i) {\n      self.counts[i] = 0;\n    }\n  }\n\n  play int Tick() {\n    int notices = 0;\n\n    for (uint i = 0; i < self.blips.Size(); ++i) {\n      if ((self.blips[i].flags & ARADAR_BLIPF_VISIBLE) != 0) {\n        switch (self.blips[i].type) {\n          case ARADAR_BLIP_GREEN:\n          case ARADAR_BLIP_YELLOW: {\n            break;\n          }\n          default: {\n            continue;\n          }\n        }\n      }\n\n      Actor mo = self.blips[i].mo;\n\n      if (mo == null) {\n        continue;\n      }\n\n      switch (self.blips[i].type) {\n        case ARADAR_BLIP_RED: {\n          if (mo.target != null) {\n            ++notices;\n            self.blips[i].flags |= ARADAR_BLIPF_VISIBLE;\n            continue;\n          }\n\n          break;\n        }\n        case ARADAR_BLIP_GREEN:\n        case ARADAR_BLIP_YELLOW: {\n          let item = Inventory(mo);\n\n          if (item != null) {\n            if (item.Owner != null) {\n              self.blips[i].flags &= ~ARADAR_BLIPF_VISIBLE;\n              continue;\n            }\n\n            if (!item.bSPECIAL) {\n              self.blips[i].flags &= ~ARADAR_BLIPF_VISIBLE;\n              self.blips[i].flags |=  ARADAR_BLIPF_RESPAWNED;\n              continue;\n            }\n          }\n\n          break;\n        }\n      }\n\n      // CheckIfSeen returns FALSE if seen for some reason\n      if (!mo.CheckIfSeen()) {\n        if (self.blips[i].type == ARADAR_BLIP_RED) {\n          ++notices;\n        }\n\n        self.blips[i].flags |= ARADAR_BLIPF_VISIBLE;\n        continue;\n      }\n    }\n\n    for (uint i = 0; i < self.blots.Size();) {\n      if (self.blots[i].life-- > 0) {\n        ++i;\n        continue;\n      }\n\n      self.blots.Delete(i);\n    }\n\n    return notices;\n  }\n\n  uint GetIndex(ARadarBlipType type) const {\n    uint index = 0;\n\n    for (int i = 0; i < type; ++i) {\n      index += self.counts[i];\n    }\n\n    return index;\n  }\n\n  bool AddBlip(Actor mo) {\n    ARadarBlip blip = ARadarBlip.Create(mo);\n\n    if (blip == null) {\n      return false;\n    }\n\n    uint index = GetIndex(blip.type);\n    self.blips.Insert(index, blip);\n    ++self.counts[blip.type];\n\n    return true;\n  }\n\n  bool RemoveBlip(Actor mo) {\n    for (uint i = 0; i < self.blips.Size(); ++i) {\n      if (self.blips[i].mo != mo) {\n        continue;\n      }\n\n      --self.counts[self.blips[i].type];\n      self.blips.Delete(i);\n\n      return true;\n    }\n\n    return false;\n  }\n\n  bool AddBlot(vector3 pos, ARadarBlotType type, double secs) {\n    ARadarBlot blot = ARadarBlot.Create(pos, type, secs);\n\n    if (blot == null) {\n      return false;\n    }\n\n    self.blots.Push(blot);\n\n    return true;\n  }\n\n}\n\n// -------------------------------------------------------------------------- //"
      },
      {
        "source": "pk3",
        "name": "zscript/arookas/radar/manager.txt",
        "contents": "//\n// This file is part of ARADAR.\n// See README and LICENSE for details.\n//\n\n// -------------------------------------------------------------------------- //\n\nclass ARadarManager : EventHandler {\n\n  const NOTICE_BUFFER_SZ = 10;\n\n  private bool mDefunct;\n  private ARadarData mData;\n  private ARadarRenderer mRenderer;\n  private int mNoticeBuffer[NOTICE_BUFFER_SZ];\n  private int mNoticeDebounce;\n\n  private transient CVar mDeathMatch;\n\n  override void OnRegister() {\n    mDefunct = false;\n    mNoticeDebounce = 0;\n\n    for (uint i = 0; i < NOTICE_BUFFER_SZ; ++i) {\n      mNoticeBuffer[i] = 0;\n    }\n\n    if (!mRenderer.InitCVar()) {\n      mDefunct = true;\n      return;\n    }\n\n    mDeathMatch = CVar.GetCVar('aradar_deathmatch');\n  }\n\n  override void WorldLoaded(WorldEvent e) {\n    mData.Init();\n\n    if (!mRenderer.InitRes()) {\n      mDefunct = true;\n      return;\n    }\n\n    if (!mRenderer.InitBox()) {\n      mDefunct = true;\n      return;\n    }\n  }\n\n  override void WorldThingSpawned(WorldEvent e) {\n    if (mDefunct) {\n      return;\n    }\n\n    mData.AddBlip(e.Thing);\n  }\n\n  override void WorldThingRevived(WorldEvent e) {\n    if (mDefunct) {\n      return;\n    }\n\n    mData.AddBlip(e.Thing);\n  }\n\n  override void WorldThingDied(WorldEvent e) {\n    if (mDefunct) {\n      return;\n    }\n\n    mData.RemoveBlip(e.Thing);\n  }\n\n  override void WorldThingDestroyed(WorldEvent e) {\n    if (mDefunct) {\n      return;\n    }\n\n    mData.RemoveBlip(e.Thing);\n  }\n\n  override void PlayerDied(PlayerEvent e) {\n    if (mDefunct) {\n      return;\n    }\n\n    int pnum = e.PlayerNumber;\n\n    if (pnum < 0 || pnum >= MAXPLAYERS) {\n      return;\n    }\n\n    PlayerPawn mo = players[pnum].mo;\n\n    if (mo == null) {\n      return;\n    }\n\n    mData.AddBlot(mo.Pos, ARADAR_BLOT_RED, 5);\n  }\n\n  override void WorldTick() {\n    if (mDefunct) {\n      return;\n    }\n\n    mRenderer.Tick();\n\n    if (mNoticeDebounce > 0) {\n      --mNoticeDebounce;\n    }\n\n    for (uint i = (NOTICE_BUFFER_SZ - 1); i > 0; --i) {\n      mNoticeBuffer[i] = mNoticeBuffer[i - 1];\n    }\n\n    mNoticeBuffer[0] = mData.Tick();\n\n    int notices = 0;\n\n    for (uint i = 0; i < NOTICE_BUFFER_SZ; ++i) {\n      notices += mNoticeBuffer[i];\n    }\n\n    if (notices >= 8 && mNoticeDebounce <= 0) {\n      double volume = 1.0;\n\n      CVar opt = CVar.GetCVAR('aradar_volume', players[consoleplayer]);\n\n      if (opt != null) {\n        volume = opt.GetFloat();\n\n        if (volume < 0.0) {\n          volume = 0.0;\n        }\n\n        if (volume > 1.0) {\n          volume = 1.0;\n        }\n      }\n\n      S_StartSound(\n        \"arookas/radar/alert\", CHAN_VOICE,\n        (CHANF_MAYBE_LOCAL | CHANF_UI),\n        volume, ATTN_NONE\n      );\n\n      mNoticeDebounce = (GameTicRate * 2);\n    }\n  }\n\n  private bool CheckRender() const {\n    if (mDefunct) {\n      return false;\n    }\n\n    bool enabled = true;\n\n    if (automapactive) {\n      enabled = false;\n    }\n\n    if (deathmatch) {\n      enabled = false;\n\n      if (mDeathMatch != null && mDeathMatch.GetBool()) {\n        enabled = true;\n      }\n    }\n\n    return enabled;\n  }\n\n  override void RenderUnderlay(RenderEvent e) {\n    if (!CheckRender()) {\n      return;\n    }\n\n    mRenderer.RenderUnderlay(e, mData);\n  }\n\n  override void RenderOverlay(RenderEvent e) {\n    if (!CheckRender()) {\n      return;\n    }\n\n    mRenderer.RenderOverlay(e, mData);\n  }\n\n}\n\n// -------------------------------------------------------------------------- //"
      },
      {
        "source": "pk3",
        "name": "zscript/arookas/radar/renderer.txt",
        "contents": "//\n// This file is part of ARADAR.\n// See README and LICENSE for details.\n//\n\n// -------------------------------------------------------------------------- //\n\nstruct ARadarDrawData {\n\n  Actor camera;\n  double frac_tic;\n  double timer;\n\n  vector3 origin;\n  double angle;\n  double sine;\n  double cosine;\n  double fov;\n\n  int radar_offset_x;\n  int radar_offset_y;\n  double radar_size;\n  double radar_radius;\n  double scan_radius;\n  double clip_radius;\n  double limit_z;\n  double blip_size;\n  double blip_bias;\n  double pip_size;\n  double blot_size;\n  double map_scale_x;\n  double map_scale_y;\n  double map_scale_z;\n\n  vector2 center;\n\n  vector3 CalcWorldPos(Actor mo) const {\n    vector3 pos = (0, 0, 0);\n\n    if (mo != null) {\n      pos = (mo.Prev + self.frac_tic * (mo.Pos - mo.Prev));\n    }\n\n    return pos;\n  }\n\n  vector3 CalcRadarPos(vector3 pos) const {\n    vector3 diff = Level.Vec3Diff(self.origin, pos);\n\n    diff.X *=  self.map_scale_x;\n    diff.Y *= -self.map_scale_y;\n    diff.Z *=  self.map_scale_z;\n\n    double x = (diff.X * self.cosine - diff.Y *   self.sine);\n    double y = (diff.X *   self.sine + diff.Y * self.cosine);\n\n    return (x, y, diff.Z);\n  }\n\n  bool ClampRadarPos(\n    in out double x,\n    in out double y,\n    in out double z\n  ) const {\n    if (z > self.limit_z) {\n      z = self.limit_z;\n    } else if (z < -self.limit_z) {\n      z = -self.limit_z;\n    }\n\n    vector2 unit  = (x, y);\n    double length = unit.Length();\n\n    if (length < self.radar_radius) {\n      return false;\n    }\n\n    unit /= length;\n    x     = (unit.X * self.radar_radius);\n    y     = (unit.Y * self.radar_radius);\n\n    return true;\n  }\n\n}\n\n// -------------------------------------------------------------------------- //\n\nclass ARadarAnm {\n\n  private Array<double> mFrame;\n  private Array<double> mKey;\n\n  uint size() const { return mFrame.Size(); }\n\n  void clear() {\n    mFrame.Clear();\n    mKey.Clear();\n  }\n\n  void reserve(uint amt) {\n    mFrame.Reserve(amt);\n    mKey.Reserve(amt);\n  }\n\n  void addKeyLinear(double at, double key) {\n    uint index = 0;\n\n    while (index < mFrame.Size()) {\n      if (mFrame[index] > at) {\n        break;\n      }\n\n      ++index;\n    }\n\n    mFrame.Insert(index, at);\n    mKey.Insert(index, key);\n  }\n\n  static double mix(double a, double b, double t) {\n    return (a * (1.0 - t) + b * t);\n  }\n\n  double eval(double at) const {\n    uint count = mFrame.Size();\n\n    if (count == 0) {\n      return 0.0;\n    }\n\n    uint last = (count - 1);\n\n    if (at < mFrame[0]) {\n      return mKey[0];\n    } else if (at >= mFrame[last]) {\n      return mKey[last];\n    }\n\n    uint frame = 0;\n\n    while (frame < last) {\n      if (mFrame[frame + 1] > at) {\n        break;\n      }\n\n      ++frame;\n    }\n\n    double s = (mFrame[frame + 1] - mFrame[frame]);\n    double t = 0.0;\n\n    if (s != 0.0) {\n      t = ((at - mFrame[frame]) / s);\n    }\n\n    return mix(mKey[frame], mKey[frame + 1], t);\n  }\n\n}\n\n// -------------------------------------------------------------------------- //\n\nstruct ARadarLine {\n\n  vector2 a;\n  vector2 b;\n\n  vector2 ab() const {\n    return (self.b - self.a);\n  }\n\n  double length() const {\n    return (self.b - self.a).Length();\n  }\n\n  vector2 normal() const {\n    return (self.b - self.a).Unit();\n  }\n\n  double t(vector2 pt) const {\n    vector2 ab = self.ab();\n    vector2 ac = (pt - self.a);\n    return ((ab dot ac) / (ab dot ab));\n  }\n\n  vector2 eval(double t) const {\n    return (self.a + (self.b - self.a) * t);\n  }\n\n  bool clip(double r) {\n    vector2 ab = self.ab();\n    double sqr_mag = (ab dot ab);\n\n    double b = (2 * (ab dot self.a));\n    double c = ((self.a dot self.a) - r * r);\n\n    double determ = (b * b - 4 * sqr_mag * c);\n\n    if (determ <= 0) {\n      return false;\n    }\n\n    vector2 p0, p1;\n    double bias = sqrt(determ);\n\n    p0 = self.eval(Clamp01((-b - bias) / (2 * sqr_mag)));\n    p1 = self.eval(Clamp01((-b + bias) / (2 * sqr_mag)));\n\n    self.a = p0;\n    self.b = p1;\n\n    return true;\n  }\n\n  static double Clamp01(double x) {\n    if (x < 0) {\n      return 0;\n    } else if (x > 1) {\n      return 1;\n    } else {\n      return x;\n    }\n  }\n\n}\n\n// -------------------------------------------------------------------------- //\n\nstruct ARadarRenderer {\n\n  enum EAnchor {\n\n    ANCHOR_OFF,\n    ANCHOR_TP_RT, // top-right\n    ANCHOR_TP_LT, // top-left\n    ANCHOR_BT_RT, // bottom-right\n    ANCHOR_BT_LT  // bottom-left\n\n  }\n\n  enum EOrder {\n\n    ORDER_UNDERLAY,\n    ORDER_OVERLAY\n\n  }\n\n  enum ETexID {\n\n    TEX_RADAR_BACK,\n    TEX_RADAR_SCAN,\n    TEX_RADAR_FOV,\n    TEX_RADAR_MARK,\n    TEX_RADAR_RIM,\n\n    TEX_BLIP_NEAR,\n    TEX_BLIP_FAR,\n\n    TEX_PIP_BASE,\n    TEX_PIP_TEXT,\n\n    TEX_BLOT,\n\n    TEX_NUM\n\n  }\n\n  static const Color BLIP_COLORS[] = {\n    Color(255, 255, 255, 255), // white\n    Color(255,   2, 252,   5), // green\n    Color(255, 245, 247,  26), // yellow\n    Color(255,   0, 193, 247), // blue\n    Color(255, 250,   7,   3)  // red\n  };\n\n  static const Color BLOT_COLORS[] = {\n    Color(255, 255,  64,  72), // red\n    Color(255,   0, 255, 255), // blue\n    Color(255, 245, 247,  26)  // yellow\n  };\n\n  private TextureID mTex[TEX_NUM];\n  private int mPlayerName[MAXPLAYERS];\n  private int mTextSrcWidth;\n  private transient CVar mScreenBlocks;\n  private transient CVar mRadarAnchor;\n  private transient CVar mRadarOrder;\n  private transient CVar mRadarAltitude;\n  private transient CVar mRadarRespawn;\n  private transient CVar mRadarScale;\n  private transient CVar mRadarOffsetX;\n  private transient CVar mRadarOffsetY;\n  private ARadarAnm mAnmScanScale;\n  private ARadarAnm mAnmScanFade;\n\n  private vector3 mBoxVertex[4];\n\n  bool InitCVar() {\n    mScreenBlocks  = CVar.GetCVar('screenblocks');\n    mRadarAnchor   = CVar.GetCVar('aradar_anchor');\n    mRadarOrder    = CVar.GetCVar('aradar_order');\n    mRadarAltitude = CVar.GetCVar('aradar_altitude');\n    mRadarRespawn  = CVar.GetCVar('aradar_respawn');\n    mRadarOffsetX  = CVar.GetCVar('aradar_offset_x');\n    mRadarOffsetY  = CVar.GetCVar('aradar_offset_y');\n    mRadarScale    = CVar.GetCVar('aradar_scale');\n\n    for (uint i = 0; i < MAXPLAYERS; ++i) {\n      mPlayerName[i] = -1;\n    }\n\n    return true;\n  }\n\n  bool InitRes() {\n    static const string NAMES[] = {\n      \"ARADBACK\", // TEX_RADAR_BACK\n      \"ARADSCAN\", // TEX_RADAR_SCAN\n      \"ARADFOV\",  // TEX_RADAR_FOV\n      \"ARADMARK\", // TEX_RADAR_MARK\n      \"ARADRIM\",  // TEX_RADAR_RIM\n      \"ARADBLIP\", // TEX_BLIP_NEAR\n      \"ARADTIP\",  // TEX_BLIP_FAR\n      \"ARADPIPB\", // TEX_PIP_BASE\n      \"ARADPIPT\", // TEX_PIP_TEXT\n      \"ARADBLOT\"  // TEX_BLOT\n    };\n\n    for (int i = 0; i < TEX_NUM; ++i) {\n      mTex[i] = TexMan.CheckForTexture(NAMES[i], TexMan.Type_Any);\n\n      if (!mTex[i].isValid()) {\n        return false;\n      }\n    }\n\n    int width, height;\n\n    [width, height] = TexMan.GetSize(mTex[TEX_PIP_TEXT]);\n    mTextSrcWidth = (width / 26);\n\n    mAnmScanScale = new('ARadarAnm');\n\n    if (mAnmScanScale != null) {\n      mAnmScanScale.addKeyLinear(0.0, 0.0);\n      mAnmScanScale.addKeyLinear(1.0, 0.3);\n      mAnmScanScale.addKeyLinear(2.0, 1.0);\n    }\n\n    mAnmScanFade = new('ARadarAnm');\n\n    if (mAnmScanFade != null) {\n      mAnmScanFade.addKeyLinear(0.0, 0.00);\n      mAnmScanFade.addKeyLinear(1.0, 0.00);\n      mAnmScanFade.addKeyLinear(1.5, 0.15);\n      mAnmScanFade.addKeyLinear(2.0, 0.00);\n    }\n\n    return true;\n  }\n\n  bool InitBox() {\n    vector2 box_min = Level.Vertexes[0].p;\n    vector2 box_max = box_min;\n\n    for (uint i = 0; i < Level.Vertexes.Size(); ++i) {\n      vector2 v = Level.Vertexes[i].p;\n\n      if (v.X < box_min.X) {\n        box_min.X = v.X;\n      }\n\n      if (v.Y < box_min.Y) {\n        box_min.Y = v.Y;\n      }\n\n      if (v.X > box_max.X) {\n        box_max.X = v.X;\n      }\n\n      if (v.Y > box_max.Y) {\n        box_max.Y = v.Y;\n      }\n    }\n\n    mBoxVertex[0] = (box_min.X, box_min.Y, 0);\n    mBoxVertex[1] = (box_min.X, box_max.Y, 0);\n    mBoxVertex[2] = (box_max.X, box_max.Y, 0);\n    mBoxVertex[3] = (box_max.X, box_min.Y, 0);\n\n    return true;\n  }\n\n  clearscope void Tick() {\n    for (uint i = 0; i < MAXPLAYERS; ++i) {\n      if (!playeringame[i]) {\n        mPlayerName[i] = -1;\n        continue;\n      }\n\n      int cell = -1;\n      string name = players[i].GetUserName();\n\n      if (name.CodePointCount() > 0) {\n        int code, next;\n\n        [code, next] = name.GetNextCodePoint(0);\n        code = string.CharUpper(code);\n        cell = (code - 65);\n      }\n\n      if (0 <= cell && cell < 26) {\n        mPlayerName[i] = cell;\n      } else {\n        mPlayerName[i] = -1;\n      }\n    }\n  }\n\n  ui void RenderUnderlay(\n    RenderEvent e,\n    in ARadarData radar\n  ) const {\n    int order = ORDER_UNDERLAY;\n\n    if (mRadarOrder != null) {\n      order = mRadarOrder.GetInt();\n    }\n\n    if (order == ORDER_UNDERLAY) {\n      Render(e, radar);\n    }\n  }\n\n  ui void RenderOverlay(\n    RenderEvent e,\n    in ARadarData radar\n  ) const {\n    int order = ORDER_UNDERLAY;\n\n    if (mRadarOrder != null) {\n      order = mRadarOrder.GetInt();\n    }\n\n    if (order == ORDER_OVERLAY) {\n      Render(e, radar);\n    }\n  }\n\n  ui void Render(\n    RenderEvent e,\n    in ARadarData radar\n  ) const {\n    int anchor = 0;\n\n    if (mRadarAnchor != null) {\n      anchor = mRadarAnchor.GetInt();\n    }\n\n    if (anchor <= ANCHOR_OFF || anchor > ANCHOR_BT_LT) {\n      return;\n    }\n\n    if (mScreenBlocks != null && mScreenBlocks.GetInt() > 11) {\n      return;\n    }\n\n    ARadarDrawData draw;\n\n    draw.camera   = e.Camera;\n    draw.frac_tic = e.FracTic;\n    draw.timer    = ((double(gametic) + e.FracTic) / double(GameTicRate));\n\n    // use actor Z and not the view/eye Z\n    draw.origin   = draw.CalcWorldPos(draw.camera);\n    draw.angle    = e.ViewAngle;\n    draw.sine     = sin(draw.angle - 90);\n    draw.cosine   = cos(draw.angle - 90);\n    draw.fov      = (players[consoleplayer].FOV / 2);\n\n    draw.radar_offset_x = 0;\n    draw.radar_offset_y = 0;\n    draw.radar_size     = 280;\n    draw.radar_radius   = 118;\n    draw.scan_radius    = 102;\n    draw.clip_radius    = 102;\n    draw.limit_z        = 100;\n    draw.blip_size      = 16;\n    draw.pip_size       = 20;\n    draw.blot_size      = 48;\n    draw.map_scale_x    = 0.18;\n    draw.map_scale_y    = 0.18;\n    draw.map_scale_z    = 0.18;\n\n    if (mRadarAltitude != null && mRadarAltitude.GetBool()) {\n      draw.map_scale_z = 0.0;\n    }\n\n    if (mRadarOffsetX != null) {\n      draw.radar_offset_x = mRadarOffsetX.GetInt();\n    }\n\n    if (mRadarOffsetY != null) {\n      draw.radar_offset_y = mRadarOffsetY.GetInt();\n    }\n\n    if (mRadarScale != null) {\n      double scale = mRadarScale.GetFloat();\n\n      draw.radar_size   *= scale;\n      draw.radar_radius *= scale;\n      draw.scan_radius  *= scale;\n      draw.clip_radius  *= scale;\n      draw.limit_z      *= scale;\n      draw.blip_size    *= scale;\n      draw.pip_size     *= scale;\n      draw.blot_size    *= scale;\n      draw.map_scale_x  *= scale;\n      draw.map_scale_y  *= scale;\n      draw.map_scale_z  *= scale;\n    }\n\n    if (draw.radar_size <= 0) {\n      return;\n    }\n\n    draw.center.X = (draw.radar_size / 2 + draw.radar_offset_x);\n    draw.center.Y = (draw.radar_size / 2 + draw.radar_offset_y);\n\n    switch (anchor) {\n      case ANCHOR_TP_RT:\n      case ANCHOR_BT_RT: {\n        draw.center.X = (Screen.GetWidth() - draw.center.X);\n        break;\n      }\n    }\n\n    switch (anchor) {\n      case ANCHOR_BT_LT:\n      case ANCHOR_BT_RT: {\n        int height = Screen.GetHeight();\n\n        if (mScreenBlocks != null && mScreenBlocks.GetInt() < 11) {\n          height = StatusBar.GetTopOfStatusBar();\n        }\n\n        draw.center.Y = (height - draw.center.Y);\n        break;\n      }\n    }\n\n    RenderRadar(draw);\n    RenderBlips(draw, radar);\n    RenderPips(draw, radar);\n    RenderBox(draw);\n    RenderBlots(draw, radar);\n  }\n\n  private ui void RenderRadar(\n    in ARadarDrawData draw\n  ) const {\n    Screen.DrawTexture(\n      mTex[TEX_RADAR_BACK], false,\n      draw.center.X, draw.center.Y,\n\n      DTA_CenterOffset, true,\n      DTA_DestHeightF,  draw.radar_size,\n      DTA_DestWidthF,   draw.radar_size\n    );\n\n    double time = (draw.timer % 2.0);\n    double scan_size = mAnmScanScale.eval(time);\n    double scan_fade = mAnmScanFade.eval(time);\n\n    Screen.DrawTexture(\n      mTex[TEX_RADAR_SCAN], false,\n      draw.center.X, draw.center.Y,\n\n      DTA_Alpha,        scan_fade,\n      DTA_CenterOffset, true,\n      DTA_DestHeightF,  (draw.scan_radius * 2.0 * scan_size),\n      DTA_DestWidthF,   (draw.scan_radius * 2.0 * scan_size)\n    );\n\n    Screen.DrawTexture(\n      mTex[TEX_RADAR_FOV], false,\n      draw.center.X, draw.center.Y,\n\n      DTA_CenterOffset, true,\n      DTA_ClipLeft,     int(draw.center.X),\n      DTA_DestHeightF,  draw.radar_size,\n      DTA_DestWidthF,   draw.radar_size,\n      DTA_Rotate,       -draw.fov\n    );\n\n    Screen.DrawTexture(\n      mTex[TEX_RADAR_FOV], false,\n      draw.center.X, draw.center.Y,\n\n      DTA_CenterOffset, true,\n      DTA_ClipRight,    int(draw.center.X),\n      DTA_DestHeightF,  draw.radar_size,\n      DTA_DestWidthF,   draw.radar_size,\n      DTA_FlipX,        true,\n      DTA_Rotate,       draw.fov\n    );\n\n    Screen.DrawTexture(\n      mTex[TEX_RADAR_MARK], false,\n      draw.center.X, draw.center.Y,\n\n      DTA_CenterOffset, true,\n      DTA_DestHeightF,  draw.radar_size,\n      DTA_DestWidthF,   draw.radar_size\n    );\n\n    Screen.DrawTexture(\n      mTex[TEX_RADAR_RIM], false,\n      draw.center.X, draw.center.Y,\n\n      DTA_CenterOffset, true,\n      DTA_DestHeightF,  draw.radar_size,\n      DTA_DestWidthF,   draw.radar_size\n    );\n  }\n\n  private ui void RenderBlips(\n    in ARadarDrawData draw,\n    in ARadarData radar\n  ) const {\n    bool hide_respawn = false;\n\n    if (mRadarRespawn != null) {\n      hide_respawn = mRadarRespawn.GetBool();\n    }\n\n    for (uint i = 0; i < radar.blips.Size(); ++i) {\n      if ((radar.blips[i].flags & ARADAR_BLIPF_VISIBLE) == 0) {\n        continue;\n      }\n\n      if ((radar.blips[i].flags & ARADAR_BLIPF_RESPAWNED) != 0) {\n        if (hide_respawn) {\n          continue;\n        }\n      }\n\n      vector3 pos = draw.CalcRadarPos(\n        draw.CalcWorldPos(radar.blips[i].mo)\n      );\n\n      int blip_tex      = TEX_BLIP_NEAR;\n      double blip_angle = 0;\n\n      if (draw.ClampRadarPos(pos.X, pos.Y, pos.Z)) {\n        blip_tex   = TEX_BLIP_FAR;\n        blip_angle = -(VectorAngle(pos.X, pos.Y) + 90);\n      }\n\n      ARadarBlipType blip_type = radar.blips[i].type;\n      Color blip_color         = BLIP_COLORS[blip_type];\n\n      Screen.DrawTexture(\n        mTex[blip_tex], false,\n        (draw.center.X + pos.X),\n        (draw.center.Y + pos.Y - pos.Z),\n\n        DTA_CenterOffset, true,\n        DTA_Color,        int(blip_color),\n        DTA_DestHeightF,  draw.blip_size,\n        DTA_DestWidthF,   draw.blip_size,\n        DTA_Rotate,       blip_angle\n      );\n\n      if (abs(pos.Z) > 1) {\n        Screen.DrawLine(\n          (draw.center.X + pos.X + 1),\n          (draw.center.Y + pos.Y),\n          (draw.center.X + pos.X + 1),\n          (draw.center.Y + pos.Y - pos.Z),\n          blip_color\n        );\n      }\n    }\n  }\n\n  private ui void RenderPips(\n    in ARadarDrawData draw,\n    in ARadarData radar\n  ) const {\n    for (uint i = 0; i < MAXPLAYERS; ++i) {\n      if (i == consoleplayer || !playeringame[i]) {\n        continue;\n      }\n\n      PlayerPawn mo = players[i].mo;\n\n      if (mo == null || mo.Health <= 0) {\n        continue;\n      }\n\n      vector3 pos = draw.CalcRadarPos(draw.CalcWorldPos(mo));\n      draw.ClampRadarPos(pos.X, pos.Y, pos.Z);\n\n      Color color = (players[i].GetColor() | 0xFF000000);\n\n      Screen.DrawTexture(\n        mTex[TEX_PIP_BASE], false,\n        (draw.center.X + pos.X),\n        (draw.center.Y + pos.Y - pos.Z),\n\n        DTA_CenterOffset, true,\n        DTA_Color,        int(color),\n        DTA_DestHeightF,  draw.pip_size,\n        DTA_DestWidthF,   draw.pip_size\n      );\n\n      if (abs(pos.Z) > 1) {\n        Screen.DrawLine(\n          (draw.center.X + pos.X + 1),\n          (draw.center.Y + pos.Y),\n          (draw.center.X + pos.X + 1),\n          (draw.center.Y + pos.Y - pos.Z),\n          color\n        );\n      }\n\n      int cell = -1;\n      string name = players[i].GetUserName();\n\n      if (name.CodePointCount() > 0) {\n        int code, next;\n\n        [code, next] = name.GetNextCodePoint(0);\n        code = string.CharUpper(code);\n\n        if (65 <= code && code <= 90) {\n          cell = (code - 65);\n        }\n      }\n\n      if (0 <= cell && cell < 26) {\n        Screen.DrawTexture(\n          mTex[TEX_PIP_TEXT], false,\n          (draw.center.X + pos.X),\n          (draw.center.Y + pos.Y - pos.Z),\n\n          DTA_CenterOffset, true,\n          DTA_DestHeightF,  draw.pip_size,\n          DTA_DestWidthF,   draw.pip_size,\n          DTA_SrcWidth,     double(mTextSrcWidth),\n          DTA_SrcX,         double(mTextSrcWidth * cell)\n        );\n      }\n    }\n  }\n\n  private ui void RenderBox(\n    in ARadarDrawData draw\n  ) const {\n    ARadarLine line;\n    vector3 p0, p1;\n\n    for (uint i = 0; i < 4; ++i) {\n      p0 = draw.CalcRadarPos(mBoxVertex[i]);\n      p1 = draw.CalcRadarPos(mBoxVertex[(i + 1) % 4]);\n\n      line.a = p0.Xy;\n      line.b = p1.Xy;\n\n      if (!line.clip(draw.clip_radius)) {\n        continue;\n      }\n\n      Screen.DrawLine(\n        int(draw.center.X + line.a.X), int(draw.center.Y + line.a.Y),\n        int(draw.center.X + line.b.X), int(draw.center.Y + line.b.Y),\n        0xFFFF0000\n      );\n    }\n  }\n\n  private ui void RenderBlots(\n    in ARadarDrawData draw,\n    in ARadarData radar\n  ) const {\n    for (uint i = 0; i < radar.blots.Size(); ++i) {\n      vector3 pos = draw.CalcRadarPos(radar.blots[i].pos);\n\n      draw.ClampRadarPos(pos.X, pos.Y, pos.Z);\n\n      ARadarBlotType blot_type = radar.blots[i].type;\n      Color blot_color         = BLOT_COLORS[blot_type];\n\n      Screen.DrawTexture(\n        mTex[TEX_BLOT], false,\n        (draw.center.X + pos.X),\n        (draw.center.Y + pos.Y - pos.Z),\n\n        DTA_CenterOffset, true,\n        DTA_Color,        int(blot_color),\n        DTA_DestHeightF,  draw.blot_size,\n        DTA_DestWidthF,   draw.blot_size\n      );\n    }\n  }\n\n}\n\n// -------------------------------------------------------------------------- //"
      }
    ]
  },
  "maps": []
}

gib.gg runs on open-source software and freely licensed replacement game assets from the Freedoom project. gib.gg is not affiliated with Bethesda Softworks, id Software, or ZeniMax Media. All trademarks belong to their respective owners. Some WADs and associated metadata on this site are sourced from WAD Archive. User-submitted content remains the responsibility of its respective authors. If you believe content on this site violates your rights, please send DMCA requests to dmca@gib.gg.