Raw model (for completeness)
{
"meta": {
"id": "061c682e-12e6-4683-b888-9c146fcf14de",
"sha1": "89bee63a1985301544658bbe126fa2454f3a4c03",
"sha256": "c7598511a7f8e6534b6776d487f5ace1b557aaa58231f1038d1a21d983330971",
"filenames": [
"zmr-2018.010-unstable.pk3"
],
"additional": {
"engines": [
"ZDOOM"
],
"iwad": [],
"filename": null,
"added": "2019-04-18 04:35:55",
"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": "2019-04-18 04:35:55",
"file": {
"type": "PK3",
"size": 15264275,
"url": "https://wadarchive2.nyc3.digitaloceanspaces.com/89bee63a1985301544658bbe126fa2454f3a4c03/89bee63a1985301544658bbe126fa2454f3a4c03.pk3.gz",
"corrupt": false
},
"content": {
"counts": {
"endoom": 0,
"graphics": 0,
"lumps": 620,
"maps": 0,
"palettes": 0
},
"engines_guess": [
"ZDOOM"
]
},
"analysis": {
"title": "Zandro Monster Randomiser - Cyantusk Edit",
"description": "This WAD is a monster randomizer mod designed for ZDoom-compatible engines, featuring no standalone maps but extensive monster variety and behavior changes. It introduces numerous new and modified monsters, including minibosses, rare bosses, and secret creatures, significantly increasing difficulty for skilled players. The mod adds custom items and power-ups to aid combat, alongside destructible objects that drop resources, promoting dynamic encounters. Visual variety is enhanced with decoration and keycard redesigns. The gameplay is intended for use with existing map packs, emphasizing randomized monster spawns and challenging combat rather than new level design.",
"tags": [
"ammo_plentiful",
"boss_encounters",
"hard",
"mod",
"monster_randomizer",
"no_maps",
"nonlinear",
"zdoom"
],
"origin": "gpt-4.1-mini"
},
"text_files": [
{
"source": "pk3",
"name": "Credits.txt",
"contents": "================================================================================\n\t\t\t\t* Zandro Monster Randomiser - Cyantusk Edit *\n================================================================================\n\nI've decided to make some kind of monster randomizer to Doom, cause fighting the\nsame monsters for during decades is kinda boring, specially if we have lots of\nchallenging/hard ZDoom monsters. Plus, I thought Monster Mixer apparently had\ndied. So I decided to make this. Many Zdoom Monsters are added here but, of\ncourse, vanilla monsters still here. There's some rare monsters and secret\nmonsters too. Have fun! :)\n\nBE ADVISED: This monster mod also increases the difficulty, and its intended for\nskilled players!\n\nFeatures:\n- 4 mini-bosses, 2 rare but powerful bosses and 5 secret monsters!\n- Each miniboss can drop a goodie, so players get a boost in combat!\n- Some bosses drop goodies!\n- 2 custom spheres and 3 custom items:\n * LifeSphere: +50 extra HP. Players can get it up to 500\n * ArmorSphere: +50 extra Armor (50% protection if player had no armor). Players\n can get it up to 500\n * Stimbonus: +5 extra HP, up to 200 (its like 5 HP bonus combined in one item)\n * Armor Shard: +5 extra armor, up to 200 (its like 5 armor bonus combined in\n one item)\n\n- Many monsters got profoundly changed (e.g., changed attack behavior, created\nnew attacks, balancing, appearence, etc) so they feel more unique.\n- Nethersyst: replaces Commander Keen. It has the same purpose, but its a very\nannoying monster, so be very careful when you see it!\n- PlasmaGlobe: replaces Computer Map. When destroyed, it spawns randomly a rune\n(except Reflection, Spread and Highjump).\n- SupplyModule: its a destroyable object which, when destroyed, drops random\nammo and health amounts.\n- No Impse guys, no pr0n 4 u while dooming!\n- Decoration variants: decorations like columns and trees vary!\n- Keys variants: cards and skulls have different design!\n- It has 3 custom flags (use 0 or 1 for the # place):\n> zmr_random #: spawns random variants\n> zmr_demonic #: spawns demonic replacement only\n> zmr_tech #: spawns tech replacement only\n\nNOTE: if all these flags are disabled, you'll have a hidden spawn mode. If you\nreally want to play this hidden mode, you should begin in the first levels of\nyour mappacks, and / or play with some players. Things will get really hard.\n\n[SAMSARA-EXCLUSIVE]\n- Robotic foes get proper damage from Fusion Pistol, Tesla and Eletric Bolts.\n- Freeley bullets cant hurt Paladin and Dark Inquisitor, to simulate the\noriginal ROTT behavior for robots.\n- Zombieman, Shotgunner and Chaingunner variants get instakilled with Strife's\nPoisonbolts.\n- Duke's kick works for almost every monster, except bosses, minibosses and\nNethersyst.\n\nCompatibility: Zandronum with Samsara Addons Mod (Modes: Survival Coop or\nSurvival Invasion recommended). I might try to make this compatible with\nZandronum without mods in the future.\n\nIf you want to create a monster for this mod, feel free to contact me\n(Cyantusk), so we can talk about it. DON'T CREATE ANY MONSTER W/O DISCUSSING\nIT WITH ME FIRST (so you dont waste your time). Just discuss ideas before\nproceeding.\n\nSuggestions for balancing are always welcome!\n\n================================================================================\n\t\t\t\t\t\t\t\t* Credits *\n================================================================================\n\nFile Author: Cyantusk\nMonster Mixer (base): Minesae Hiromu, Shadowlink223\nMonsters' balancing and modifications: Cyantusk\nAuthors of Realm667 Beastiary's monsters (yea im lazy to add them all manually\n:P -- but most of them are included on each wad file).\nAuthor(s) of Skulltag Monsters.\nAuthor(s) of used Hierarchy of Chaos monsters: Vader, Nanami, Carnevil, Cyb,\nNeoworm, MaelStrom.\nAuthor(s) of Chaos From Hell Invasion monsters used here.\nInt0x: for partially giving me the Plasma Globe behavior idea.\nDonald: for Taurus and Orange Rockets.\nAuthor(s) of NeoDoom Trees.\nAuthor(s) of Armageddon Invasion Trees and Bushes.\nVirtue for Vanilla Doom brightmaps.\nFor the people that helped with balance suggestions, including:\n\nGundere\nInt0x\nSidhe Guy (aka King Gengar)\nViktro\nLaserpope\nJack Freeman\nHardbash\nPopsoap\n\nWithout you all, ZMR wont be sufficiently balanced and playable! You made me\nlearn a lot about monster balancing.\n\nAnd... I think thats it! My apologies if I forgot someone!\n\n================================================================================\n\t\t\t\t\t\t* Copyright / Permissions *\n================================================================================\n\nAuthors MAY use the monsters in this file as a base for modification or\nreuse. You MAY modify and re-use graphics as you will, with proper credits\ngiven. You should contact the file author for acknowledgements.\n\nYou MAY distribute this file, provided you include this text file, with no\nmodifications. You may distribute this file in any electronic format\n(BBS, Diskette, CD, etc) as long as you include this file intact."
},
{
"source": "pk3",
"name": "acs/ZMRACSs.txt",
"contents": "#library \"ZMRACS\"\n#include \"zcommon.acs\"\n\n#pragma define raw on\n#pragma block_scope on\n#pragma fixed off\n#define \tDISABLE_DEBUG\n\n#ifndef DISABLE_DEBUG\n#define\t\tZMR_DEBUG_LOG\t\tLog\n\n#define\t\tZMR_ASSERT(expr)\t\tif(!(expr)) \\\n\t\t\t\t\t\t\t\t\t\tZMR_DEBUG_LOG(#expr)\n\n#else\n#define\t\tZMR_DEBUG_LOG(...)\n#define\t\tZMR_ASSERT(expr)\n#endif\n\n#define\t\ttid_t\t\t\tint\n\nfunction tid_t zmr_create16KPage(void) {\n\ttid_t resultTID = UniqueTID();\n\tSpawn(\"ZMR_Page16k\", 0, 0, 0, resultTID);\n\treturn resultTID;\n}\n\nfunction tid_t zmr_createPathfinderMonster(void) {\n\ttid_t resultTID = UniqueTID();\n\tSpawn(\"ZMR_Pathfinder\", 0, 0, 0, resultTID);\n\treturn resultTID;\n}\n\nfunction tid_t zmr_createPatrolPoint(void) {\n\ttid_t resultTID = UniqueTID();\n\tSpawn(\"PatrolPoint\", 0, 0, 0, resultTID);\n\treturn resultTID;\n}\n\n#define\t\tZMR_KILOBYTE\t\t\t(1024)\n\n#define\t\tZMR_MEGABYTE\t\t\t(ZMR_KILOBYTE * ZMR_KILOBYTE)\n\n#define\t\tZMR_PAGE_SIZE\t\t\t(4096*4)\n#define\t\tZMR_PAGE_FOR_PTR(p)\t\t((p) >> 14)\n\n#define\t\tZMR_PAGE_OFFSET(p)\t\t((p) & (ZMR_PAGE_SIZE - 1))\n\n#define\t\tZMR_MAX_MEMENTRIES\t\t8192\n\n#define\t\tZMR_MAX_PAGES\t\t\t4096\n\n#define\t\tzmr_page_t\t\t\t\tint\n\n#define\t\tZMR_STARTUP_MEMORY\t\t(ZMR_MEGABYTE * 5)\n\n#define\t\tZMR_PREALLOC_PAGES\t\t((ZMR_STARTUP_MEMORY / ZMR_PAGE_SIZE) + 1)\n\nstruct zmr_mementry_t {\n\tint offset;\n\tint size;\n\tbool claimed;\n\tbool in_use;\n};\n\nzmr_mementry_t g_mementries[ZMR_MAX_MEMENTRIES];\n\nzmr_page_t g_zmr_pages[ZMR_MAX_PAGES];\n\nbool g_zmr_didinit = false;\n\nint g_zmr_current_free_memory = ZMR_STARTUP_MEMORY;\n\nfunction void zmr_init_mman(void) {\n\tg_mementries[0].size = ZMR_STARTUP_MEMORY;\n\tg_mementries[0].offset = 8;\n\tg_mementries[0].in_use = true;\n\tg_mementries[0].claimed = false;\n\n\tfor(int i = 0; i < ZMR_PREALLOC_PAGES; ++i) {\n\t\tg_zmr_pages[i] = zmr_create16KPage();\n\t}\n\tg_zmr_didinit = true;\n}\n\nfunction void zmr_deinit_mman(void) {\n\tfor(int i = 0; i < ZMR_MAX_PAGES; ++i) {\n\tg_mementries[i].size = 0;\n\tg_mementries[i].offset = 0;\n\tg_mementries[i].in_use = 0;\n\tg_mementries[i].claimed = 0;\n\t}\n\n\tfor(int i = 0; i < ZMR_PREALLOC_PAGES; ++i) {\n\t\tg_zmr_pages[i] = 0;\n\t}\n\tg_zmr_didinit = false;\n\tg_zmr_current_free_memory = ZMR_STARTUP_MEMORY;\n\n}\n\nfunction void zmr_ensure_init(void) {\n\tif(!g_zmr_didinit) {\n\t\tzmr_init_mman();\n\t//\tZMR_DEBUG_LOG( s: \"mman init\");\n\t}\n}\n\nfunction void zmr_free_relocating(int i) {\n\tif(i > 0 && g_mementries[i-1].claimed == false && g_mementries[i-1].in_use == true) {\n\n\t\t//set current entry to be unused, enlargen previous entry\n\t\tg_mementries[i-1].size += g_mementries[i].size;\n\t\tg_mementries[i].size = 0;\n\t\tg_mementries[i].offset = -1;\n\t\tg_mementries[i].in_use = false;\n\t\treturn;\n\t}\n\telse if((i+1) < ZMR_MAX_MEMENTRIES && g_mementries[i+1].in_use == true && g_mementries[i+1].claimed == false) {\n\t\tg_mementries[i].size += g_mementries[i+1].size;\n\t\tg_mementries[i+1].size = 0;\n\t\tg_mementries[i+1].offset = -1;\n\t\tg_mementries[i+1].in_use = false;\n\t}\n\telse if(i > 0 && g_mementries[i-1].in_use == false) {\n\t\tg_mementries[i-1].size = g_mementries[i].size;\n\t\tg_mementries[i-1].offset = g_mementries[i].offset;\n\t\tg_mementries[i-1].in_use = true;\n\t\tg_mementries[i].size = 0;\n\t\tg_mementries[i].offset = -1;\n\t\tg_mementries[i].in_use = false;\n\t}\n}\n\nfunction void zmr_malloc_relocating(int i, int size) {\n\tif(g_mementries[i].size == size)\n\t\treturn;\n\tint relocate_size = g_mementries[i].size - size;\n\tif(i > 0 && g_mementries[i-1].claimed == false && g_mementries[i-1].in_use == true) {\n\n\t\t/*\n\t\t\tan entry prior to this one is present,\n\t\t\tthe prior entry is a record of memory that is free\n\n\t\t\twe need to make the previous entry larger by giving it the bytes in our entry\n\t\t\tthat we do not need\n\n\t\t\tprior->size += current->size - size;\n\t\t\tcurrent->offset += current->size - size;\n\t\t\tcurrent->size = size;\n\n\t\t\twe relocate the unused bytes to prior, advance our offset to be after prior, and set our size to the new size\n\t\t*/\n\n\t\tg_mementries[i-1].size += relocate_size;\n\t\tg_mementries[i].offset += relocate_size;\n\t\tg_mementries[i].size = size;\n\t}\n\telse if((i+1) < ZMR_MAX_MEMENTRIES && g_mementries[i+1].in_use == true && g_mementries[i+1].claimed == false) {\n\n\t\t/*\n\t\t\tinverse of prior, we relocate bytes to the next entry, moving its offset back\n\t\t*/\n\t\tg_mementries[i+1].size += relocate_size;\n\t\tg_mementries[i+1].offset -= relocate_size;\n\t\tg_mementries[i].size = size;\n\n\t}\n\telse if(i > 0 && g_mementries[i-1].in_use == false) {\n\n\t\tg_mementries[i-1].in_use = true;\n\t\tg_mementries[i-1].size = relocate_size;\n\t\tg_mementries[i-1].offset = g_mementries[i].offset;\n\t\tg_mementries[i-1].claimed = false;\n\t\tg_mementries[i].offset += relocate_size;\n\t\tg_mementries[i].size = size;\n\t}\n\telse if((i+1) < ZMR_MAX_MEMENTRIES && g_mementries[i+1].in_use == false) {\n\n\t\tg_mementries[i+1].in_use = true;\n\t\tg_mementries[i+1].size = relocate_size;\n\t\tg_mementries[i+1].offset = g_mementries[i].offset + size;\n\t\tg_mementries[i+1].claimed = false;\n\t\tg_mementries[i].size = size;\n\t}\n}\n\nfunction int zmr_malloc(int size) {\n\tZMR_ASSERT(size < g_zmr_current_free_memory && size > 0);\n\n\tfor(int i = 0; i < ZMR_MAX_MEMENTRIES;++i) {\n\t\tif(g_mementries[i].claimed == false && g_mementries[i].in_use == true && g_mementries[i].size >= size) {\n\t\t\tg_mementries[i].claimed = true;\n\t\t\tzmr_malloc_relocating(i, size);\n\t\t\tg_zmr_current_free_memory -= size;\n\t\t\tint result = g_mementries[i].offset;\n\n\t\t\t//ZMR_DEBUG_LOG(s:\"Allocated memory, offset is \", d:result, s:\".\");\n\t\t\treturn result;\n\t\t}\n\t}\n\treturn 0;\n}\n\nfunction bool zmr_free(int offset) {\n\tfor(int i = 0; i < ZMR_MAX_MEMENTRIES;++i) {\n\t\tif(g_mementries[i].offset == offset) {\n\t\t\tint sz = g_mementries[i].size;\n\n\t\t\tg_mementries[i].claimed = false;\n\t\t\tzmr_free_relocating(i);\n\t\t\tg_zmr_current_free_memory += sz;\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction void zmr_write_i32(int ptr, int value) {\n\tZMR_ASSERT(ptr != 0);\n\tZMR_ASSERT((ptr & 3) == 0); //must be int aligned\n\n\tSetUserArray(g_zmr_pages[ZMR_PAGE_FOR_PTR(ptr)], \"user_data\", (ZMR_PAGE_OFFSET(ptr)) >> 2, value);\n}\n\nfunction int zmr_read_i32(int ptr) {\n\tZMR_ASSERT(ptr != 0);\n\tZMR_ASSERT((ptr & 3) == 0); //must be int aligned\n\treturn GetUserArray(g_zmr_pages[ZMR_PAGE_FOR_PTR(ptr)], \"user_data\", ZMR_PAGE_OFFSET(ptr) >> 2);\n}\n\n#define N_MONSTER_CLASSES 20\nint g_total_monsters = 0;\n\nstr g_monster_classes[N_MONSTER_CLASSES] = {\n\t\"SpiderMastermind\",\n\t\"Cyberdemon\",\n\t\"Archvile\",\n\t\"Arachnotron\",\n\t\"StealthArachnotron\",\n\t\"BaronOfHell\",\n\t\"Revenant\",\n\t\"StealthRevenant\",\n\t\"PainElemental\",\n\t\"Fatso\",\n\t\"HellKnight\",\n\t\"Cacodemon\",\n\t\"Spectre\",\n\t\"ChaingunGuy\",\n\t\"Demon\",\n\t\"ShotgunGuy\",\n\t\"DoomImp\",\n\t\"LostSoul\",\n\t\"WolfensteinSS\",\n\t\"ZombieMan\"\n};\n\nstr g_weight_cvar_strings[N_MONSTER_CLASSES] = {\n\t\"SpiderMastermind_weight\",\n\t\"Cyberdemon_weight\",\n\t\"Archvile_weight\",\n\t\"Arachnotron_weight\",\n\t\"StealthArachnotron_weight\",\n\t\"BaronOfHell_weight\",\n\t\"Revenant_weight\",\n\t\"StealthRevenant_weight\",\n\t\"PainElemental_weight\",\n\t\"Fatso_weight\",\n\t\"HellKnight_weight\",\n\t\"Cacodemon_weight\",\n\t\"Spectre_weight\",\n\t\"ChaingunGuy_weight\",\n\t\"Demon_weight\",\n\t\"ShotgunGuy_weight\",\n\t\"DoomImp_weight\",\n\t\"LostSoul_weight\",\n\t\"WolfensteinSS_weight\",\n\t\"ZombieMan_weight\"\n\n};\n\nint g_n_monsters_of_class[N_MONSTER_CLASSES] = {0};\n\nint g_monster_ratios[N_MONSTER_CLASSES] = {0};\n\n#define\t\tzmr_patherptr_t\t\tint\n#define\t\tzmr_pointvec_t\t\tint\nenum {\n\tZMR_PATHER_FIELD_startx = 0,\n\tZMR_PATHER_FIELD_starty = 4,\n\tZMR_PATHER_FIELD_startz = 8,\n\tZMR_PATHER_FIELD_goalx = 12,\n\tZMR_PATHER_FIELD_goaly = 16,\n\tZMR_PATHER_FIELD_goalz = 20,\n\tZMR_PATHER_FIELD_tid = 24,\n\tZMR_PATHER_FIELD_flags = 28,\n\tZMR_PATHER_FIELD_points = 32,\n\tZMR_PATHER_FIELD_goaltid = 36,\n\tZMR_PATHER_FIELD_tickpoll = 40,\n\tZMR_PATHER_FIELD_nextpather = 44,\n\tZMR_PATHER_FIELD_lasttick = 48,\n\tZMR_PATHER_FIELD_speed = 52,\n\tZMR_SIZEOF_PATHER = 56\n}\n\nenum {\n\tZMR_PATHER_FLAGS_in_use = 1,\n\tZMR_PATHER_FLAGS_allocated = 2,\n\tZMR_PATHER_FLAGS_completed = 4,\n\tZMR_PATHER_FLAGS_failed = 8\n}\n\n#define\t\tZMR_PATHER_SET_START(pather, x, y, z) {\\\n\t\t\tzmr_patherptr_t _pather = (pather); \\\n\t\t\tint _x = (x);\\\n\t\t\tint _y = (y);\\\n\t\t\tint _z = (z);\\\n\t\t\tWarp(zmr_read_i32(_pather + ZMR_PATHER_FIELD_tid), _x, _y, _z, 0, WARPF_ABSOLUTEPOSITION);\\\n\t\t\tzmr_write_i32(_pather + ZMR_PATHER_FIELD_startx, _x);\\\n\t\t\tzmr_write_i32(_pather + ZMR_PATHER_FIELD_starty, _y);\\\n\t\t\tzmr_write_i32(_pather + ZMR_PATHER_FIELD_startx, _z);\\\n\t\t\t}\n\n#define\t\tZMR_PATHER_SET_GOAL(pather, x, y, z) {\\\n\t\t\tzmr_patherptr_t _pather = (pather); \\\n\t\t\tint _x = (x);\\\n\t\t\tint _y = (y);\\\n\t\t\tint _z = (z);\\\n\t\t\ttid_t goal_tid = zmr_read_i32(_pather + ZMR_PATHER_FIELD_goaltid);\\\n\t\t\tWarp(goal_tid, _x, _y, _z, 0, WARPF_ABSOLUTEPOSITION);\\\n\t\t\tzmr_write_i32(_pather + ZMR_PATHER_FIELD_goalx, _x);\\\n\t\t\tzmr_write_i32(_pather + ZMR_PATHER_FIELD_goaly, _y);\\\n\t\t\tzmr_write_i32(_pather + ZMR_PATHER_FIELD_goalx, _z);\\\n\t\t\tThing_SetGoal(zmr_read_i32(_pather + ZMR_PATHER_FIELD_tid), goal_tid, 0, 1);\\\n\t\t\t}\n\nzmr_patherptr_t g_zmr_first_pather = 0;\n\nzmr_patherptr_t g_zmr_previous_pather = 0;\n\nfunction zmr_patherptr_t zmr_create_pathfinder(void) {\n\tzmr_patherptr_t pather = zmr_malloc(ZMR_SIZEOF_PATHER);\n\tZMR_ASSERT(pather != 0);\n\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_flags, 0);\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_tid, zmr_createPathfinderMonster());\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_goaltid, zmr_createPatrolPoint());\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_nextpather, 0);\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_points, 0);\n\n\t/*\n\t\tsave first pather so we can iterate over them\n\t*/\n\tif(g_zmr_first_pather == 0) {\n\n\t\tg_zmr_first_pather = pather;\n\t}\n\telse {\n\t/*\n\t\tlink new pather into the global list\n\t*/\n\t\tzmr_write_i32(g_zmr_previous_pather + ZMR_PATHER_FIELD_nextpather, pather);\n\n\t}\n\tg_zmr_previous_pather = pather;\n\treturn pather;\n}\n\n#define\t\tZMR_FOREACH_PATHER(indexvar)\t\tfor(zmr_patherptr_t indexvar = g_zmr_first_pather; indexvar != 0; indexvar = zmr_read_i32(indexvar + ZMR_PATHER_FIELD_nextpather))\n\n/*\n\tfind an unused pathfinder in the global list to reuse\n\tor allocate a new one\n*/\nfunction zmr_patherptr_t zmr_allocate_pathfinder(void) {\n\tZMR_FOREACH_PATHER(pather) {\n\t\tint pather_flags = zmr_read_i32(pather + ZMR_PATHER_FIELD_flags);\n\t\tif((pather_flags & ZMR_PATHER_FLAGS_allocated) == 0) {\n\t\t\tzmr_write_i32(pather + ZMR_PATHER_FIELD_flags, pather_flags | ZMR_PATHER_FLAGS_allocated);\n\t\t\treturn pather;\n\t\t}\n\t}\n\n\tzmr_patherptr_t new_pather = zmr_create_pathfinder();\n\tzmr_write_i32(new_pather + ZMR_PATHER_FIELD_flags, ZMR_PATHER_FLAGS_allocated);\n\treturn new_pather;\n}\n\nfunction void zmr_release_pathfinder(zmr_patherptr_t pather) {\n\tZMR_ASSERT(pather != 0);\n\tzmr_pointvec_t point_data = zmr_read_i32(pather + ZMR_PATHER_FIELD_points);\n\tif(point_data != 0) {\n\t\tzmr_free(point_data);\n\t\tzmr_write_i32(pather + ZMR_PATHER_FIELD_points, 0);\n\t}\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_flags, zmr_read_i32(pather + ZMR_PATHER_FIELD_flags) & (~ZMR_PATHER_FLAGS_allocated));\n\n}\n\nenum {\n\tZMR_POINTVEC_FIELD_position = 0,\n\tZMR_POINTVEC_FIELD_nalloc = 4,\n\tZMR_SIZEOF_POINTVEC = 8\n}\n\nenum {\n\tZMR_POINT_FIELD_x = 0,\n\tZMR_POINT_FIELD_y = 4,\n\tZMR_POINT_FIELD_z = 8,\n\tZMR_SIZEOF_POINT = 12\n}\n\nfunction zmr_pointvec_t zmr_create_pointvec(int maxpoints) {\n\tZMR_ASSERT(maxpoints > 0);\n\n\tzmr_pointvec_t points = zmr_malloc(ZMR_SIZEOF_POINTVEC + (ZMR_SIZEOF_POINT * maxpoints));\n\tZMR_ASSERT(points != 0);\n\n\tzmr_write_i32(points + ZMR_POINTVEC_FIELD_position, 0);\n\tzmr_write_i32(points + ZMR_POINTVEC_FIELD_nalloc, maxpoints);\n\treturn points;\n}\n\nfunction void zmr_release_pointvec(zmr_pointvec_t points) {\n\tZMR_ASSERT(points != 0);\n\tzmr_free(points);\n}\n\nfunction void zmr_pointvec_set_at(zmr_pointvec_t points, int x, int y, int z, int index) {\n\tint start_offs = (points + ZMR_SIZEOF_POINTVEC) + (index * ZMR_SIZEOF_POINT);\n\n\tzmr_write_i32(start_offs + ZMR_POINT_FIELD_x, x);\n\tzmr_write_i32(start_offs + ZMR_POINT_FIELD_y, y);\n\tzmr_write_i32(start_offs + ZMR_POINT_FIELD_z, z);\n\n}\n\nfunction zmr_patherptr_t zmr_find_path(\nint startx, int starty, int startz,\nint goalx, int goaly, int goalz,\nint movement_speed, int tick_granularity, int maxpoints) {\n\tzmr_patherptr_t pather = zmr_allocate_pathfinder();\n\n\tZMR_ASSERT(pather != 0);\n\n\tZMR_PATHER_SET_START(pather, startx, starty, startz)\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_lasttick, Timer());\n\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_tickpoll, tick_granularity);\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_points, zmr_create_pointvec(maxpoints));\n\tZMR_PATHER_SET_GOAL(pather, goalx, goaly, goalz)\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_speed, movement_speed);\n\n\tSetActorProperty( zmr_read_i32(pather + ZMR_PATHER_FIELD_tid), APROP_SPEED, movement_speed);\n\n\tzmr_write_i32(pather + ZMR_PATHER_FIELD_flags, zmr_read_i32(pather + ZMR_PATHER_FIELD_flags) | ZMR_PATHER_FLAGS_in_use);\n\n\treturn pather;\n\n}\n\nint\ng_current_unique_id = 1;\n\nint g_uid_tid_lut = 0;\n\nint g_uid_tid_mod = 0;\n\n//i swear to god, this value wasnt randomly chosen. i used the m,n formula for collision calculation and this\n//was the ideal table scale\n#define\t\tZMR_ZEROCOLLIDE_SCALE\t\t666\n\n#define \tZMR_MONSTER_DATA_SIZE\t\t512\n\nenum {\n\tZMR_MONSTER_FIELD_prev = 0,\n\tZMR_MONSTER_FIELD_next = 4,\n\tZMR_MONSTER_FIELD_thingid = 8,\n\tZMR_MONSTER_FIELD_lastx = 12,\n\tZMR_MONSTER_FIELD_lasty = 16,\n\tZMR_MONSTER_FIELD_lastz = 20,\n\tZMR_MONSTER_FIELD_buddy = 24,\n\tZMR_MONSTER_FIELD_dead\t= 28,\n\tZMR_MONSTER_FIELD_initial_health = 32,\n\tZMR_MONSTER_FIELD_flee_timepoint = 36,\n\tZMR_MONSTER_FIELD_is_fleeing = 40,\n\tZMR_MONSTER_FIELD_has_missile = 44\n}\n\n#define\t\tzmr_monsterptr_t\t\t\t\tint\n\n#define\t\tZMR_M0NSTER_READ(monster, field, type)\t\t\t\tzmr_read_##type ((monster) + (ZMR_MONSTER_FIELD_##field ))\n#define\t\tZMR_M0NSTER_WRITE(monster, field, type, val)\t\tzmr_write_##type ((monster) +ZMR_MONSTER_FIELD_##field , (val))\nzmr_monsterptr_t g_zmr_last_monster_alloc = 0;\nzmr_monsterptr_t g_zmr_first_monster = 0;\n\nfunction zmr_monsterptr_t zmr_alloc_monster_data(void) {\n\n\tzmr_monsterptr_t p = zmr_malloc(ZMR_MONSTER_DATA_SIZE);\n\n\tZMR_M0NSTER_WRITE(p, prev, i32, g_zmr_last_monster_alloc);\n\n\tif(g_zmr_last_monster_alloc != 0)\n\t\tZMR_M0NSTER_WRITE(g_zmr_last_monster_alloc, next, i32, p);\n\telse\n\t\tg_zmr_first_monster = p;\n\n\tg_zmr_last_monster_alloc = p;\n\treturn p;\n}\n\nbool g_zmr_monster_globals_initialized = false;\n\nfunction void zmr_monster_global_ensure_init(void) {\n\tif(!g_zmr_monster_globals_initialized) {\n\n\t\tzmr_ensure_init();\n\n\t\t//WASTE MEMORY\n\t\tzmr_malloc(32);\n\t\tg_total_monsters = GetLevelInfo(LEVELINFO_TOTAL_MONSTERS);\n\t\tg_uid_tid_mod = (g_total_monsters) * ZMR_ZEROCOLLIDE_SCALE;\n\t\tg_uid_tid_lut = zmr_malloc(((g_total_monsters) * ZMR_ZEROCOLLIDE_SCALE) * sizeof(int));\n\n\t\tg_zmr_monster_globals_initialized = true;\n\n\tACS_NamedExecute(\"ZMR_UpdateBuddies\", 0);\n\tACS_NamedExecute(\"ZMR_UpdatePaths\", 0);\n\t}\n}\n\n/*\n\tzero is not a valid uid\n*/\nfunction bool zmr_monster_has_uid(int tid) {\n\treturn GetUserVariable(tid, \"user_ZMR_enemy_uid\") != 0;\n}\n\nfunction int zmr_monster_get_uid(int tid) {\n\treturn GetUserVariable(tid, \"user_ZMR_enemy_uid\");\n}\n\nfunction void zmr_assign_uid_impl(void) {\n\tzmr_monster_global_ensure_init();\n\tg_current_unique_id = g_current_unique_id + 1;\n\tSetUserVariable(0, \"user_ZMR_enemy_uid\", g_current_unique_id);\n\tzmr_monsterptr_t myptr = zmr_alloc_monster_data();\n\tif(ActivatorTID() ==0)\n\t\tThing_ChangeTID(0, UniqueTID());\n\tint _tid = ActivatorTID();\n\tif(_tid == 0) {\n\t\t//ZMR_DEBUG_LOG(s:\"Got a zero tid in ZMR_AssignUID!\");\n\t}\n\tZMR_M0NSTER_WRITE(myptr, thingid, i32, _tid);\n\tzmr_write_i32(myptr + ZMR_MONSTER_FIELD_initial_health, GetActorProperty(_tid, APROP_HEALTH));\n\tzmr_set_monster_dataptr(g_current_unique_id, myptr);\n\n}\n\nfunction zmr_monsterptr_t zmr_get_monster_dataptr(int uid) {\nzmr_monster_global_ensure_init();\n\tif(uid == 0) {\n\n\t\tzmr_assign_uid_impl();\n\n\t\treturn 0;\n\t}\n\tzmr_monsterptr_t result = zmr_read_i32( g_uid_tid_lut + ((uid % g_uid_tid_mod) << 2));\n\tZMR_ASSERT(result != 0);\n\treturn result;\n}\nfunction void zmr_set_monster_dataptr(int uid, zmr_monsterptr_t dataptr) {\n\tZMR_ASSERT(dataptr != 0);\n\n\tzmr_write_i32( g_uid_tid_lut + ((uid % g_uid_tid_mod) << 2), dataptr);\n}\n\n#define\t\tZMR_FOREACH_MONSTER(indexname)\t\tfor(zmr_monsterptr_t indexname = g_zmr_first_monster; indexname != 0; indexname = zmr_read_i32(indexname + ZMR_MONSTER_FIELD_next))\n\n#define\t\tZMR_MONSTER_IS_DEAD(monster)\t\t(GetActorProperty(zmr_read_i32((monster) + ZMR_MONSTER_FIELD_thingid), APROP_Health) <= 0)\n\n//(zmr_read_i32((monster) + ZMR_MONSTER_FIELD_dead) != 0\n\nfunction zmr_monsterptr_t find_closest_monster(zmr_monsterptr_t self) {\n\n\tif(self == 0)\n\t\treturn 0;\n\tint mytid = zmr_read_i32(self+ZMR_MONSTER_FIELD_thingid);\n\n\tint selfx = GetActorX(mytid),//zmr_read_i32(self + ZMR_MONSTER_FIELD_lastx),\n\t\tselfy = GetActorY(mytid),//zmr_read_i32(self + ZMR_MONSTER_FIELD_lasty),\n\t\tselfz = GetActorZ(mytid);//zmr_read_i32(self + ZMR_MONSTER_FIELD_lastz);\n\n\tint smallest_absdistance = 0x7fffffff;\n\n\tzmr_monsterptr_t closest_found = 0;\n\n\tZMR_FOREACH_MONSTER(i) {\n\t\tif(i == self || ZMR_MONSTER_IS_DEAD(i) )\n\t\t\tcontinue;\n\t\tint theirtid = zmr_read_i32(i+ZMR_MONSTER_FIELD_thingid);\n\n\tint x = GetActorX(theirtid);//zmr_read_i32(i + ZMR_MONSTER_FIELD_lastx);\n\tint y = GetActorY(theirtid);//zmr_read_i32(i + ZMR_MONSTER_FIELD_lasty);\n\t//int z = zmr_read_i32(i + ZMR_MONSTER_FIELD_lastz);\n\n\tint len = VectorLength(selfx - x, selfy - y);\n\t//len = VectorLength(selfz - z, len);\n\n\tif(len < smallest_absdistance) {\n\t\tsmallest_absdistance = len;\n\t\tclosest_found = i;\n\t}\n\n\t}\n\t//ZMR_DEBUG_LOG(s:\"Closest found is \", d: smallest_absdistance);\n\n\treturn closest_found;\n}\n\nScript \"ZMR_UpdateBuddies\" (void) NET {\nzmr_monster_global_ensure_init();\n\twhile(true) {\n\t\tDelay(1);\n\t\tint counter = 0;\n\t\tZMR_FOREACH_MONSTER(i) {\n\t\t\tif(ZMR_MONSTER_IS_DEAD(i))\n\t\t\t\tcontinue;\n\n\t\t\tzmr_write_i32(i + ZMR_MONSTER_FIELD_buddy, find_closest_monster(i));\n\t\t\t++counter;\n\n\t\t\tif((counter & 0xF) == 0)\n\t\t\t\tDelay(1);\n\t\t}\n\t}\n}\nScript \"ZMR_UpdatePaths\" (void) NET {\nzmr_monster_global_ensure_init();\n\twhile(true) {\n\t\tDelay(10);\n\t\tint current_tick = Timer();\n\t\tZMR_FOREACH_PATHER(path) {\n\t\t\tint flags = zmr_read_i32(path + ZMR_PATHER_FIELD_flags);\n\t\t\tif( (flags & (ZMR_PATHER_FLAGS_completed | ZMR_PATHER_FLAGS_failed)) != 0\n\t\t\t\t||\n\t\t\t\t(flags & ZMR_PATHER_FLAGS_in_use) == 0)\n\t\t\t\tcontinue;\n\n\t\t\tint last_tick = zmr_read_i32(path + ZMR_PATHER_FIELD_lasttick);\n\t\t\tint tickpoll = zmr_read_i32(path + ZMR_PATHER_FIELD_tickpoll);\n\n\t\t\tif( (last_tick + tickpoll) < current_tick) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tzmr_write_i32(path + ZMR_PATHER_FIELD_lasttick, current_tick);\n\n\t\t\tzmr_pointvec_t points = zmr_read_i32(path + ZMR_PATHER_FIELD_points);\n\t\t\tZMR_ASSERT(points != 0);\n\n\t\t\tint current_pointvec_index = zmr_read_i32(points + ZMR_POINTVEC_FIELD_position);\n\n\t\t\tint pointvec_nalloc = zmr_read_i32(points + ZMR_POINTVEC_FIELD_nalloc);\n\n\t\t\tint pather_tid = zmr_read_i32(path + ZMR_PATHER_FIELD_tid);\n\n\t\t\tint currentx = GetActorX(pather_tid),\n\t\t\t\tcurrenty = GetActorY(pather_tid),\n\t\t\t\tcurrentz = GetActorZ(pather_tid);\n\n\t\t\tint goalx = zmr_read_i32(path + ZMR_PATHER_FIELD_goalx),\n\t\t\t\tgoaly = zmr_read_i32(path + ZMR_PATHER_FIELD_goaly),\n\t\t\t\tgoalz = zmr_read_i32(path + ZMR_PATHER_FIELD_goalz);\n\n\t\t\tint len = VectorLength(goalx - currentx, goaly - currenty);\n\t\t\tlen = VectorLength(goalz - currentz, len);\n\n\t\t\tint movement_speed = zmr_read_i32(path + ZMR_PATHER_FIELD_speed);\n\n\t\t\tif( len < movement_speed) {\n\t\t\t\tzmr_write_i32(path + ZMR_PATHER_FIELD_flags, flags | ZMR_PATHER_FLAGS_completed);\n\t\t\t\tSetActorProperty( pather_tid, APROP_SPEED, 0);\n\t\t\t}\n\n\t\t\telse if((current_pointvec_index + 1) >= pointvec_nalloc) {\n\t\t\t\tzmr_write_i32(path + ZMR_PATHER_FIELD_flags, flags | ZMR_PATHER_FLAGS_failed);\n\t\t\t\tSetActorProperty( pather_tid, APROP_SPEED, 0);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tzmr_pointvec_set_at(points, currentx, currenty, currentz, current_pointvec_index);\n\n\t\t\tzmr_write_i32(points + ZMR_POINTVEC_FIELD_position, current_pointvec_index + 1);\n\n\t\t}\n\t}\n}\nScript 32766 OPEN NET\n{\n\tzmr_monster_global_ensure_init();\n\n\tfor( int i = 0; i < N_MONSTER_CLASSES; ++i) {\n\t\tg_n_monsters_of_class[i] = ThingCountName(g_monster_classes[i], 0);\n\t\tif(g_n_monsters_of_class[i] != 0)\n\t\t\tg_monster_ratios[i] = (g_total_monsters/ g_n_monsters_of_class[i]);\n\n\t\t\t\t\tint x = ((N_MONSTER_CLASSES+1) - i) * g_monster_ratios[i];\n\t\t\tSetCVar(g_weight_cvar_strings[i], x);\n\t}\n\n\tACS_NamedExecute(\"ZMR_UpdateBuddies\", 0);\n\tACS_NamedExecute(\"ZMR_UpdatePaths\", 0);\n\n}\n\n#define\t\tZMR_thunk_prologue\t\\\n\t\t\tzmr_monster_global_ensure_init();\\\n\t\t\tif(zmr_monster_has_uid(0) == false)\\\n\t\t\t\tterminate;\\\n\t\t\tzmr_monsterptr_t self = zmr_get_monster_dataptr(zmr_monster_get_uid(ActivatorTID()) );\\\n\t\t\tif(self == 0) \\\n\t\t\t\tterminate;\\\n\t\t\tzmr_write_i32(self + ZMR_MONSTER_FIELD_lastx, GetActorX(0));\\\n\t\t\tzmr_write_i32(self + ZMR_MONSTER_FIELD_lasty, GetActorY(0));\\\n\t\t\tzmr_write_i32(self + ZMR_MONSTER_FIELD_lastz, GetActorZ(0));\n\nScript \"ZMR_OnDeath\" KILL NET {\n\tZMR_thunk_prologue\n\n\tZMR_DEBUG_LOG(s:\"Dead monster had tid \", d: ZMR_M0NSTER_READ( self, thingid, i32), s:\".\");\n\tZMR_DEBUG_LOG(s:\"Dead monster had buddy with tid \", d: ZMR_M0NSTER_READ( zmr_read_i32(self + ZMR_MONSTER_FIELD_buddy), thingid, i32), s:\".\");\n\n\tzmr_write_i32(self + ZMR_MONSTER_FIELD_dead, 1);\n\tSetActivatorToTarget(0);\n\n\tint target = ActivatorTID();\n\n\tzmr_monsterptr_t buddy = zmr_read_i32(self + ZMR_MONSTER_FIELD_buddy);\n\n\tif(buddy == 0 )//|| ZMR_MONSTER_IS_DEAD(buddy))\n\t\tterminate;\n\n\t//SetActivator(zmr_read_i32(buddy + ZMR_MONSTER_FIELD_thingid));\n\n\t//SetPointer(AAPTR_TARGET, target);\n\t//SetActorState(0, \"See\");\n\n\tint i = 0;\n\tzmr_monsterptr_t otherbuddy;\n\tfor( otherbuddy = zmr_read_i32(buddy + ZMR_MONSTER_FIELD_buddy); otherbuddy != 0 && otherbuddy != buddy;\n\n\t\totherbuddy = zmr_read_i32(otherbuddy + ZMR_MONSTER_FIELD_buddy),++i) {\n\n\t\tif(i > 4)\n\t\t\tbreak;\n\t\tif (!ZMR_MONSTER_IS_DEAD(otherbuddy)){\n\n\t\tSetActivator(zmr_read_i32(otherbuddy + ZMR_MONSTER_FIELD_thingid));\n\n\t\tSetPointer(AAPTR_TARGET, target);\n\t\tSetActorState(0, \"See\");\n\t\tbuddy = otherbuddy;\n\t\t}\n\t}\n\n\tif(i != 0) {\n\t\tZMR_DEBUG_LOG(s:\"They're coming for you! \", d:i );\n\t}\n\telse\n\t\tZMR_DEBUG_LOG(s:\"He's coming for you!\");\n}\n\nScript \"ZMR_Hierophant_GravManip\" (void) {\n}\n\nScript \"ZMR_monster_OnIdle\" (void) {\n}\n\nscript \"ZMR_monster_OnSee\" (void) NET {\nZMR_thunk_prologue\n\n}\n\nscript \"ZMR_monster_OnMelee\" (void) {\n\n}\n\nscript \"ZMR_monster_OnMissile\" (void) NET {\nZMR_thunk_prologue\n\tzmr_write_i32(self + ZMR_MONSTER_FIELD_has_missile, 1);\n\n}\n\nscript \"ZMR_monster_OnPain\" (void) NET {\n\tZMR_thunk_prologue\n\tint curr_tick = Timer();\n\tif(zmr_read_i32(self + ZMR_MONSTER_FIELD_is_fleeing) == 1) {\n\n\t\tif( curr_tick - zmr_read_i32(self + ZMR_MONSTER_FIELD_flee_timepoint) >= 50) {\n\n\t\t\tzmr_write_i32(self + ZMR_MONSTER_FIELD_is_fleeing, 0);\n\t\t\tSetActorProperty(0, APROP_Frightened, 0);\n\t\t\tint original_speed = GetActorProperty(0, APROP_Speed);\n\t\t\toriginal_speed = (original_speed >> 2) * 3;\n\t\t\tSetActorProperty(0, APROP_Speed, original_speed);\n\t\t\tZMR_DEBUG_LOG(s:\"Nah, fuck you.\");\n\t\t\t/*\n\t\t\t\tWe put some distance between us and them, so if we have\n\t\t\t\ta missile attack use it\n\t\t\t*/\n\t\t\tif(zmr_read_i32(self + ZMR_MONSTER_FIELD_has_missile) == 1)\n\t\t\t\tSetActorState(0, \"Missile\");\n\t\t\telse {\n\t\t\t\tSetActorState(0, \"See\");\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tterminate;\n\t}\n\tint myhealth = GetActorProperty(0, APROP_Health);\n\tint initial_health = zmr_read_i32(self + ZMR_MONSTER_FIELD_initial_health);\n\n\t/*\n\t\tpanic mode - 50% health - 25%\n\t*/\n\tif(myhealth < (initial_health >> 1) && myhealth >= (initial_health >> 2) ) {\n\t\tSetActorProperty(0, APROP_Frightened, 1);\n\t\tint original_speed = GetActorProperty(0, APROP_Speed);\n\t\toriginal_speed += original_speed >> 1;\n\t\tSetActorProperty(0, APROP_Speed, original_speed);\n\t\tzmr_write_i32(self + ZMR_MONSTER_FIELD_flee_timepoint, curr_tick);\n\t\tzmr_write_i32(self + ZMR_MONSTER_FIELD_is_fleeing, 1);\n\t\tZMR_DEBUG_LOG(s:\"I'm scared!\");\n\t}\n\t/*\n\t\tdesperation - other monsters attacking this monster should leave them alone\n\n\t\tmonster attacks slightly faster in a sort of frenzied way\n\t*/\n\telse if (myhealth < (initial_health >> 2)) {\n\t\tint reaction_time = GetActorProperty(0, APROP_ReactionTime);\n\t\tSetActorProperty(0, APROP_ReactionTime, reaction_time + (reaction_time >> 3));\n\t\tSetActorProperty(0, APROP_NOTARGET, 1);\n\t\tZMR_DEBUG_LOG(s:\"I'm desperate\");\n\t}\n\n}\n\nscript \"ZMR_monster_OnResurrected\" (void) NET {\n\t\t\tzmr_monster_global_ensure_init();\n\n}\n\nscript \"ZMR_monster_OnSpawn\" (void) NET {\n zmr_monster_global_ensure_init();\n\tzmr_assign_uid_impl();\n}\nScript \"ZMR_AssignUID\" (void) {\nzmr_monster_global_ensure_init();\n\t//zmr_monster_global_ensure_init();\nzmr_assign_uid_impl();\n}\n\nscript \"ZMR_OnUnload\" UNLOADING NET {\nzmr_monster_global_ensure_init();\n\tACS_NamedTerminate(\"ZMR_UpdateBuddies\", 0);\n\n\tzmr_deinit_mman();\n\tg_zmr_monster_globals_initialized = false;\n\tg_current_unique_id = 1;\n\tg_zmr_last_monster_alloc = 0;\n}\n\nscript 32767 (void) NET\n{\nzmr_monster_global_ensure_init();\n\t//zmr_monster_global_ensure_init();\n\tSetActorState(0,\"Demonic\",true);\n\n}"
}
]
},
"maps": []
}