7 Commits
Author SHA1 Message Date
bdot89andClaude Opus 5.5 262333a852 2.23.0: weapon glows are shared, setup pop-up at login
- other DMorph users (2.23+) see your weapon glows: a g token in look
  messages and G messages; receivers put glows on with DmorphHelper and
  keep them on, skipping glows their game doesn't have
- a pop-up a few seconds after login or /reload when VanillaHelpers isn't
  running or DmorphHelper is missing or older (Don't remind me until the
  next helper version)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 20:20:18 +01:00
bdot89andClaude Opus 5.5 08d5bcd0b2 2.22.0: item morphs survive durability changes, revives and repairs
1.12 fires no event for a durability change, so the game's redraw of those
slots from the real items went unseen. The morphed slots' durability is now
read once a second, and dying, coming back to life (rebuilt twice), closing a
vendor and inventory alerts check at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 20:04:52 +01:00
bdot89andClaude Opus 5.5 4cde13cf62 Docs: Ported Pack via a DM to benito9295 on Discord
The server invite expired in 30 days; every Discord button and link now
says "DM benito9295 on Discord" and opens that profile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 00:12:02 +01:00
bdot89andClaude Opus 5.5 c5588f44b9 Docs: project page follows the README; Ported Pack via Discord
- project page rebuilt in the README's order and words (intro, What you
  get, every tab, install steps), in the banner's green and purple
- Ported Pack section on both: how to install it, download links on the
  OctoWoW Hub Discord (no download links on GitHub)
- Discord buttons at the top, in the pack section and the footer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 23:15:17 +01:00
bdot89andClaude Opus 5.5 e85de01704 Banner: the download badge matches the slogan plate
Same dark glass, green-to-purple border and side glows, gradient
lettering in the slogan's font.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:48:57 +01:00
bdot89andClaude Opus 5.5 9b7a2199bd Banner: "Forge your illusion!" plate under the group
A glowing plate on the ground under the characters, in the banner's
green-to-purple, with "Share DMorph with your friends to see each
other's looks" under it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:47:24 +01:00
bdot89andClaude Opus 5.5 0001efd729 Docs: new banner from the group screenshot, every number recounted
- banner: the user's group shot, title and accents in its own fel green
  (#72F92B) and outline purple (#B44CFF)
- numbers counted from the data files and the pack list: 16,000+
  creatures (13,000+ models), 950 mounts, 13,000+ items, 351 sets; pack
  8,157 creatures, 2,193 mounts, 48,889 weapons and armour, 915 sets
- mount numbers added to the README, project page, toc notes and banner

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:45:11 +01:00
11 changed files with 687 additions and 218 deletions
+2
View File
@@ -170,4 +170,6 @@ The live copy is the game's `Interface\AddOns\DmorphOcto` folder, a git checkout
- 2.21.7 (19 Oct), SEEN IN GAME, /dmorph frametest on 63568 (Colossal Umbrahide Mawrat): A (fit, world-unit move), B (move / scale) and E (no turning of the middle) were pixel-identical, and the quarter-turned row matched the first: with a model camera set this client ignores SetPosition and SetFacing; only SetModelScale shows (weaker than predicted). C (portrait, scale 1) = the head close-up; D (no camera, scale 0.1 / height) drew nothing. So every fit of 2.21.0-2.21.6 was moot. The ported mounts carry a "character info" camera (type 1, lookup 0,1), Blizzard's own whole-model framing: GameFiles.Frame now adds a 10th value (1 = has one; 2,918 of 2,984 ported models, 389 of 679 stock), and views use SetCamera(1) for those, else SetCamera(0) (the portrait, as before 2.21), never moved; zoom = scale (P.ViewCamera, FrameView). Boxes and tiles don't turn while a camera is set (SetFacing ignored). The frame test now shows A camera 1, B camera 0, C/D camera 1 at scale 0.7/1.4, E no camera. Unverified: that SetCamera(1) picks the type-1 camera (index or ID: both 1 for these models).
- 2.21.8 (19 Oct), user: 2.21.7 "all good apart from I can't drag the model around or zoom in myself, use the same controls as the character window" (screenshot: Rusty Mechanocrawler whole and centred in the Your skin box). Views (boxes, tiles, the stage's creature view) are now PlayerModels when ClassicAPI's SetDisplayInfo exists on one (ui.playerViews, probed at Build; else Models as before): they turn with SetRotation (P.TurnView) and FrameView also sets SetPosition(zoom * 0.3, panX * 3, panY * 3) like the dressing room, on top of the zoom scale. Untested in game: SetDisplayInfo on a PlayerModel, and that a PlayerModel with SetCamera(1) honours SetPosition / SetRotation as the dressing room's does.
- 2.21.9 (19 Oct), user: 2.21.8 still didn't drag or zoom. An explicit SetCamera seems to lock any model frame's transform (the frame test's A/B/E; the 2.21.8 PlayerModels still had SetCamera(1)). The dressing room's PlayerModel never gets SetCamera and moves/turns fine with its own player-sized view; the Arboon morph filled it because a 14-unit creature was drawn at full size in that view. So PlayerModel views (ui.playerViews) now get no SetCamera at all, are scaled to a player's height (P.PLAYER_SIZE 2.2 / max(height, width * 0.75) from the frame data) and zoom / pan by SetPosition like the dressing room; SetRotation turns them. Model views (no ClassicAPI on PlayerModels) keep 2.21.7's camera choice. SEEN IN GAME (user, 19 Oct): "the preview drags, zooms and moves now". Lesson: never SetCamera on a preview you want to move; ClassicAPI's SetDisplayInfo works on PlayerModels.
- 2.22.0, user (21 Oct): "the durability bug again: losing durability changes items; a spirit res or being revived loses items; repairing loses items". All three are durability changes, after which the game redraws those slots from the real items; 2.17.5 only re-checked durability on UNIT_INVENTORY_CHANGED, which 1.12 evidently doesn't fire for a durability change. GearCheck(force) (M.GearCheck) now also runs once a second (GEAR_POLL; GearState reads the morphed slots' durability from the hidden tooltip, so a change rebuilds the model as before, still at most once a second), on PLAYER_DEAD, MERCHANT_CLOSED (repairs) and UPDATE_INVENTORY_ALERTS, and forced on PLAYER_ALIVE / PLAYER_UNGHOST with a second forced check RES_AGAIN (1.5 s) later, as the game builds the living model again after those events. Event names checked in WoW.exe. Tests: change with no event found by the poll, revive rebuilds twice, repair on vendor close, no repeat rebuild (2 mutations). Untested in game: whether one rebuild per second while tanking (durability ticks) is noticeable.
- 2.23.0, user: "weapon glows are not sharing looks" (they never were) and "if someone has an outdated version or hasn't run the DmorphHelper installer, a pop-up when logging in or reloading". (1) Share.lua: M.GetSharedGlows() (db.glows of 16-18, 0 = No glow; hover previews not sent) goes as a "g" token (slot letter p/q/r + base-36 enchant per hand) after the guid in L and H messages, after the size token (DMorph before 2.23 reads H's third token as the size and drops one it can't read; its ReadLook skips unknown tokens), and alone as "G <token|->" (timers.glow, SETTLE like sizes). Not in the fingerprint (like sizes). Receivers keep peer.glows (GlowsOf: only enchants M.IsKnownGlow knows, i.e. in this PC's glow list, ported ones only with the pack's glows), SetPeerGlows bumps the version; KeepGlows (every scan, also when the version didn't change) writes the glow with DmorphHelper_SetItemEnchants(token, slot, glow, 0) when the field differs, records their real enchant whenever the field shows something else (a server resend), and writes it back when the glow goes. Glows tab note now "DMorph users (2.23+) see it too." (2) UI.lua: P.SetupProblem() (no VanillaHelpers, no DmorphHelper, or DmorphHelper_Version < HELPER_VERSION) shown as StaticPopup DMORPHOCTO_SETUP SETUP_NAG_DELAY (5 s) after the first PLAYER_ENTERING_WORLD of each UI load; "Don't remind me" (button2/OnCancel, no hideOnEscape so Escape doesn't count) stores DmorphOctoAccount.setupNagOff = HELPER_VERSION, so a newer helper nags again. Tests: glow on, put back after a resend, removed with G -, unknown glow skipped, token after s, sent G and in replies (mutation-checked); pop-up without helper, not before 5 s, older helper text, Don't remind me, none with the right helper. Untested in game: DmorphHelper_SetItemEnchants on another player (the DLL accepts friendly players; never used on others before), how often the server resends their weapon fields.
- 12 Oct 2026, seen in game: the user and a friend with the same pack (Install Ported.bat on the friend's PC, game at C:\client) see each other's ported looks (2.14.0 sharing works). The friend's list first showed no ported models until a full game restart; a quick check is `/run DEFAULT_CHAT_FRAME:AddMessage(tostring(DmorphOcto.GetPortedPack()))` (nil = Ported.lua not loaded; the user's pack is L201088x2612617x53695). The user's Config.wtf has scriptMemory 512000 (Ported.lua is 2.8 MB): suspect a low value if Ported.lua fails to load elsewhere.
+92 -15
View File
@@ -11,7 +11,7 @@
-- The client runs Lua 5.0: no #, no %, no string.match, no select(), and
-- table.getn() counts element by element, so long lists keep their own count.
local VERSION = "2.21.9"
local VERSION = "2.23.0"
local PREFIX = "|cff33ff99DMorph|r: "
-- VANILLAHELPERS_VERSION is major * 10000 + minor * 100 + patch; morphing
-- came in v1.1.0. Older versions load and set it, but can't morph.
@@ -2089,6 +2089,36 @@ function M.GetSharedLook()
return display, items, mount
end
-- Your picked weapon glows for other DMorph users (2.23.0, user: "weapon glows
-- are not sharing"): slot (16-18) -> enchant ID, 0 for "No glow". A glow only
-- hovered in the Glows tab isn't sent.
function M.GetSharedGlows()
InitDB()
local glowsOut = {}
for slot in pairs(GLOW_SLOT) do
if db.glows[slot] then
glowsOut[slot] = db.glows[slot]
end
end
return glowsOut
end
-- Whether this PC can show a glow someone sent: 0 (no glow) or an enchant in
-- the glow list (a ported one only with the ported pack's glows).
function M.IsKnownGlow(enchantID)
if enchantID == 0 then
return true
end
local all = M.GetGlows()
if not all.byEnchant then
all.byEnchant = {}
for i = 1, all.count do
all.byEnchant[all.enchant[i]] = true
end
end
return all.byEnchant[enchantID] or false
end
-- The ported parts of your look (display, items, mount), which only DMorph
-- users with the same ported pack can show; nil where a part isn't ported.
function M.GetSharedPorted()
@@ -4043,24 +4073,26 @@ end
-- reports (bags, loot, food, every arrow, bullet or throw): rebuilding the
-- model while you move left you running on the spot or frozen, and on every
-- shot made a hunter blink and broke the shooting animation (users, 15-17 Oct).
--
-- 2.22.0 (user, 21 Oct: items still changed when losing durability, after a
-- spirit res or being revived, and after repairing): 1.12 doesn't fire
-- UNIT_INVENTORY_CHANGED for a durability change, so those redraws went
-- unseen. The morphed slots' durability is now also read once a second
-- (GEAR_POLL), and dying, releasing, being resurrected and closing a vendor
-- (repairs) check at once; coming back to life rebuilds twice (now and
-- RES_AGAIN seconds later), as the game builds your living model again after
-- the events.
local GEAR_POLL, RES_AGAIN = 1, 1.5
local itemFrame = CreateFrame("Frame")
itemFrame:RegisterEvent("UNIT_INVENTORY_CHANGED")
itemFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
itemFrame:SetScript("OnEvent", function()
if event == "PLAYER_ENTERING_WORLD" then
-- What you have on (GearState) against the last look: a change gets the
-- morphs checked and, a fifth of a second later, the model rebuilt.
local function GearCheck(force)
if not next(db.items) then
itemCheck.gear, itemCheck.counts = GearState()
-- The game can build your model before it has the items your morphs
-- show (a ported piece needs its template from the server), which
-- leaves you invisible, white in previews: then rebuilt once they're
-- all in (or after LOGIN_WAIT seconds), see below.
itemCheck.loginWait = not MorphedItemsLoaded() and 0 or nil
return
end
if arg1 ~= "player" then
return
end
local gear, counts = GearState()
local changed = gear ~= itemCheck.gear
local changed = force or gear ~= itemCheck.gear
itemCheck.gear, itemCheck.counts = gear, counts
if itemCheck.clock < (itemCheck.ignoreUntil or -1) then
-- Right after our own rebuild (which changes none of this): a real
@@ -4072,10 +4104,55 @@ itemFrame:SetScript("OnEvent", function()
end
CheckItems()
if changed then
this.wait = 0.2
itemFrame.wait = 0.2
end
end
M.GearCheck = GearCheck
itemFrame:RegisterEvent("UNIT_INVENTORY_CHANGED")
itemFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
itemFrame:RegisterEvent("PLAYER_DEAD")
itemFrame:RegisterEvent("PLAYER_ALIVE")
itemFrame:RegisterEvent("PLAYER_UNGHOST")
itemFrame:RegisterEvent("MERCHANT_CLOSED")
itemFrame:RegisterEvent("UPDATE_INVENTORY_ALERTS")
itemFrame:SetScript("OnEvent", function()
if event == "PLAYER_ENTERING_WORLD" then
itemCheck.gear, itemCheck.counts = GearState()
-- The game can build your model before it has the items your morphs
-- show (a ported piece needs its template from the server), which
-- leaves you invisible, white in previews: then rebuilt once they're
-- all in (or after LOGIN_WAIT seconds), see below.
itemCheck.loginWait = not MorphedItemsLoaded() and 0 or nil
return
end
if event == "PLAYER_ALIVE" or event == "PLAYER_UNGHOST" then
-- Back to life (a spirit healer, a res, back at your body): rebuilt
-- now and once more when the game has built your living model.
GearCheck(true)
this.again = RES_AGAIN
return
end
if event == "UNIT_INVENTORY_CHANGED" and arg1 ~= "player" then
return
end
GearCheck()
end)
itemFrame:SetScript("OnUpdate", function()
-- Durability changes have no event: read them once a second.
this.poll = (this.poll or 0) + arg1
if this.poll >= GEAR_POLL then
this.poll = 0
if sessionReady and itemCheck.on and next(db.items) then
GearCheck()
end
end
if this.again then
this.again = this.again - arg1
if this.again <= 0 then
this.again = nil
GearCheck(true)
end
end
if itemCheck.loginWait then
itemCheck.loginWait = itemCheck.loginWait + arg1
if itemCheck.loginWait >= 1.5 and sessionReady and (MorphedItemsLoaded() or itemCheck.loginWait >= LOGIN_WAIT) then
+2 -2
View File
@@ -1,8 +1,8 @@
## Interface: 11200
## Title: DMorph |cff33ff99(OctoWoW)|r
## Notes: Morph window for OctoWoW: every creature model in the client (16,000+, with 3D previews, bosses and mounts), every race, 12,000+ items and 352 item sets. Skins for your mount, favourites, and DMorph users see each other's morphs. Weapon glows, real skin, face and hair, size, weather and time of day with the bundled DmorphHelper.dll. Optional ported packs add later-expansion models, armour and glows. Type /dmorph. Needs VanillaHelpers v1.1.0+ (OctoLauncher's vanillaHelpers mod); previews need ClassicAPI.
## Notes: Morph window for OctoWoW: 16,000+ creatures (every model in the client, with 3D previews, bosses and 950 mounts), every race, 13,000+ items and 351 item sets. Skins for your mount, favourites, and DMorph users see each other's morphs. Weapon glows, real skin, face and hair, size, weather and time of day with the bundled DmorphHelper.dll. Optional ported packs add later-expansion models, armour and glows. Type /dmorph. Needs VanillaHelpers v1.1.0+ (OctoLauncher's vanillaHelpers mod); previews need ClassicAPI.
## Author: bdot89
## Version: 2.21.9
## Version: 2.23.0
## X-Website: https://github.com/bdot89/DmorphOcto
## OptionalDeps: DMorph_Ported
## SavedVariables: DmorphOctoAccount
+29 -19
View File
@@ -4,7 +4,7 @@
### Become anything. Ride anything. Wear anything. ✨
**DMorph** is a free morph addon for WoW 1.12 (OctoWoW), **version 2.21.9**. Turn into a dragon 🐉, ride a mechanical chicken 🐔, swap your race 🧝, light your blade on fire 🔥, make it snow in Orgrimmar ❄️, and dress up in any armour set in the game 🛡️, all from one slick purple window.
**DMorph** is a free morph addon for WoW 1.12 (OctoWoW), **version 2.23.0**. Turn into a dragon 🐉, ride a mechanical chicken 🐔, swap your race 🧝, light your blade on fire 🔥, make it snow in Orgrimmar ❄️, and dress up in any armour set in the game 🛡️, all from one slick purple window.
> 🔒 **100% client-side and safe:** morphs only change what *you* and other DMorph users see. Everyone else, and the server, sees your real character.
@@ -13,14 +13,23 @@
Unzip, drop the **DmorphOcto** folder into your AddOns, done. Full steps below 👇 · 🌐 [Project page](https://bdot89.github.io/DmorphOcto/) · 📜 [All versions](https://github.com/bdot89/DmorphOcto/releases)
## 🚀 Want MORE? The Ported Pack
**8,157** creatures · **2,193** mounts · **48,889** weapons & armour · **915** sets · **33** glows, from **The Burning Crusade to Mists of Pandaria**, right inside DMorph. Free and optional, and friends with the pack see your ported looks too 👯
### 💬 [**DM benito9295 on Discord to get the Ported Pack**](https://discord.com/users/637439763040960564)
Send **benito9295** a message on Discord for the download links and help. How to install it: [Ported Pack](#-ported-pack-optional) below 👇
## 🌟 What you get
| | |
|---|---|
| 🐲 **16,000+ creature models** | Every model in the game, with turning 3D previews, search, and filters for bosses 👑, rares 💎 and mounts |
| 🐎 **Mount skins** | Any model as the look of your mount, from Ashes of Al'ar 🔥🦅 to a giant crab. Mount and dismount with your own keys |
| 🐲 **16,000+ creatures** | 13,000+ different models, every one in the game, with turning 3D previews, search, and filters for bosses 👑, rares 💎 and mounts |
| 🐎 **950 mounts** | Any of 950 mount models (3,143 with the pack), or any other model, as the look of your mount, from Ashes of Al'ar 🔥🦅 to a giant crab. Mount and dismount with your own keys |
| 🧝 **Every race and gender** | With real skin colours, faces, hair styles, hair colours and beards. You keep your own faction, languages, flight paths and reputation |
| 🗡️ **12,000+ items & 352 sets** | Every weapon and armour piece, and whole sets in one click. Hover to try it on first |
| 🗡️ **13,000+ items & 351 sets** | Every weapon and armour piece, and whole sets in one click. Hover to try it on first |
| ✨ **Weapon glows** | Crusader, Fiery, Icy and every other enchant glow in the game, on any weapon |
| 👙 **Slutmog** | Every revealing piece in one list, plus **Birthday suit** 🎂 and **Invisible** slots |
| ⛈️ **Weather & time of day** | Rain, snow or a sandstorm 🌪️, dawn 🌅, noon ☀️, dusk 🌇 or midnight 🌙, in every zone |
@@ -39,12 +48,12 @@ One window, ten tabs, and your character front and centre: the dressing room on
### 🐲 Models: become anything
![Models tab](docs/models.jpg)
Every creature model in the game, 16,000+ of them, plus 8,000+ more from later expansions with a ported pack. Search by name, sort A-Z or by ID, filter for bosses, rares or mounts, and watch each one turn in the preview before you commit. Grow or shrink yourself from 25% to 300% with the size slider. Here: Supremus, at 125%. 😈
16,000+ creatures to become (13,000+ different models, every one in the game), plus 8,157 more from later expansions with a ported pack. Search by name, sort A-Z or by ID, filter for bosses, rares or mounts, and watch each one turn in the preview before you commit. Grow or shrink yourself from 25% to 300% with the size slider. Here: Supremus, at 125%. 😈
### 🐎 Mounts: ride anything
![Mounts tab](docs/mounts.jpg)
Pick any model as the skin for all your mounts, or for just one of them. It goes on the moment you mount and comes off when you get down, and you still use your own mount keys. Over 3,000 mount models with the pack, from Ashes of Al'ar to the Venomous Gladiator's Goredrake turning in the preview. 🐉
Pick any model as the skin for all your mounts, or for just one of them. It goes on the moment you mount and comes off when you get down, and you still use your own mount keys. 950 mount models to choose from, and 3,143 with the pack (2,193 more), from Ashes of Al'ar to the Venomous Gladiator's Goredrake turning in the preview. 🐉
### 🧝 Races: any race, still you
![Races tab](docs/races.jpg)
@@ -59,7 +68,7 @@ Every weapon glow in the game for main hand, off hand and ranged. With the pack,
### 🗡️ Items: every weapon and armour piece
![Items tab](docs/items.jpg)
12,000+ weapons and armour pieces, and tens of thousands more with the pack. Filter by slot, type, quality and source, hover to try it on, click to wear it. **Invisible** 👻 hides a slot completely. Here: the Scythe of Elune, on a dwarf.
13,000+ weapons and armour pieces, and 48,889 more with the pack. Filter by slot, type, quality and source, hover to try it on, click to wear it. **Invisible** 👻 hides a slot completely. Here: the Scythe of Elune, on a dwarf.
### 👙 Slutmog: show some skin
![Slutmog tab](docs/slutmog.jpg)
@@ -69,7 +78,7 @@ Every revealing piece in one list: chests, shirts, legs and feet, measured from
### 🛡️ Sets: a whole outfit in one click
![Sets tab](docs/sets.jpg)
352 sets from 1.12, and 1,200+ with the pack. One click wears every piece, and the slots a set doesn't cover go bare, so your own gear never peeks through. Hover a set to see every piece on your character first.
351 sets, and 1,266 with the pack. One click wears every piece, and the slots a set doesn't cover go bare, so your own gear never peeks through. Hover a set to see every piece on your character first.
### 👗 Wardrobe: save your looks
![Wardrobe tab](docs/wardrobe.jpg)
@@ -215,28 +224,29 @@ Item slots: 1 head, 3 shoulder, 4 shirt, 5 chest, 6 waist, 7 legs, 8 feet, 9 wri
- During a race morph your faction, languages, skills, flight paths, spells and reputation stay those of your own character (with DmorphHelper v16): NPCs of your faction stay friendly and every flight path you know shows, even as a race of the other faction. Your model, skin and hair stay the other race's.
- With a race portrait you keep your own face and hair. If the other race doesn't have one of your values (say a Tauren hair style on a Gnome), the closest one that race has is used instead, so nothing shows up green.
- Mount skins go on when you mount and come off when you dismount. Flight master birds keep their own look.
- Glows and picked faces are only on your own screen for now.
- Picked faces are only on your own screen for now. Weapon glows show to other DMorph users with 2.23 or newer (glows from the Ported Pack only to friends who have it).
- Shapeshifting shows your morph instead of the form. Reset your model first if you want the form.
- Models, glows and races from The Burning Crusade onwards aren't in the 1.12 game files. A ported pack (below) adds many models, items and glows; later races can't be added.
- A ported item borrows a normal item while it's on you. The first time you wear one after logging in, the game may still be loading that item: click it again a second later.
## 🚀 Ported packs (optional)
## 🚀 Ported Pack (optional)
Want a LOT more models? DMorph from this page has no later-expansion models, and doesn't need them. A ported pack adds them: extra patch files with 6,399 creature looks, 949 mounts, 12,781 weapons, 36,014 armour looks, 915 armour sets and 33 weapon glows converted from a newer WoW install, plus a list for DMorph (Data\Ported.lua). They show in DMorph's lists under "Ported (later expansions)". These are Blizzard's files, so packs are never on GitHub: they're passed between friends privately.
Want a LOT more models? DMorph has no later-expansion models, and doesn't need them. The Ported Pack adds them: extra patch files with **8,157 creature looks** (2,193 of them mounts), **12,798 weapons and shields**, **36,091 armour looks**, **915 armour sets** and **33 weapon glows**, converted from a newer WoW install, plus a list for DMorph (the DMorph_Ported addon). They show in DMorph's lists under **Ported (later expansions)**. These are Blizzard's files, so the pack isn't on GitHub: 💬 [**DM benito9295 on Discord**](https://discord.com/users/637439763040960564) for the download links.
If someone sends you a pack:
**✅ Before you start:** DMorph 2.19.0 or newer installed (see How to install), about **50 GB of free space** (the download is about 15 GB, most of it can be deleted afterwards), and the **game closed**.
1. Update DMorph to the version the pack was made with, or newer.
2. Close the game and double-click **Install Ported.bat** in the pack folder you downloaded, the one with manifest.txt and the patch files in it (DMorph's own copy in DmorphOcto\tools\pack only goes into packs; **Pack Ported.bat** is only for the PC that made the models). It checks every file first, never replaces OctoWoW's own patches, removes ported patches from an older pack, puts the list in its own addon folder (DMorph_Ported, which DMorph updates never touch), and installs DmorphHelper. **Remove Ported.bat** takes them out again.
3. Start the game from OctoLauncher.
1. **Download BOTH parts** (Part 1 and Part 2) from the links **benito9295** sends you on Discord. Pick one site, MEGA or File Insane: the files are the same.
2. **Unzip both parts into ONE folder.** Make a folder, for example **C:\DMorphPack**. Right-click **Part 1** → **Extract All**, change the path to **C:\DMorphPack** → **Extract**. Do the same with **Part 2**, into the **same** folder.
> ⚠️ Windows adds the zip's name to the path: delete that part, so both parts land in the same folder. Don't unzip into the game folder. The folder then has **Install Ported.bat**, **manifest.txt**, **Ported.lua** and 17 patch files.
3. **Install:** double-click **Install Ported.bat** in that folder ("Windows protected your PC": **More info**, then **Run anyway**). It finds your game, checks every file (a few minutes), never replaces OctoWoW's own patches, removes patches from an older pack, puts the list in its own addon folder (DMorph_Ported, which DMorph updates never touch) and installs DmorphHelper. Wait for **"The ported models are installed"**.
4. **Play:** start the game from **OctoLauncher**, type **/dmorph** and pick **Ported (later expansions)**. 🎮
If you made the pack yourself and want to send it:
🧹 Afterwards you can delete the two zips and the patch-?.mpq files in your pack folder (the game has its own copy). Keep **Remove Ported.bat** and **install_ported.ps1**: double-click **Remove Ported.bat** to take the pack out again.
1. Close the game and double-click **Pack Ported.bat** in the DmorphOcto folder. It copies the ported patches and the list into a **DmorphPorted** folder on your Desktop, with a manifest of every file's checksum.
2. Upload that whole folder privately (Google Drive, OneDrive or MEGA) and send the link to your friends. It's several GB.
DMorph users with the same pack see each other's ported models, mounts and items; everyone else sees your normal look.
Pack again after every porting run: friends need exactly the same pack. DMorph users with the same pack see each other's ported models, mounts and items; everyone else sees your normal look.
**Made the models yourself?** Close the game and double-click **Pack Ported.bat** in the DmorphOcto folder. It copies the ported patches and the list into a **DmorphPorted** folder on your Desktop, with a manifest of every file's checksum. Share that whole folder privately; pack again after every porting run, as friends need exactly the same pack.
## 🧑‍💻 For developers
+142 -8
View File
@@ -37,6 +37,11 @@
-- It goes last in L messages, so older DMorph reads only the first three
-- parts and keeps showing the normal look; receivers use it only when their
-- pack is the same (M.GetPortedPack). Fingerprints cover all four parts.
-- Weapon glows (2.23.0) ride along like the size: a "g" token after the guid in
-- L and H messages, a slot letter (p, q, r = 16, 17, 18) and an enchant ID in
-- base 36 per glowing hand ("gp1CE", 0 = no glow), none without glows; older
-- DMorph skips the token. Receivers put a glow on only if their game has it.
-- G <glows|-> my weapon glows changed, the rest didn't
-- M <mount> my mount skin changed, the rest didn't
-- H <fingerprint> <guid|-> my look is still the one with this fingerprint
-- Q <name>[:<fingerprint>],... what do these players look like now?
@@ -73,7 +78,7 @@ local audience = {} -- name -> when they last showed they see us
local inGroup, inGuild = {}, {} -- names
local replies = {} -- way -> "L" (full look) or "H" (fingerprint)
local timers = {} -- clock times: join, ready, send, first, mount, reply, replied, query, scan, guild, next
local sent = { d = "0", m = "0", it = "-", s = "", p = "" } -- what the others were last told
local sent = { d = "0", m = "0", it = "-", s = "", p = "", g = "" } -- what the others were last told
local cache -- DmorphOctoAccount.peerCache for this realm
local guidWorks -- whether VanillaHelpers took a GUID as a unit token (nil: not tried)
local counts = { channel = 0, hidden = 0 }
@@ -501,6 +506,43 @@ local function Call(fn, token, a, b)
return pcall(fn, token, a)
end
-- A player's weapon glows, through DmorphHelper (the enchant field of each
-- weapon slot, like your own glows). Checked on every scan, not only when their
-- look changes: the server resends the field when they change weapons, which
-- takes the glow off. Their real enchant is kept to put back when the glow goes.
local function KeepGlows(token, want, done)
if type(DmorphHelper_SetItemEnchants) ~= "function" or type(DmorphHelper_GetItemEnchants) ~= "function" then
return
end
local wantGlows = want.glows or {}
done.glows, done.glowReal = done.glows or {}, done.glowReal or {}
for slot = 16, 18 do
local glow = wantGlows[slot]
if glow or done.glows[slot] then
local ok, p, t = pcall(DmorphHelper_GetItemEnchants, token, slot)
if ok and type(p) == "number" then
if glow then
if p ~= glow or t ~= 0 then
if p ~= glow then
done.glowReal[slot] = { p, t or 0 } -- theirs (again, after a resend)
end
if pcall(DmorphHelper_SetItemEnchants, token, slot, glow, 0) then
done.glows[slot] = glow
end
else
done.glows[slot] = glow
end
else
local real = done.glowReal[slot]
if not real or pcall(DmorphHelper_SetItemEnchants, token, slot, real[1], real[2]) then
done.glows[slot], done.glowReal[slot] = nil, nil
end
end
end
end
end
end
-- Puts a player's look on them. `force` sets every part again, for a player
-- the game has just built afresh (their morph is gone on our screen).
local function ApplyTo(name, token)
@@ -517,6 +559,7 @@ local function ApplyTo(name, token)
local force = not done or done.away or (ok and want.display and shown ~= want.display)
if not force and done.version == want.version then
done.scan = scanID
KeepGlows(token, want, done)
return
end
done = done or { items = {} }
@@ -559,8 +602,10 @@ local function ApplyTo(name, token)
done.scale = scale
end
end
KeepGlows(token, want, done)
done.version, done.scan, done.away = want.version, scanID, nil
if want == NONE and not done.display and not done.mount and not next(done.items) and not done.scale then
if want == NONE and not done.display and not done.mount and not next(done.items) and not done.scale
and not (done.glows and next(done.glows)) then
applied[name] = nil
else
applied[name] = done
@@ -599,6 +644,7 @@ local function SetPeer(name, look, guid, confirmed)
end
look.guid = guid or (peer and peer.guid)
look.scale = peer and peer.scale -- a full look message sets it again after
look.glows = peer and peer.glows -- (the same for weapon glows)
look.version = (peer and peer.version or 0) + 1
look.heard = confirmed and clock or -1000
look.confirmed = confirmed
@@ -743,6 +789,38 @@ local function SizeOf(token)
end
end
-- A player's weapon glows from a "g..." token: slot -> enchant ID, only the ones
-- this PC can show (M.IsKnownGlow), and a key to compare them by; nil for none.
local function GlowsOf(token)
local _, _, list = strfind(token or "", "^g([p-r0-9A-Z]+)$")
if not list then
return nil
end
local glowsOut, keyParts = {}, {}
for letter, id in string.gfind(list, "([p-r])([0-9A-Z]+)") do
local enchant = Decode(id)
if enchant and enchant < 1000000 and M.IsKnownGlow and M.IsKnownGlow(enchant) then
local slot = string.byte(letter) - 96
glowsOut[slot] = enchant
table.insert(keyParts, slot .. ":" .. enchant)
end
end
if table.getn(keyParts) == 0 then
return nil
end
glowsOut.key = table.concat(keyParts, ",")
return glowsOut
end
local function SetPeerGlows(name, glowsIn)
local peer = peers[name]
if peer and (peer.glows and peer.glows.key) ~= (glowsIn and glowsIn.key) then
peer.glows = glowsIn
peer.version = peer.version + 1
Scan()
end
end
local function SetPeerSize(name, scale)
local peer = peers[name]
if peer and peer.scale ~= scale then
@@ -754,14 +832,17 @@ end
local function ReadLook(sender, rest)
local _, _, d, m, it, guid, more = strfind(rest, "^(%S+) (%S+) (%S+) ?(%S*) ?(.*)$")
local size, ported
local size, ported, glowToken
for token in string.gfind(more or "", "%S+") do
if strfind(token, "^s%d+$") then
size = token
elseif strfind(token, "^P") then
ported = token
elseif strfind(token, "^g") then
glowToken = token
end
end
local glowsIn = GlowsOf(glowToken)
local look = MakeLook(d, m, it, ported)
if not look then
return
@@ -781,10 +862,12 @@ local function ReadLook(sender, rest)
Cache()[sender] = { look = peer.look, guid = peer.guid, seen = time() }
end
SetPeerSize(sender, scale)
SetPeerGlows(sender, glowsIn)
return
end
if SetPeer(sender, look, guid, true) then
look.scale = scale
look.glows = glowsIn
Scan()
end
end
@@ -803,7 +886,7 @@ local function ReadMount(sender, m)
end
-- "Nothing changed": confirms what we remember, else we ask for it all.
local function ReadPrint(sender, print, guid, size)
local function ReadPrint(sender, print, guid, size, glowToken)
Unask(sender)
Answered(sender)
asked[sender] = clock
@@ -811,6 +894,7 @@ local function ReadPrint(sender, print, guid, size)
if peer and peer.print == print then
peer.heard = clock
SetPeerSize(sender, SizeOf(size))
SetPeerGlows(sender, GlowsOf(glowToken))
if strfind(guid or "", "^0x%x+$") then
peer.guid = guid
end
@@ -863,9 +947,23 @@ local function Receive(sender, text, way)
elseif kind == "M" then
ReadMount(sender, rest)
elseif kind == "H" then
local _, _, print, guid, size = strfind(rest, "^(%S+) ?(%S*) ?(%S*)")
local _, _, print, guid, more = strfind(rest, "^(%S+) ?(%S*) ?(.*)$")
if print then
ReadPrint(sender, print, guid, size)
local size, glowToken
for token in string.gfind(more or "", "%S+") do
if strfind(token, "^s%d+$") then
size = token
elseif strfind(token, "^g") then
glowToken = token
end
end
ReadPrint(sender, print, guid, size, glowToken)
end
elseif kind == "G" then
-- Only the weapon glows changed ("-": none any more).
local peer = peers[sender]
if peer and peer.confirmed then
SetPeerGlows(sender, GlowsOf(rest))
end
elseif kind == "S" then
-- Only the size changed.
@@ -890,8 +988,28 @@ local function OwnSize()
return "s" .. pct
end
-- Your weapon glows as a message token: "gp1CE...", or "" with none picked.
local function OwnGlows()
if not (Sharing() and M.GetSharedGlows) then
return ""
end
local picked, parts = M.GetSharedGlows(), {}
for slot = 16, 18 do
if picked[slot] then
table.insert(parts, string.char(96 + slot) .. Encode(picked[slot]))
end
end
if table.getn(parts) == 0 then
return ""
end
return "g" .. table.concat(parts)
end
local function OnChange()
local d, m, it = OwnParts()
if OwnGlows() ~= sent.g then
timers.glow = timers.glow or clock + SETTLE
end
-- Mounting and dismounting go out at once; other changes wait until
-- they stand still a moment.
if m ~= sent.m then
@@ -914,10 +1032,16 @@ local function OnChange()
end
end
-- The size and glow tokens after the guid (size first: DMorph before 2.23 reads
-- the token after an H message's guid as the size, and skips one it can't read).
local function WithSize(text)
local size = OwnSize()
if size ~= "" then
return text .. " " .. size
text = text .. " " .. size
end
local glow = OwnGlows()
if glow ~= "" then
text = text .. " " .. glow
end
return text
end
@@ -936,7 +1060,8 @@ local function SendLook(ways)
sent.d, sent.m, sent.it = OwnParts()
sent.s = OwnSize()
sent.p = OwnPorted()
timers.send, timers.first, timers.mount, timers.size = nil, nil, nil, nil
sent.g = OwnGlows()
timers.send, timers.first, timers.mount, timers.size, timers.glow = nil, nil, nil, nil, nil
local text = LookText()
for way in pairs(ways) do
Send(text, way)
@@ -972,6 +1097,15 @@ local function SendNext()
Send("S " .. (size == "" and "100" or strsub(size, 2)), way)
end
end
elseif timers.glow and clock >= timers.glow then
timers.glow = nil
local glow = OwnGlows()
if glow ~= sent.g then
sent.g = glow
for way in pairs(ChangeWays()) do
Send("G " .. (glow == "" and "-" or glow), way)
end
end
elseif timers.reply and clock >= timers.reply then
timers.reply, timers.replied = nil, clock
local look = OwnFull()
+62 -1
View File
@@ -2734,7 +2734,7 @@ local function BuildGlowsPage(page)
Button(page, "My own glow", 110, 102, -346, function()
Morph(M.SetGlow, glowSlot, nil)
end, "DmorphOctoGlowOwn")
Label(page, "Only you see it, like every morph.", "GameFontDisableSmall", 222, -351)
Label(page, "DMorph users (2.23+) see it too.", "GameFontDisableSmall", 222, -351)
end
-- Items tab -------------------------------------------------------------------------
@@ -3417,6 +3417,67 @@ StaticPopupDialogs["DMORPHOCTO_DELETE_OUTFIT"] = {
hideOnEscape = 1,
}
-- Setup reminder (user, 21 Oct: "if someone has an outdated version or hasn't
-- run the DmorphHelper installer, a pop-up when logging in or reloading"): once
-- per login or /reload, a few seconds in, when VanillaHelpers isn't running or
-- DmorphHelper is missing or older than this DMorph's. "Don't remind me" holds
-- until DMorph comes with a newer DmorphHelper.
local SETUP_NAG_DELAY = 5
function P.SetupProblem()
if not M.HasMorphAPI() then
return "DMorph can't morph anything: VanillaHelpers isn't running.\n\n" .. M.MissingAPI()
end
local running, wanted = M.GetHelperVersion()
if not running then
return "DmorphHelper isn't running, so weapon glows, size, your real skin, face and hair, weather and "
.. "keeping your own faction during race morphs don't work.\n\nClose the game, double-click "
.. "\"Install DmorphHelper.bat\" in Interface\\AddOns\\DmorphOcto, then start the game from OctoLauncher."
end
if running < wanted then
return "Your DmorphHelper is out of date: v" .. running .. " is running, this DMorph needs v" .. wanted
.. ".\n\nClose the game, double-click \"Install DmorphHelper.bat\" in Interface\\AddOns\\DmorphOcto, "
.. "then start the game from OctoLauncher."
end
end
StaticPopupDialogs["DMORPHOCTO_SETUP"] = {
text = "DMorph: %s",
button1 = "OK",
button2 = "Don't remind me",
-- (No hideOnEscape: Escape would count as "Don't remind me".)
OnCancel = function()
local _, wanted = M.GetHelperVersion()
DmorphOctoAccount.setupNagOff = wanted
end,
timeout = 0,
whileDead = 1,
}
local setupNag = CreateFrame("Frame")
setupNag:RegisterEvent("PLAYER_ENTERING_WORLD")
setupNag:SetScript("OnEvent", function()
this:UnregisterEvent("PLAYER_ENTERING_WORLD") -- once per login or /reload
this.wait = SETUP_NAG_DELAY
end)
setupNag:SetScript("OnUpdate", function()
if not this.wait then
return
end
this.wait = this.wait - arg1
if this.wait > 0 then
return
end
this.wait = nil
local _, wanted = M.GetHelperVersion()
if DmorphOctoAccount and DmorphOctoAccount.setupNagOff == wanted and M.HasMorphAPI() then
return
end
local problem = P.SetupProblem()
if problem then
StaticPopup_Show("DMORPHOCTO_SETUP", problem)
end
end)
-- Weather tab ---------------------------------------------------------------------
-- A button per weather (M.WEATHERS): Clear skies on its own row, then light,
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 995 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

+150 -90
View File
@@ -7,121 +7,181 @@
<meta name="description" content="Free morph addon for WoW 1.12 (OctoWoW): become any creature, ride any mount, wear any item.">
<!-- What Discord (and other sites) show when the link is posted. Discord cuts the
description at about 350 characters: keep it under that, the pack line last.
Change ?v= on the image after a new banner, so Discord fetches it again. -->
Change ?v= on the image after a new banner, so Discord fetches it again.
This page follows README.md section by section, with the same words: change both together. -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="Free addon for WoW 1.12 · OctoWoW">
<meta property="og:title" content="🦄 DMorph v2.21: become any creature, ride any mount, wear any item ✨">
<meta property="og:description" content="🐲 16,000+ creatures to become, 3D previews&#10;🐎 Any mount look on your own mount&#10;🧝 Real skin, face &amp; hair for every race&#10;🗡️ 12,000+ items, 352 sets, weapon glows ✨&#10;⛈️ Weather, time of day &amp; your size&#10;👯 Friends with DMorph see your morphs&#10;🚀 Want MORE? Optional pack: 6,399 creatures, 949 mounts, 36,000+ armour looks">
<meta property="og:description" content="🐲 16,000+ creatures to become, 3D previews&#10;🐎 950 mounts, any look on your own mount&#10;🧝 Real skin, face &amp; hair for every race&#10;🗡️ 13,000+ items, 351 sets, weapon glows ✨&#10;⛈️ Weather, time of day &amp; your size&#10;👯 Friends with DMorph see your morphs&#10;🚀 Want MORE? Optional pack: 8,157 creatures, 2,193 mounts, 36,091 armour">
<meta property="og:url" content="https://bdot89.github.io/DmorphOcto/">
<meta property="og:image" content="https://bdot89.github.io/DmorphOcto/banner.png?v=2210">
<meta property="og:image" content="https://bdot89.github.io/DmorphOcto/banner.png?v=2221">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1280">
<meta property="og:image:height" content="640">
<meta property="og:image:alt" content="DMorph for OctoWoW: features, the optional ported pack, a ported mount, a weapon glow and ported armour">
<meta property="og:image:alt" content="DMorph for OctoWoW: three friends morphed in glowing armour and a winged mount, with the features and numbers">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://bdot89.github.io/DmorphOcto/banner.png?v=2210">
<meta name="theme-color" content="#b46bff">
<meta name="twitter:image" content="https://bdot89.github.io/DmorphOcto/banner.png?v=2221">
<meta name="theme-color" content="#b44cff">
<style>
:root{--bg:#0d0c10;--panel:#16131b;--gold:#b8923a;--line:#8a6d2b;--text:#eee;--dim:#a39d8f;--green:#33ff99;--purple:#b46bff;--yellow:#ffd23f}
:root{--bg:#0c0a11;--panel:#16111f;--panel2:#1d1529;--text:#f1ecff;--dim:#b3a7cb;
--fel:#72f92b;--fel2:#9ffe3c;--pur:#b44cff;--pur2:#cb70ff;--pur3:#d192fd;--teal:#43fadd}
*{box-sizing:border-box;margin:0;padding:0}
body{background:radial-gradient(ellipse 900px 500px at 80% 10%,rgba(150,70,230,.18),transparent 70%),radial-gradient(ellipse 700px 500px at 0% 0%,rgba(40,200,140,.12),transparent 70%),var(--bg);color:var(--text);font:17px/1.5 "Segoe UI",system-ui,-apple-system,sans-serif}
main{max-width:1040px;margin:0 auto;padding:28px 16px 48px}
.banner{display:block;width:100%;height:auto;border:2px solid var(--gold);border-radius:4px;box-shadow:0 14px 40px rgba(0,0,0,.7)}
h1{font-size:34px;margin:26px 0 4px;line-height:1.2}
h1 .d{color:var(--green)}h1 .m{color:var(--purple)}
.tag{color:var(--dim);font-size:18px}
.buttons{display:flex;flex-wrap:wrap;gap:12px;margin:22px 0 8px}
.btn{display:inline-block;padding:11px 20px;border-radius:4px;font-weight:600;text-decoration:none;border:1px solid var(--line)}
.btn.main{background:linear-gradient(#a8202a,#6e1016);color:#ffd23f}
.btn.alt{background:var(--panel);color:var(--text)}
h2{font-size:22px;margin:30px 0 12px;color:var(--yellow)}
ul.features{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:10px 24px}
ul.features li{background:var(--panel);border:1px solid #2a2110;border-radius:4px;padding:10px 14px}
ul.features b{color:#fff}
.gallery{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px}
.gallery figure{background:var(--panel);border:1px solid #2a2110;border-radius:4px;overflow:hidden}
.gallery img{display:block;width:100%;height:auto}
.gallery figcaption{padding:8px 12px;color:var(--dim);font-size:15px}
.wide{margin-top:14px}
.wide img{display:block;width:100%;height:auto;border:1px solid #2a2110;border-radius:4px}
ol{padding-left:22px}ol li{margin:6px 0}
code{background:#221d29;padding:1px 6px;border-radius:3px;font-size:15px}
a{color:var(--green)}
footer{margin-top:36px;color:var(--dim);font-size:14px;border-top:1px solid #2a2110;padding-top:14px}
body{background:
radial-gradient(ellipse 900px 520px at 85% 0%,rgba(180,76,255,.22),transparent 70%),
radial-gradient(ellipse 700px 500px at 0% 0%,rgba(114,249,43,.12),transparent 70%),var(--bg);
color:var(--text);font:17px/1.55 "Segoe UI",system-ui,-apple-system,sans-serif}
main{max-width:1060px;margin:0 auto;padding:28px 16px 48px}
a{color:var(--fel2)}
.banner{display:block;width:100%;height:auto;border-radius:10px;border:2px solid transparent;
background:linear-gradient(var(--bg),var(--bg)) padding-box,linear-gradient(90deg,var(--fel2),var(--teal),var(--pur2),var(--pur)) border-box;
box-shadow:-12px 0 30px -10px rgba(114,249,43,.5),12px 0 30px -10px rgba(180,76,255,.6),0 18px 40px rgba(0,0,0,.6)}
h1{font:900 40px/1.15 "Segoe UI Black","Segoe UI",sans-serif;margin:26px 0 2px;letter-spacing:-.5px}
.d{color:var(--fel2);text-shadow:0 0 18px rgba(114,249,43,.6)}.m{color:var(--pur2);text-shadow:0 0 18px rgba(180,76,255,.7)}
.slogan{font-size:22px;font-weight:700;color:#fff}
.lead{margin-top:8px;color:#e6defa}
.safe{margin-top:12px;padding:10px 14px;border-left:3px solid var(--teal);background:rgba(67,250,221,.06);border-radius:0 6px 6px 0;color:#dff}
.buttons{display:flex;flex-wrap:wrap;gap:12px;margin:22px 0 6px}
.btn{display:inline-block;padding:11px 20px;border-radius:10px;font-weight:700;text-decoration:none;color:#fff;border:2px solid transparent;
background:linear-gradient(var(--panel2),var(--panel2)) padding-box,linear-gradient(90deg,var(--fel2),var(--teal),var(--pur2),var(--pur)) border-box}
.btn.main{background:linear-gradient(90deg,#4fc21c,#2f9e8a 50%,#8f34d6) padding-box,linear-gradient(90deg,var(--fel2),var(--teal),var(--pur2),var(--pur)) border-box;
box-shadow:-8px 0 20px -6px rgba(114,249,43,.6),8px 0 20px -6px rgba(180,76,255,.7)}
.btn.discord{background:linear-gradient(#5865f2,#4752c4) padding-box,linear-gradient(90deg,#8ea1ff,#5865f2) border-box}
.under{font-size:15px;color:var(--dim)}
h2{font:800 26px/1.2 "Segoe UI",sans-serif;margin:38px 0 14px;color:#fff}
h2 .hl{background:linear-gradient(90deg,var(--fel2),var(--teal),var(--pur3));-webkit-background-clip:text;background-clip:text;color:transparent}
h3{font-size:19px;margin:0 0 6px;color:#fff}
.pack{margin-top:30px;padding:18px 22px;border-radius:12px;border:2px solid transparent;
background:linear-gradient(135deg,rgba(60,20,100,.92),rgba(22,14,36,.95) 60%,rgba(30,70,20,.85)) padding-box,
linear-gradient(90deg,var(--fel2),var(--teal),var(--pur2),var(--pur)) border-box;
box-shadow:-12px 0 28px -10px rgba(114,249,43,.55),12px 0 28px -10px rgba(180,76,255,.7)}
.pack h2{margin:0 0 8px}
.nums{display:flex;flex-wrap:wrap;gap:8px 22px;margin:6px 0 10px}
.nums div b{display:block;font:900 30px/1 "Segoe UI Black","Segoe UI",sans-serif;color:var(--fel2);text-shadow:0 0 12px rgba(114,249,43,.5)}
.nums div span{font-size:15px;color:#e6d8ff}
b.g{color:var(--fel2)}
.features{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:10px 18px}
.features li{background:var(--panel);border:1px solid #2b1f3d;border-radius:8px;padding:11px 14px}
.features li>b{display:block;color:#fff;font-size:17px}
.features li span{color:var(--dim);font-size:15.5px}
.intro{color:#e6defa;margin-bottom:16px}
.tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(470px,1fr));gap:18px}
.tab{background:var(--panel);border:1px solid #2b1f3d;border-radius:10px;overflow:hidden}
.tab img{display:block;width:100%;height:auto;border-bottom:1px solid #2b1f3d}
.tab div{padding:12px 15px 14px}
.tab p{color:var(--dim);font-size:15.5px}
.gallery{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px;margin-top:14px}
.gallery img{display:block;width:100%;height:auto;border-radius:8px;border:1px solid #2b1f3d}
.wide img{display:block;width:100%;height:auto;border-radius:8px;border:1px solid #2b1f3d;margin-top:14px}
.steps{counter-reset:s;list-style:none;display:grid;gap:12px}
.steps>li{background:var(--panel);border:1px solid #2b1f3d;border-radius:10px;padding:14px 16px 14px 62px;position:relative}
.steps>li:before{counter-increment:s;content:counter(s);position:absolute;left:16px;top:13px;width:32px;height:32px;border-radius:8px;
font:900 18px/32px "Segoe UI Black","Segoe UI",sans-serif;text-align:center;color:#0c0a11;background:linear-gradient(135deg,var(--fel2),var(--teal) 55%,var(--pur2))}
.steps p,.steps ul{color:#e2d9f5;font-size:16px}
.steps ul{margin:6px 0 0 18px}
.warn{margin-top:8px;padding:8px 12px;border-left:3px solid #ffcc33;background:rgba(255,204,51,.07);border-radius:0 6px 6px 0;color:#ffe9a8;font-size:15.5px}
code{background:#251b35;padding:1px 6px;border-radius:4px;font-size:15px;color:#fff}
.note{margin-top:12px;color:var(--dim);font-size:15.5px}
footer{margin-top:40px;color:var(--dim);font-size:14px;border-top:1px solid #2b1f3d;padding-top:14px}
</style>
</head>
<body>
<main>
<img class="banner" src="banner.png" alt="DMorph for OctoWoW: become any creature, ride any mount, wear any item">
<h1><span class="d">D</span><span class="m">Morph</span> for OctoWoW</h1>
<p class="tag">✨ The free morph addon for WoW 1.12: become any creature 🐉, ride any mount 🐎, wear any item 🗡️, swap your race 🧝, light up your weapons 🔥 and change the weather ⛈️. Only you and other DMorph users see it, so it's 100% client-side and safe 🔒.</p>
<img class="banner" src="banner.png?v=2221" alt="DMorph for OctoWoW: three friends morphed in glowing armour and a winged mount, with the features and numbers">
<h1>🦄 <span class="d">D</span><span class="m">Morph</span> for OctoWoW</h1>
<p class="slogan">Become anything. Ride anything. Wear anything. ✨</p>
<p class="lead"><b>DMorph</b> is a free morph addon for WoW 1.12 (OctoWoW), <b>version 2.23.0</b>. Turn into a dragon 🐉, ride a mechanical chicken 🐔, swap your race 🧝, light your blade on fire 🔥, make it snow in Orgrimmar ❄️, and dress up in any armour set in the game 🛡️, all from one slick purple window.</p>
<p class="safe">🔒 <b>100% client-side and safe:</b> morphs only change what <i>you</i> and other DMorph users see. Everyone else, and the server, sees your real character.</p>
<div class="buttons">
<a class="btn main" href="https://github.com/bdot89/DmorphOcto/releases/latest/download/DmorphOcto.zip">⬇️ Download DMorph (ZIP)</a>
<a class="btn alt" href="https://github.com/bdot89/DmorphOcto">📖 Full guide on GitHub</a>
<a class="btn alt" href="https://github.com/bdot89/DmorphOcto/releases">📜 What's new</a>
<a class="btn discord" href="https://discord.com/users/637439763040960564">💬 DM benito9295 on Discord</a>
<a class="btn" href="https://github.com/bdot89/DmorphOcto#readme">📖 Full guide on GitHub</a>
<a class="btn" href="https://github.com/bdot89/DmorphOcto/releases">📜 What's new</a>
</div>
<p class="under">Unzip, drop the <b>DmorphOcto</b> folder into your AddOns, done. Full steps below 👇</p>
<h2>🌟 Features</h2>
<section class="pack">
<h2>🚀 Want MORE? <span class="hl">The Ported Pack</span></h2>
<div class="nums">
<div><b>8,157</b><span>creatures</span></div><div><b>2,193</b><span>mounts</span></div><div><b>48,889</b><span>weapons &amp; armour</span></div>
<div><b>915</b><span>sets</span></div><div><b>33</b><span>glows</span></div>
</div>
<p>From <b>The Burning Crusade to Mists of Pandaria</b>, right inside DMorph. Free and optional, and friends with the pack see your ported looks too 👯</p>
<div class="buttons"><a class="btn discord" href="https://discord.com/users/637439763040960564">💬 DM benito9295 on Discord to get the Ported Pack</a></div>
<p class="under">Send <b>benito9295</b> a message on Discord for the download links and help. How to install it: <a href="#pack">Ported Pack</a> below 👇</p>
</section>
<h2>🌟 <span class="hl">What you get</span></h2>
<ul class="features">
<li>🐲 <b>16,000+ creature models</b> with 3D previews, search, A-Z or ID sort</li>
<li>👑 <b>560+ bosses, every mount and rares</b> as filters</li>
<li>🐎 <b>Mount skins:</b> any model on your mount, mount and dismount with your own keys</li>
<li>🧝 <b>Real skin, face and hair</b> for every race, one row at a time</li>
<li>✨ <b>Weapon enchant glows:</b> Crusader, Fiery, Icy and every glow in the game</li>
<li>⛈️ <b>Weather:</b> clear skies, rain, snow or a sandstorm, light to heavy, on your screen in every zone, and any <b>time of day</b> from dawn to midnight</li>
<li>🗡️ <b>12,000+ items</b> with type, quality and source filters</li>
<li>🛡️ <b>352 item sets</b> in one click, the last set's pieces come off</li>
<li>📏 <b>Your size:</b> 25% to 300%, seen by other DMorph users too</li>
<li>⭐ <b>Favourites and a wardrobe</b> of saved outfits for all your characters</li>
<li>👯 <b>See each other's morphs:</b> DMorph users see each other's looks</li>
<li>🏳️ <b>Race morphs keep your faction:</b> languages, every flight path and friendly NPCs stay yours, even as the other faction</li>
<li>🚀 <b>Optional ported packs:</b> later-expansion models, mounts, armour, sets and 33 glows from TBC to Mists of Pandaria, shared privately between friends</li>
<li>👀 <b>A preview box on every list:</b> the whole model, or you wearing the item or set; zoom, turn, move, and <b>Previous / Next</b> to try the list one by one</li>
<li>👙 <b>Slutmog and Birthday suit:</b> every revealing piece in one list, OctoWoW's Unseen Fashion, and a bare-skin start; any slot can be <b>Invisible</b></li>
<li>🔍 <b>Zoom and turn</b> your character in the dressing room</li>
<li>⌨️ <b>DMorph's chat commands:</b> <code>.morph</code> <code>.item</code> <code>.mount</code> <code>.glow</code></li>
<li>✅ <b>Checked against your game files:</b> nothing in the lists turns invisible</li>
<li><b>🐲 16,000+ creatures</b><span>13,000+ different models, every one in the game, with turning 3D previews, search, and filters for bosses 👑, rares 💎 and mounts</span></li>
<li><b>🐎 950 mounts</b><span>Any of 950 mount models (3,143 with the pack), or any other model, as the look of your mount, from Ashes of Al'ar 🔥🦅 to a giant crab. Mount and dismount with your own keys</span></li>
<li><b>🧝 Every race and gender</b><span>With real skin colours, faces, hair styles, hair colours and beards. You keep your own faction, languages, flight paths and reputation</span></li>
<li><b>🗡️ 13,000+ items &amp; 351 sets</b><span>Every weapon and armour piece, and whole sets in one click. Hover to try it on first</span></li>
<li><b>✨ Weapon glows</b><span>Crusader, Fiery, Icy and every other enchant glow in the game, on any weapon</span></li>
<li><b>👙 Slutmog</b><span>Every revealing piece in one list, plus <b class="g">Birthday suit</b> 🎂 and <b class="g">Invisible</b> slots</span></li>
<li><b>⛈️ Weather &amp; time of day</b><span>Rain, snow or a sandstorm 🌪️, dawn 🌅, noon ☀️, dusk 🌇 or midnight 🌙, in every zone</span></li>
<li><b>📏 Your size</b><span>From a tiny 25% 🐭 to a towering 300% 🦖</span></li>
<li><b>👗 Wardrobe &amp; favourites</b><span>Save whole outfits ⭐ and star your best finds, shared by all your characters</span></li>
<li><b>👯 Share with friends</b><span>Other DMorph users see your model, items, mount skin and size, and you see theirs</span></li>
<li><b>🚀 Optional ported packs</b><span>Thousands more creatures, mounts, armour and glows from The Burning Crusade to Mists of Pandaria</span></li>
</ul>
<p class="note">Your look stays through /reload, loading screens and logging in. 💾</p>
<h2>📸 Screenshots</h2>
<div class="gallery">
<figure><img src="models.jpg" alt="Models tab" loading="lazy"><figcaption><b>Become anything.</b> 16,000+ creature models, 8,000+ more with the pack, each turning in the preview before you click. Grow or shrink from 25% to 300%.</figcaption></figure>
<figure><img src="mounts.jpg" alt="Mounts tab" loading="lazy"><figcaption><b>Ride anything.</b> Any model as your mount skin: on when you mount, off when you get down. 3,000+ mount models with the pack.</figcaption></figure>
<figure><img src="races.jpg" alt="Races tab" loading="lazy"><figcaption><b>Any race, still you.</b> Your own face and hair on every race, real skin colours and styles, and your faction, languages and flight paths kept.</figcaption></figure>
<figure><img src="glows.jpg" alt="Glows tab" loading="lazy"><figcaption><b>Every enchant glow</b> on any weapon, plus 33 from TBC to Mists with the pack: Sunfire, Mongoose, Crackling Lightning...</figcaption></figure>
<figure><img src="items.jpg" alt="Items tab" loading="lazy"><figcaption><b>Every weapon and armour piece.</b> Filter by type, quality and source, hover to try it on, click to wear. Invisible hides a slot.</figcaption></figure>
<figure><img src="slutmog.jpg" alt="Slutmog tab" loading="lazy"><figcaption><b>Show some skin.</b> Every revealing piece, measured from how much body it covers. Birthday suit starts you from bare skin.</figcaption></figure>
<figure><img src="sets.jpg" alt="Sets tab" loading="lazy"><figcaption><b>A whole outfit in one click.</b> 1,200+ sets with the pack; uncovered slots go bare so your own gear never peeks through.</figcaption></figure>
<figure><img src="wardrobe.jpg" alt="Wardrobe tab" loading="lazy"><figcaption><b>Save your looks.</b> Model, items, glows, mount skin and size in one outfit, shared by all your characters.</figcaption></figure>
<figure><img src="favourites.jpg" alt="Favourites tab" loading="lazy"><figcaption><b>Your best finds at hand.</b> Star any model or mount skin; favourites follow you to every character.</figcaption></figure>
<figure><img src="weather.jpg" alt="Weather tab" loading="lazy"><figcaption><b>Your sky, your time.</b> Rain, snow or sandstorms from light to heavy, and any time of day, in every zone.</figcaption></figure>
</div>
<div class="wide"><img src="world.jpg" alt="Mount skin and creature morph in Orgrimmar" loading="lazy"></div>
<h2>🚀 Want a LOT more models? The ported pack</h2>
<p>An optional set of extra patch files adds looks from later expansions: <b>6,399 creature looks</b>, <b>949 mounts</b>, <b>12,781 weapons</b>, <b>36,014 armour looks</b>, <b>915 armour sets</b> and <b>33 weapon glows</b> from The Burning Crusade to Mists of Pandaria. They show up in DMorph's lists under "Ported (later expansions)", and friends with the same pack see each other's ported looks. DMorph works fully without it. The pack is Blizzard's art, so it's never on GitHub: it's shared privately, and installed with one double-click on <b>Install Ported.bat</b>.</p>
<div class="gallery">
<figure><img src="ported-gunner.jpg" alt="A ported goblin gunner mount in Orgrimmar" loading="lazy"><figcaption>949 ported mounts, from goblin gunners...</figcaption></figure>
<figure><img src="ported-mount.jpg" alt="A ported war machine mount in Orgrimmar" loading="lazy"><figcaption>...to war machines in Orgrimmar's rain</figcaption></figure>
<figure><img src="ported-glow.jpg" alt="Crackling Lightning glow on a ported sword" loading="lazy"><figcaption>Crackling Lightning, one of the 33 new glows</figcaption></figure>
<figure><img src="ported-armour.jpg" alt="Ported armour and weapon" loading="lazy"><figcaption>Ported armour and weapons</figcaption></figure>
<figure><img src="ported-glow.webp" alt="Ported winged shoulders and a glowing sword" loading="lazy"><figcaption>Ported shoulders and a glowing sword</figcaption></figure>
<figure><img src="ported-pandaria.jpg" alt="Ported armour and greatsword" loading="lazy"><figcaption>A ported set and greatsword</figcaption></figure>
<figure><img src="ported-owl.jpg" alt="A ported flying machine mount" loading="lazy"><figcaption>Machines and flying mounts</figcaption></figure>
<figure><img src="ported-jetbike.jpg" alt="A ported jet bike mount" loading="lazy"><figcaption>Every mount works with your own mount keys</figcaption></figure>
<h2>📸 <span class="hl">Screenshots</span></h2>
<p class="intro">One window, ten tabs, and your character front and centre: the dressing room on the left always shows you as you'll look in the world, and every list has its own preview box that turns, zooms and moves, so you see everything before you click it. 👀</p>
<div class="tabs">
<div class="tab"><img src="models.jpg" alt="Models tab" loading="lazy"><div><h3>🐲 Models: become anything</h3><p>16,000+ creatures to become (13,000+ different models, every one in the game), plus 8,157 more from later expansions with a ported pack. Search by name, sort A-Z or by ID, filter for bosses, rares or mounts, and watch each one turn in the preview before you commit. Grow or shrink yourself from 25% to 300% with the size slider. Here: Supremus, at 125%. 😈</p></div></div>
<div class="tab"><img src="mounts.jpg" alt="Mounts tab" loading="lazy"><div><h3>🐎 Mounts: ride anything</h3><p>Pick any model as the skin for all your mounts, or for just one of them. It goes on the moment you mount and comes off when you get down, and you still use your own mount keys. 950 mount models to choose from, and 3,143 with the pack (2,193 more), from Ashes of Al'ar to the Venomous Gladiator's Goredrake turning in the preview. 🐉</p></div></div>
<div class="tab"><img src="races.jpg" alt="Races tab" loading="lazy"><div><h3>🧝 Races: any race, still you</h3><p>Every race and gender, wearing your own face, skin and hair. The arrows step through real skin colours, faces, hair styles, hair colours and facial hair, and the dice 🎲 rolls a whole new look. Your faction, languages, flight paths and reputation stay your own, so a Horde character can be a dwarf and still talk to Orgrimmar.</p></div></div>
<div class="tab"><img src="glows.jpg" alt="Glows tab" loading="lazy"><div><h3>✨ Glows: every enchant, any weapon</h3><p>Every weapon glow in the game for main hand, off hand and ranged. With the pack, 33 more from The Burning Crusade to Mists of Pandaria: Sunfire, Mongoose, Berserking, Crackling Lightning ⚡, Jade Spirit and more. Hover one and the preview puts it on your weapon.</p></div></div>
<div class="tab"><img src="items.jpg" alt="Items tab" loading="lazy"><div><h3>🗡️ Items: every weapon and armour piece</h3><p>13,000+ weapons and armour pieces, and 48,889 more with the pack. Filter by slot, type, quality and source, hover to try it on, click to wear it. <b class="g">Invisible</b> 👻 hides a slot completely. Here: the Scythe of Elune, on a dwarf.</p></div></div>
<div class="tab"><img src="slutmog.jpg" alt="Slutmog tab" loading="lazy"><div><h3>👙 Slutmog: show some skin</h3><p>Every revealing piece in one list: chests, shirts, legs and feet, measured from how much body each one actually covers, not guessed from its name. Chainkinis, halter tops, loincloths, tropical skirts 🌺 and airy sandals, plus OctoWoW's invisible Unseen Fashion pieces. Hit <b class="g">Birthday suit</b> 🎂 and build your look up from bare skin.</p></div></div>
<div class="tab"><img src="sets.jpg" alt="Sets tab" loading="lazy"><div><h3>🛡️ Sets: a whole outfit in one click</h3><p>351 sets, and 1,266 with the pack. One click wears every piece, and the slots a set doesn't cover go bare, so your own gear never peeks through. Hover a set to see every piece on your character first.</p></div></div>
<div class="tab"><img src="wardrobe.jpg" alt="Wardrobe tab" loading="lazy"><div><h3>👗 Wardrobe: save your looks</h3><p>Save your whole look as an outfit: model, items, glows, mount skin and size. Outfits are shared by all your characters and come back in one click.</p></div></div>
<div class="tab"><img src="favourites.jpg" alt="Favourites tab" loading="lazy"><div><h3>⭐ Favourites: your best finds at hand</h3><p>Right-click any model or mount skin to star it. Your favourites follow you to every character.</p></div></div>
<div class="tab"><img src="weather.jpg" alt="Weather tab" loading="lazy"><div><h3>⛈️ Weather: your sky, your time</h3><p>Clear skies, rain 🌧️, snow ❄️ or a sandstorm 🌪️, from light to heavy, and any time of day: dawn, noon, dusk or midnight. It stays on in every zone, and only you see it.</p></div></div>
</div>
<h2>🛠️ Install in two minutes</h2>
<ol>
<li>In <b>OctoLauncher</b>, tick the <b>vanillaHelpers</b> mod.</li>
<li><a href="https://github.com/bdot89/DmorphOcto/releases/latest/download/DmorphOcto.zip">Download DmorphOcto.zip</a>, <b>Extract All</b>, and move the <b>DmorphOcto</b> folder from it into <code>OctoWoW\Interface\AddOns\</code>.</li>
<li>Close the game, open that folder and double-click <b>Install DmorphHelper.bat</b> (if Windows warns you: <i>More info</i>, then <i>Run anyway</i>). It adds the glows, real skin, face and hair, the size slider, the weather and the time of day. Do it again after each update.</li>
<li>Start the game <b>from OctoLauncher</b> and click the minimap button, or type <code>/dmorph</code>.</li>
<li>The <b>Setup</b> button at the bottom of the window is green when it all works. Red? Click it: it says what isn't running and how to fix it.</li>
<h2>🌍 <span class="hl">Out in the world</span></h2>
<p class="intro">Other DMorph users see your model, items, mount skin and size, and you see theirs. 👯</p>
<div class="wide"><img src="world.jpg" alt="In the world" loading="lazy"><img src="morphs.jpg" alt="More morphs" loading="lazy"></div>
<p class="intro" style="margin-top:16px">With a ported pack (optional, see below) 🚀:</p>
<div class="gallery">
<img src="ported-gunner.jpg" alt="A ported goblin gunner mount" loading="lazy">
<img src="ported-mount.jpg" alt="A ported war machine mount in Orgrimmar" loading="lazy">
<img src="ported-glow.jpg" alt="Crackling Lightning glow on a ported sword" loading="lazy">
<img src="ported-armour.jpg" alt="Ported armour and weapons" loading="lazy">
<img src="ported-glow.webp" alt="Ported winged shoulders and a glowing sword" loading="lazy">
<img src="ported-pandaria.jpg" alt="A ported set and greatsword" loading="lazy">
<img src="ported-owl.jpg" alt="A ported flying machine" loading="lazy">
<img src="ported-jetbike.jpg" alt="A ported jet bike" loading="lazy">
</div>
<h2>🛠️ <span class="hl">How to install</span></h2>
<p class="intro">It takes about two minutes. ⏱️</p>
<ol class="steps">
<li><h3>Turn on VanillaHelpers ✅</h3><p>Open OctoLauncher and, in its list of mods, tick <b>vanillaHelpers</b>. DMorph needs it. Without it, nothing can morph.</p></li>
<li><h3>Put DMorph in your AddOns folder 📁</h3><p><a href="https://github.com/bdot89/DmorphOcto/releases/latest/download/DmorphOcto.zip"><b>Download DmorphOcto.zip</b></a>, right-click it and choose <b>Extract All</b>, then <b>Extract</b>. Move the <b>DmorphOcto</b> folder inside it into your game's AddOns folder, so it ends up like this: <code>OctoWoW\Interface\AddOns\DmorphOcto\DmorphOcto.toc</code></p>
<p class="warn">Used GitHub's green <b>Code &gt; Download ZIP</b> button instead? Then the folder is called <b>DmorphOcto-main</b>: rename it to <b>DmorphOcto</b>.</p></li>
<li><h3>Run the installer 🪄</h3><p>For glows, real skin, face and hair, size, weather and time of day. Close the game completely, open <code>OctoWoW\Interface\AddOns\DmorphOcto</code> and double-click <b>Install DmorphHelper.bat</b>. "Windows protected your PC": click <b>More info</b>, then <b>Run anyway</b>. A black window ends with "DmorphHelper is installed". You can skip this step: everything else still works.</p></li>
<li><h3>Play! 🎮</h3><p>Start the game from <b>OctoLauncher</b> (not WoW.exe). Click the polymorph button by the minimap 🐑, or type <code>/dmorph</code>. The <b>Setup</b> button at the bottom left:</p>
<ul><li>🟢 Green "Setup OK": you're ready (it shows the DmorphHelper version, for example "Helper v16").</li><li>🟡 Yellow "Old helper": close the game and run Install DmorphHelper.bat again.</li><li>🔴 Red "Setup: fix me": click it. It tells you what isn't working and how to fix it.</li></ul></li>
</ol>
<p>Step by step, plus updating and fixes: <a href="https://github.com/bdot89/DmorphOcto#readme">the install guide</a>. Have fun, and show your friends your best morphs! 🎉</p>
<p class="note">Updating, fixes for common problems, every tab and the chat commands: <a href="https://github.com/bdot89/DmorphOcto#readme">the full guide on GitHub</a>.</p>
<footer>Morphs change only what DMorph users see; everyone else sees your real character. Made for the OctoWoW 1.12.1 client. Not affiliated with Blizzard Entertainment.</footer>
<h2 id="pack">🚀 <span class="hl">Ported Pack (optional)</span></h2>
<p class="intro">Want a LOT more models? DMorph has no later-expansion models, and doesn't need them. The Ported Pack adds them: <b>8,157 creature looks</b> (2,193 of them mounts), <b>12,798 weapons and shields</b>, <b>36,091 armour looks</b>, <b>915 armour sets</b> and <b>33 weapon glows</b>, converted from a newer WoW install. They show in DMorph's lists under <b>Ported (later expansions)</b>. These are Blizzard's files, so the pack isn't on GitHub: 💬 <a href="https://discord.com/users/637439763040960564"><b>DM benito9295 on Discord</b></a> for the download links.</p>
<p class="note" style="margin-bottom:14px">✅ <b>Before you start:</b> DMorph 2.19.0 or newer installed (see above), about <b>50 GB of free space</b> (the download is about 15 GB, most of it can be deleted afterwards), and the <b>game closed</b>.</p>
<ol class="steps">
<li><h3>Download BOTH parts</h3><p>Get <b>Part 1</b> and <b>Part 2</b> from the links <b>benito9295</b> sends you on Discord. Pick one site, MEGA or File Insane: the files are the same.</p></li>
<li><h3>Unzip both parts into ONE folder</h3><p>Make a folder, for example <code>C:\DMorphPack</code>. Right-click <b>Part 1</b> → <b>Extract All</b>, change the path to <code>C:\DMorphPack</code> → <b>Extract</b>. Do the same with <b>Part 2</b>, into the <b>same</b> folder.</p>
<p class="warn">⚠️ Windows adds the zip's name to the path: delete that part, so both parts land in the same folder. Don't unzip into the game folder. The folder then has <b>Install Ported.bat</b>, <b>manifest.txt</b>, <b>Ported.lua</b> and 17 patch files.</p></li>
<li><h3>Install</h3><p>Double-click <b>Install Ported.bat</b> in that folder ("Windows protected your PC": <b>More info</b>, then <b>Run anyway</b>). It finds your game, checks every file (a few minutes), never replaces OctoWoW's own patches, and installs DmorphHelper. Wait for <b>"The ported models are installed"</b>.</p></li>
<li><h3>Play! 🎮</h3><p>Start the game from <b>OctoLauncher</b>, type <code>/dmorph</code> and pick <b>Ported (later expansions)</b>.</p></li>
</ol>
<p class="note">🧹 Afterwards you can delete the two zips and the patch-?.mpq files in your pack folder (the game has its own copy). Keep <b>Remove Ported.bat</b> and <b>install_ported.ps1</b>: double-click <b>Remove Ported.bat</b> to take the pack out again. DMorph users with the same pack see each other's ported models, mounts and items; everyone else sees your normal look.</p>
<footer>Made with 💜 for the OctoWoW community · <a href="https://github.com/bdot89/DmorphOcto">GitHub</a> · Discord: <a href="https://discord.com/users/637439763040960564">benito9295</a><br>Morphs change only what DMorph users see; everyone else sees your real character. Made for the OctoWoW 1.12.1 client. Not affiliated with Blizzard Entertainment.</footer>
</main>
</body>
</html>
+81 -83
View File
@@ -1,98 +1,96 @@
<!doctype html>
<!-- Source of docs/banner.png (1280x640, GitHub's social preview size). Fonts come from the EPLTowers addon next to this one.
Render: msedge --headless=new --hide-scrollbars --force-device-scale-factor=1 --window-size=1280,640 --screenshot=banner.png banner.html
Screenshots: ../glows.jpg and ported-*.jpg (crops of the user's in-game shots: no chat, no other players' names, own name blanked). -->
Render: msedge --headless=new --hide-scrollbars --force-device-scale-factor=1 --window-size=1280,640 --allow-file-access-from-files --screenshot=banner.png banner.html
Picture: hero-group.jpg (the user's group shot, no UI or names). Colours are taken from it: fel green #72F92B / #9FFE3C
(the left character's glows), purple #B44CFF / #CB70FF (the mount's outline), teal #43FADD (the middle character's glow).
Numbers (19 Oct 2026, counted from Data/ and DMorph_Ported\Ported.lua): 16,674 creatures (13,383 models), 950 mount models,
13,655 items, 351 sets; pack 8,157 creature looks, 2,193 mounts, 12,798 weapons + 36,091 armour = 48,889 items, 915 sets, 33 glows. -->
<html><head><meta charset="utf-8">
<style>
@font-face{font-family:Fira;src:url(../../../EPLTowers/fonts/FiraSansCondensed-Regular.ttf);font-weight:400}
@font-face{font-family:Fira;src:url(../../../EPLTowers/fonts/FiraSansCondensed-SemiBold.ttf);font-weight:600}
:root{--fel:#72f92b;--fel2:#9ffe3c;--pur:#b44cff;--pur2:#cb70ff;--pur3:#d192fd;--teal:#43fadd}
*{box-sizing:border-box;margin:0;padding:0}
html,body{width:1280px;height:640px;overflow:hidden}
body{font-family:Fira,sans-serif;color:#eee;position:relative;
body{font-family:Fira,sans-serif;color:#f1ecff;position:relative;
background:
radial-gradient(ellipse 760px 480px at 1000px 300px, rgba(150,70,230,.26), transparent 70%),
radial-gradient(ellipse 520px 380px at 110px 30px, rgba(40,200,140,.20), transparent 70%),
radial-gradient(ellipse 620px 300px at 300px 600px, rgba(170,60,220,.26), transparent 70%),
linear-gradient(160deg,#141118 0%,#0d0c10 55%,#120f14 100%);}
.frame{position:absolute;inset:10px;border:2px solid #8a6d2b;border-radius:3px;box-shadow:inset 0 0 0 1px #2a2110, inset 0 0 60px rgba(0,0,0,.6);z-index:20;pointer-events:none}
.left{position:absolute;left:40px;top:30px;width:600px;z-index:10}
.kicker{font-size:17px;letter-spacing:4px;text-transform:uppercase;color:#4fe3a2;font-weight:600}
h1{font-size:82px;line-height:.95;font-weight:600;margin-top:2px;letter-spacing:-1px}
h1 .d{color:#33ff99;text-shadow:0 0 22px rgba(51,255,153,.35)}
h1 .m{color:#b46bff;text-shadow:0 0 24px rgba(180,107,255,.45)}
h1 .v{font-size:24px;color:#8f897c;letter-spacing:0;margin-left:10px;vertical-align:middle}
.sub{font-size:26px;margin-top:6px;font-weight:600;color:#f3ead2}
ul{list-style:none;display:grid;grid-template-columns:292px 292px;gap:9px 14px;margin-top:16px}
li{font-size:19px;font-weight:600;display:flex;align-items:center;gap:9px;line-height:1.1}
li i{width:9px;height:9px;border-radius:50%;flex:none}
li span{color:#a39d8f;font-weight:400}
.g{background:#33ff99;box-shadow:0 0 8px #33ff99}.p{background:#b46bff;box-shadow:0 0 8px #b46bff}
.y{background:#ffd23f;box-shadow:0 0 8px #ffd23f}.b{background:#4a90ff;box-shadow:0 0 8px #4a90ff}
/* The ported pack callout */
.pack{margin-top:18px;position:relative;border-radius:6px;padding:12px 16px 12px;
background:linear-gradient(135deg,rgba(120,40,200,.42),rgba(40,10,70,.55) 60%,rgba(20,90,70,.35));
border:2px solid #b46bff;box-shadow:0 0 26px rgba(180,107,255,.45), inset 0 0 30px rgba(0,0,0,.35)}
.pack .head{display:flex;align-items:baseline;gap:12px}
.pack .big{font-size:27px;font-weight:600;color:#fff;text-shadow:0 0 14px rgba(180,107,255,.8)}
.pack .opt{font-size:14px;font-weight:600;letter-spacing:2px;color:#ffd23f;text-transform:uppercase}
.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:6px 10px;margin-top:8px}
.stat b{display:block;font-size:31px;line-height:1;color:#ffd23f;font-weight:600;text-shadow:0 0 10px rgba(255,210,63,.35)}
.stat span{font-size:16px;color:#e7dcf7}
.pack .foot{font-size:16px;color:#cbbfe0;margin-top:10px}
.after{font-size:16px;color:#8f897c;margin-top:12px}
.after b{color:#f3ead2;font-weight:600}
.pack .foot b{color:#33ff99;font-weight:600}
.url{position:absolute;left:44px;bottom:24px;font-size:17px;color:#8f897c;z-index:10}
.url b{color:#ffd23f;font-weight:600}
/* Screenshots */
.shot{position:absolute;border:3px solid #b8923a;box-shadow:0 14px 40px rgba(0,0,0,.75),0 0 0 1px #000;border-radius:2px;overflow:hidden;background:#000}
.shot img{display:block;width:100%;height:100%;object-fit:cover}
.hero{left:672px;top:26px;width:574px;height:318px;transform:rotate(1.2deg);z-index:2}
.hero img{object-position:50% 64%}
.glows{left:664px;top:318px;width:300px;height:286px;transform:rotate(-2deg);z-index:4}
.glows img{object-position:52% 40%;transform:scale(1.15);transform-origin:52% 30%}
.armour{left:978px;top:330px;width:270px;height:274px;transform:rotate(2deg);z-index:3;border-color:#b46bff}
.armour img{object-position:38% 40%}
.tag{position:absolute;z-index:8;font-size:14px;font-weight:600;padding:3px 10px;border-radius:3px;background:#1b1710;border:1px solid #8a6d2b;color:#ffd23f;letter-spacing:1px;white-space:nowrap}
.tag.pk{background:#2a1340;border-color:#b46bff;color:#e6d2ff}
.t1{left:1056px;top:40px;transform:rotate(1.2deg)}
.t2{left:682px;top:578px;transform:rotate(-2deg)}
.t3{left:1078px;top:582px;transform:rotate(2deg)}
radial-gradient(ellipse 430px 330px at 70px 70px,rgba(114,249,43,.30),transparent 70%),
radial-gradient(ellipse 520px 420px at 250px 640px,rgba(180,76,255,.48),transparent 70%),
radial-gradient(ellipse 300px 260px at 420px 300px,rgba(67,250,221,.10),transparent 70%),
linear-gradient(170deg,#0f1a0b 0%,#0d0a14 40%,#170a26 100%)}
.pic{position:absolute;left:360px;top:0;width:920px;height:640px;clip-path:polygon(120px 0,100% 0,100% 100%,0 100%);overflow:hidden}
.pic img{width:100%;height:100%;object-fit:cover;object-position:18% 40%;filter:saturate(1.22) contrast(1.06) brightness(1.04)}
.pic:after{content:"";position:absolute;inset:0;background:
linear-gradient(90deg,rgba(13,10,20,.55),transparent 22%),
radial-gradient(ellipse 380px 300px at 20% 30%,rgba(114,249,43,.10),transparent 70%),
radial-gradient(ellipse 420px 320px at 62% 60%,rgba(180,76,255,.12),transparent 70%)}
.edge{position:absolute;left:360px;top:0;width:124px;height:640px;
background:linear-gradient(var(--fel2),var(--fel) 30%,var(--teal) 48%,var(--pur2) 66%,var(--pur));
clip-path:polygon(117px 0,124px 0,7px 100%,0 100%);filter:drop-shadow(0 0 12px rgba(180,76,255,.9)) drop-shadow(0 0 6px rgba(114,249,43,.6))}
.left{position:absolute;left:38px;top:28px;width:430px}
.kicker{font-size:15px;letter-spacing:4px;color:var(--fel2);font-weight:600;text-shadow:0 0 10px rgba(114,249,43,.6)}
h1{font-family:"Segoe UI Black","Segoe UI",sans-serif;font-weight:900;font-size:96px;line-height:.92;letter-spacing:-2px;margin-top:4px}
h1 span{background-clip:text;-webkit-background-clip:text;color:transparent}
h1 .d{background-image:linear-gradient(180deg,#d6ff7a 0%,var(--fel2) 35%,var(--fel) 70%,#3fc214 100%);filter:drop-shadow(0 0 16px rgba(114,249,43,.75))}
h1 .m{background-image:linear-gradient(180deg,#f0d8ff 0%,var(--pur3) 30%,var(--pur2) 55%,var(--pur) 80%,#7d22d6 100%);filter:drop-shadow(0 0 18px rgba(180,76,255,.85))}
.sub{font-size:24px;font-weight:600;color:#fff;line-height:1.15;margin-top:6px;text-shadow:0 0 12px rgba(180,76,255,.45)}
ul{list-style:none;margin-top:15px;display:grid;gap:7px}
li{font-size:20px;font-weight:600;white-space:nowrap}
li span{color:#b9a9d6;font-weight:400}
li b{color:var(--fel2);text-shadow:0 0 10px rgba(114,249,43,.55)}
.pack{margin-top:15px;padding:9px 13px;border-radius:7px;border:2px solid var(--pur);width:356px;
background:linear-gradient(135deg,rgba(180,76,255,.45),rgba(60,14,110,.65) 60%,rgba(114,249,43,.16));
box-shadow:0 0 22px rgba(180,76,255,.7),inset 0 0 22px rgba(0,0,0,.35)}
.pack .h{font-size:13px;letter-spacing:2px;color:var(--pur3);font-weight:600}
.pack .n{font-size:18px;font-weight:600;color:#f1e4ff;margin-top:2px;line-height:1.3}
.pack .n b{color:var(--fel2);font-size:22px;text-shadow:0 0 10px rgba(114,249,43,.6)}
.url{position:absolute;left:40px;bottom:20px;font-size:16px;color:#9d8fb8}
.url b{color:var(--pur2)}
/* The slogan plate on the ground under the group */
.ground{position:absolute;left:360px;bottom:0;width:920px;height:150px;clip-path:polygon(28px 0,100% 0,100% 100%,0 100%);
background:linear-gradient(0deg,rgba(10,6,18,.88) 0%,rgba(10,6,18,.55) 45%,transparent 100%)}
.forge{position:absolute;left:520px;bottom:14px;width:610px;text-align:center;padding:4px 18px 8px;border-radius:12px;border:2px solid transparent;
background:linear-gradient(rgba(14,8,24,.80),rgba(14,8,24,.86)) padding-box,
linear-gradient(90deg,var(--fel2),var(--teal) 45%,var(--pur2) 75%,var(--pur)) border-box;
box-shadow:-14px 0 26px -6px rgba(114,249,43,.55),14px 0 26px -6px rgba(180,76,255,.75),0 8px 24px rgba(0,0,0,.6)}
.forge .big{font-family:"Segoe UI Black","Segoe UI",sans-serif;font-weight:900;font-size:44px;line-height:1.05;letter-spacing:1px;text-transform:uppercase;
background-image:linear-gradient(90deg,#d6ff7a 0%,var(--fel2) 18%,var(--teal) 48%,var(--pur3) 72%,var(--pur) 100%);
-webkit-background-clip:text;background-clip:text;color:transparent;
filter:drop-shadow(0 0 12px rgba(67,250,221,.45)) drop-shadow(0 0 18px rgba(180,76,255,.45))}
.forge .small{font-size:18px;font-weight:600;color:#eee4ff;letter-spacing:.3px;margin-top:1px}
.forge .small b{color:var(--fel2);font-weight:600}
.forge .small i{font-style:normal;color:var(--pur3)}
/* The download badge: a small copy of the slogan plate */
.badge{position:absolute;right:24px;top:20px;display:flex;align-items:center;gap:9px;padding:6px 16px 7px 12px;border-radius:10px;border:2px solid transparent;
background:linear-gradient(rgba(14,8,24,.82),rgba(14,8,24,.88)) padding-box,
linear-gradient(90deg,var(--fel2),var(--teal) 45%,var(--pur2) 75%,var(--pur)) border-box;
box-shadow:-10px 0 20px -6px rgba(114,249,43,.6),10px 0 20px -6px rgba(180,76,255,.8),0 6px 18px rgba(0,0,0,.6)}
.badge .ico{font-size:18px;filter:drop-shadow(0 0 6px rgba(67,250,221,.6))}
.badge .txt{font-family:"Segoe UI Black","Segoe UI",sans-serif;font-weight:900;font-size:19px;letter-spacing:1px;text-transform:uppercase;line-height:1;
background-image:linear-gradient(90deg,#d6ff7a 0%,var(--fel2) 20%,var(--teal) 50%,var(--pur3) 75%,var(--pur) 100%);
-webkit-background-clip:text;background-clip:text;color:transparent;
filter:drop-shadow(0 0 8px rgba(67,250,221,.4)) drop-shadow(0 0 12px rgba(180,76,255,.4))}
</style></head><body>
<div class="frame"></div>
<div class="pic"><img src="hero-group.jpg"></div>
<div class="ground"></div>
<div class="edge"></div>
<div class="forge"><div class="big">Forge your illusion!</div>
<div class="small">👯 Share <b>DMorph</b> with your friends to <i>see each other's looks</i></div></div>
<div class="badge"><span class="ico">⬇️</span><span class="txt">Free on GitHub</span></div>
<div class="left">
<div class="kicker">Morph window · WoW 1.12 · OctoWoW</div>
<h1><span class="d">D</span><span class="m">Morph</span><span class="v">v2.21</span></h1>
<div class="sub">Become any creature, ride any mount, wear any item</div>
<div class="kicker">MORPH ADDON · WOW 1.12 · OCTOWOW</div>
<h1><span class="d">D</span><span class="m">Morph</span></h1>
<div class="sub">Become any creature,<br>ride any mount, wear any item</div>
<ul>
<li><i class="g"></i><div>16,000+ models <span>3D previews</span></div></li>
<li><i class="p"></i><div>Whole-model previews <span>zoom, step</span></div></li>
<li><i class="b"></i><div>Mount skins <span>on your own keys</span></div></li>
<li><i class="p"></i><div>Real skin, face and hair</div></li>
<li><i class="p"></i><div>Weapon glows <span>and your size</span></div></li>
<li><i class="y"></i><div>12,000+ items, 352 sets</div></li>
<li><i class="b"></i><div>Weather <span>and</span> time of day</div></li>
<li><i class="g"></i><div>See each other's morphs</div></li>
<li>🐲 <b>16,000+</b> creatures <span>3D previews</span></li>
<li>🐎 <b>950</b> mounts <span>on your own keys</span></li>
<li>🧝 Every race <span>real skin, face, hair</span></li>
<li>🗡️ <b>13,000+</b> items · <b>351</b> sets</li>
<li>✨ Glows · ⛈️ weather · 📏 size</li>
<li>👯 Friends see your morphs</li>
</ul>
<div class="pack">
<div class="head"><div class="big">Want a LOT more models?</div><div class="opt">+ optional ported pack</div></div>
<div class="stats">
<div class="stat"><b>6,399</b><span>creature looks</span></div>
<div class="stat"><b>949</b><span>mounts</span></div>
<div class="stat"><b>12,781</b><span>weapons</span></div>
<div class="stat"><b>36,014</b><span>armour looks</span></div>
<div class="stat"><b>915</b><span>armour sets</span></div>
<div class="stat"><b>33</b><span>TBC-MoP glows</span></div>
</div>
<div class="foot">From later expansions, in extra patch files · <b>one double-click to install</b></div>
</div>
<div class="after"><b>Free addon</b> · works without the pack · friends with it see your ported looks</div>
<div class="pack"><div class="h">🚀 + OPTIONAL PORTED PACK</div>
<div class="n"><b>8,157</b> creatures · <b>2,193</b> mounts<br><b>48,889</b> weapons &amp; armour · <b>915</b> sets</div></div>
</div>
<div class="url"><b>github.com/bdot89/DmorphOcto</b> · uses VanillaHelpers</div>
<div class="shot hero"><img src="ported-gunner.jpg"></div>
<div class="shot glows"><img src="ported-glow-sword.jpg"></div>
<div class="shot armour"><img src="ported-armour.jpg"></div>
<div class="tag pk t1">949 PORTED MOUNTS</div>
<div class="tag t2">52 WEAPON GLOWS</div>
<div class="tag pk t3">PORTED ARMOUR</div>
<div class="url"><b>github.com/bdot89/DmorphOcto</b> · v2.21</div>
</body></html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

+127
View File
@@ -1709,6 +1709,66 @@ check(channelSays(" s200"), "and with your look when someone asks")
DmorphOctoDB.scale = nil
say(".item head 0")
wait(3)
-- 2.23.0: weapon glows are shared too (user: "weapon glows are not sharing").
;(function()
local others = {} -- guid -> slot -> { permanent, temporary }
local ownGet, ownSet = DmorphHelper_GetItemEnchants, DmorphHelper_SetItemEnchants
function DmorphHelper_GetItemEnchants(unit, slot)
local u = Mock.Unit(unit)
if not u then
error("Unit not found.")
end
local e = (others[u.guid] or {})[slot] or { 7, 0 } -- their real enchant: 7
return e[1], e[2], 0
end
function DmorphHelper_SetItemEnchants(unit, slot, permanent, temporary)
local u = Mock.Unit(unit)
if not u then
error("Unit not found.")
end
others[u.guid] = others[u.guid] or {}
others[u.guid][slot] = { permanent, temporary }
end
local function b36(n)
local digits, text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", ""
while n > 0 do
text = string.sub(digits, math.mod(n, 36) + 1, math.mod(n, 36) + 1) .. text
n = math.floor(n / 36)
end
return text == "" and "0" or text
end
local glow = DmorphOcto.GetGlows().enchant[1]
local function shown(slot)
local e = (others[ally] or {})[slot]
return e and e[1]
end
hear("Ally", "L 3HR 0 - " .. ally .. " gp" .. b36(glow))
check(shown(16) == glow and morphOf(ally).display == 4527, "a DMorph user's weapon glow shows on them")
others[ally][16] = { 7, 0 } -- the server resends their weapon (a weapon swap)
wait(0.5)
check(shown(16) == glow, "and goes back on when the game puts their own enchant back")
hear("Ally", "G -")
wait(0.5)
check(shown(16) == 7, "a G message without glows puts their own enchant back")
hear("Ally", "G gp" .. b36(999999))
wait(0.5)
check(shown(16) == 7, "a glow this game doesn't have (another ported pack) isn't put on")
hear("Ally", "L 3HR 0 - " .. ally .. " s150 gq" .. b36(glow))
check(shown(17) == glow, "a glow token after the size token is read too")
quiet()
DmorphOctoDB.glows[16] = glow
say(".item head 0") -- any change tells the sharing code
wait(3)
check(channelSays("DMO2 G gp" .. b36(glow)), "your weapon glow goes out to DMorph users around you")
quiet()
hear("Someone", "Q Tester")
wait(4)
check(channelSays(" gp" .. b36(glow)), "and with your look when someone asks")
DmorphOctoDB.glows[16] = nil
say(".item head 0")
wait(3)
DmorphHelper_GetItemEnchants, DmorphHelper_SetItemEnchants = ownGet, ownSet
end)()
hear("Ally", "L 3HR 3HR - " .. ally) -- Ally's look as the tests below remember it
DmorphHelper_SetScale, DmorphHelper_GetScale = nil, nil
Mock.units.target = nil
@@ -2489,6 +2549,40 @@ Mock.Tick(0.3)
check(game.rebuilds == rebuilt + 5, "/dmorph itemcheck off stops the rebuilds too")
Mock.gear[1] = nil
slash("dmorph itemcheck on")
-- 2.22.0 (user, 21 Oct: items changed when losing durability, after a spirit res
-- or a revive, and after repairing): 1.12 has no event for a durability change,
-- so it's read once a second; coming back to life and closing a vendor check at once.
do
Mock.gear[1] = { 7000, 1, 60, 60 }
Mock.Fire("UNIT_INVENTORY_CHANGED", "player")
Mock.Tick(2)
local worn = game.rebuilds
Mock.gear[1][3] = 55 -- worn down in a fight: no event
Mock.Tick(0.6)
Mock.Tick(0.6)
Mock.Tick(0.3)
check(game.rebuilds == worn + 1, "a durability change with no event is found within a second and rebuilds the model")
Mock.Tick(2)
local dead = game.rebuilds
Mock.Fire("PLAYER_UNGHOST")
Mock.Tick(0.3)
local revived = game.rebuilds
Mock.Tick(0.7)
Mock.Tick(0.7)
Mock.Tick(0.3)
check(revived == dead + 1 and game.rebuilds == dead + 2,
"coming back to life rebuilds the model now and once more a moment later")
Mock.Tick(2)
local beforeRepair = game.rebuilds
Mock.gear[1][3] = 60
Mock.Fire("MERCHANT_CLOSED")
Mock.Tick(0.3)
check(game.rebuilds == beforeRepair + 1, "a repair rebuilds the model when the vendor closes")
Mock.Tick(1.1)
Mock.Tick(1.1)
check(game.rebuilds == beforeRepair + 1, "and the once-a-second check finds nothing new to rebuild")
Mock.gear[1] = nil
end
-- After a loading screen the game may have built your model before it had the
-- items your morphs show (invisible, white in previews: user, 16 Oct): rebuilt
-- once, when every morphed item is in.
@@ -2954,6 +3048,39 @@ Mock.portedData = nil
loadUI()
check(not DmorphOcto.GetCreatureCatalog().byID[60001], "without Data/Ported.lua there are no ported models")
-- 2.23.0 (user): a pop-up at login or /reload when DmorphHelper is missing or out of date.
;(function()
local function setupPopup()
for _, p in ipairs(Mock.popups) do
if p.which == "DMORPHOCTO_SETUP" then
return p.arg
end
end
end
Mock.Tick(6)
check(contains(setupPopup() or "", "DmorphHelper isn't running"), "logging in without DmorphHelper shows a pop-up")
installHelper({ 1, 2, 3, 4, 5 })
local newest = DmorphHelper_Version
function DmorphHelper_Version()
return 15
end
loadUI()
Mock.Tick(2)
check(setupPopup() == nil, "not straight away: a few seconds after the loading screen")
Mock.Tick(4)
check(contains(setupPopup() or "", "v15 is running"), "an older DmorphHelper shows a pop-up with both versions")
StaticPopupDialogs.DMORPHOCTO_SETUP.OnCancel()
loadUI()
Mock.Tick(6)
check(setupPopup() == nil, "Don't remind me keeps it away after a /reload")
DmorphOctoAccount.setupNagOff = nil
DmorphHelper_Version = newest
loadUI()
Mock.Tick(6)
check(setupPopup() == nil, "with the right DmorphHelper there's no pop-up")
removeHelper()
end)()
-- 2.18.0 Slutmog (user, 18 Oct): an Items source listing Data/Slutmog.lua's revealing
-- pieces (measured from the body textures) and OctoWoW's invisible Unseen Fashion items.
;(function()