RPG Minimap v1.4

This bundle is marked as high quality. It exceeds standards and is highly desirable.
RbeQz1.png


A scrolling minimap for Quadruple-A RPG Maps

RbeQz1.png


Overview

Installation

Tutorial

Credits


Overview

RPG Minimap is a scrolling minimap made completely from scratch that is designed for maps with a locked camera, but it can also be used as a static minimap.

If you use this system, the default minimap will be hidden. Instead, the terrain will be rendered with an array of frames that are moved smoothly across the minimap area to achieve the scrolling effect. Objects are rendered on top of the terrain. You are given complete control over which objects are being drawn and which icon should be used.

Minimap icons can have mouse-over tooltips that show the name of a unit or quest objective. Objects outside of the minimap area can be highlighted with a waypoint marker, helping the players in orienting themselves despite the lack of a global minimap. Objects inside dungeons or buildings, which are typically separate sections on the map, can be translocated to appear at the correct location in the overworld. There is currently no way to show doodads on the minimap, but I'm already working on a system to solve that.

A good minimap requires good texture assets. There are a number of textures included in the test map and I will include more as a I make them. If you're using this system, please share all textures you make for it in this thread, so that others may use them.

Included in the Test Map is also Region Titles, a small system that creates WoW-style region name popups when you enter a new area of the map. Since both systems have the same dependencies, and, if you're interested in one, you're likely to be interested in the other, I decided to bundle them together.

RPG Minimap is powered by A.L.I.C.E.

Will make a Lua-GUI version on request.

RPG Minimap

Copy the RPG Minimap and TerrainTextureColors scripts into your map. Next, make sure you have all the requirements imported. These are:

RequirementDescription
Total InitializationNeeds no explanation.
ALICEThe engine used as the backbone of the system. Follow the installation guide as it is laid out in the hiveworkshop thread. You also need to import the Camera and Rects libraries.
HandleTypeRequirement for ALICE.
HookRequirement for ALICE.
Pathing Wizard (optional)This tool is used to create a pathing map and is required if you want to hide inaccessible terrain.

Next, import all assets required for RPG Minimap. These are compiled in the .zip-file that is included in the archive. The best way to import all of the assets quickly is to save the map in folder mode and then copy & paste the contents of the .zip-file into the parent folder.

RequirementDescription
CustomTooltip.toc
CustomTooltip.fdf
These are the frame definition files used by ALICE for its debug mode tooltips.
RPGMinimapFrames.toc
NeatTextMessage.fdf
MinimapTextureFrames.fdf
These are the frame definition files for all minimap frames.
MinimapTextures/MinimapTextureTexture0-14.blpThese are the textures used to render the minimap terrain.
UI/Console/Race/RaceUITile01-04.blpThese are modified console UI textures for the four races that are transparent in various regions. If you're using a custom user interface, you have to edit the textures as laid out in the tutorial.
MinimapTextures/MinimapMarker0-354.blp (optional)These are the textures used for the waypoint markers. Including these is optional and you only need them if you want to use waypoint markers. You can also create your own waypoint marker textures and use those.

To show the RPG Minimap, you must call RPGMinimap.Show(). You should do this the earliest at 0 seconds.


Region Titles

To install Region Titles, you need to install ALICE, the Cameras and Rects libraries, as well as import the RegionTitle.toc and RegionTitle.fdf files.

Terrain

Minimap Icons

Waypoint Markers

Translocators

UI Adjustments


Terrain

The terrain is rendered using a matrix of frames, where each 128x128 in the world is given its own set of frames. Only one of those frames is moved, while all other frames are anchored to that frame, thereby moving automatically. As a row or column of frames is exiting the minimap area on one side, it is simply recycled and enters the area on the opposite side.

The frames are tinted to the appropriate color of the terrain. The tinting colors are stored in the TERRAIN_TEXTURE_COLORS table. These colors were derived from the average color of the terrain texture. Water and blight colors are customized in the RPG Minimap config.

To avoid a pixelated look, multiple frames with partial transparency are used for one terrain tile, each frame corresponding to one of the neighboring terrain types. This creates a large amount of frames, but because they are simple frames, there seem to be no performance issues.

The default terrain color can be overwritten, if necessary, in specific regions with the function:
Lua:
RPGMinimap.OverwriteTerrainColor(rect, color)

Fog of War

You have the option to create a fog of war that hides all areas until they are explored. The color of the fog of war can be customized. The location where the minimap is being explored is bound to the player's camera and is therefore asynchronous. If you're using this feature, make sure to disable the RPG Minimap system during cinematics.

Hiding Inaccessible Terrain

Another powerful feature of this system is that inaccessible terrain can be hidden, replacing the terrain textures with complete black. This feature is especially useful for dungeons and caves. If you want to use this feature, import the Pathing Wizard and get yourself accustomed with its interface, then define the necessary seed points for the pathing map to be generated correctly. If the generation is faulty and areas that should be inaccessible are visible, enable VISUALIZE_MAP and check for any leaks in your pathing map.

Minimap Icons

RPG Minimap offers automatic minimap icon creation for units, destructables, and items. Their texture, size, level, color, and visibility radius, as well as whether they are being drawn are controlled by functions in the config that you can fully customize. The values you need to set for an icon are:

Texture
The full texture path. I recommend setting up string constants as shown in the config.

Size
The size is given in screen coordinates, where 0.00055 corresponds to one pixel on standard HD resolution.

Level
The level of a minimap icon determines which other minimap icons it occludes. Normally, you want to draw more important objects, such as heroes, over less important ones. The levels of the different widget types are customized in the GetWidgetLevel functions.

The lowest possible level is 4. This is because the levels 0-3 are occupied by the terrain frames and any object with a lower level would therefore be occluded. The highest possible level is 9. If you set the level any higher, the game crashes.

Visibility Radius
The visibility radius determines how far an object can be from the camera center before it stops being drawn. To omit the visibility radius and have the object always be drawn as long as it is within the minimap area, set the visibility radius to nil or -1.

Color
The tinting color of the frame. It is expected to be a table with {red, green, blue}-values from 0 to 255.

You can also manually add minimap icons with the functions:
Lua:
RPGMinimap.AddIconTarget(whichObject, texture, size, level, flags)
RPGMinimap.AddIconLoc(x, y, texture, size, level, flags)
Flags are a table that can hold additional, optional parameters. These are:
  • visibilityRadius - The same as for widgets.
  • color - The same as for widgets.
  • owner - Setting an owner will make the icon be hidden based on the ownership filters set.
  • name - Sets the name of the icon for the mouse-over tooltip. If the icon is attached to a target, the icon will inherit the target's name by default. To disable the tooltip, set its name to an empty string.
  • identifier - A string that is added to the ALICE identifiers.
  • onFirstReveal - A function that is invoked when this object is first revealed on the minimap. If your map is a multiplayer map, only run async-safe code in this function!

Creating a Hero Icon

A nice way to create a minimap icon for a hero is to take the hero's command icon and cut it into a circular shape with the frame of the button removed. You can use ButtonManager to do that. The frame required is included in the MinimapAssets archive.

You can also generate the icons with a programming language like Python or JavaScript. Here is the Python code for generating such an hero icon (translated by ChatGPT, subject to correction).

Python:
import numpy as np
from PIL import Image

# Define the x and y arrays, considering Python's 0-based indexing
x = np.arange(0, 64)  # 0 to 63
y = np.arange(0, 64)  # 0 to 63
x, y = np.meshgrid(x, y)

# Compute the radial distance from the center of the grid
r = np.sqrt((x - 31.5) ** 2 + (y - 31.5) ** 2)

# Calculate the alpha and mask arrays
alpha = np.clip(15.5 - 0.5 * r, 0, 1)
mask = np.clip(14.75 - 0.5 * r, 0, 1)

# Apply the mask to the image data (assuming cdata is a numpy array with image data)
cdata = mask[..., np.newaxis] * cdata  # Broadcasting mask over the RGB channels

# Save the image with the alpha channel
image = Image.fromarray(np.uint8(cdata))
image.putalpha(np.uint8(alpha * 255))
image.save('minimap.png', 'PNG')

You can underlay the icon with a glow using the HeroGlow.blp texture. To do that, create a second minimap icon with:
Lua:
RPGMinimap.AddIconTarget(yourHero, "MinimapTextures\\HeroGlow.blp", size, heroLevel - 1, {
    name = "",
    color = PLAYER_COLORS_RGB[GetConvertedPlayerId(GetOwningPlayer(yourHero))])
})
For size, use a value 30-50% higher than the hero icon size.

ALICE Integration

ALICE will handle the destruction of minimap icons you attach to widgets or other objects automatically. You can use ALICE widget event hooks and the OnCreation API to detect events that should create new minimap icons.

The ALICE_OnWidgetEvent function allows you to hook any function to its event detection. For example:
Lua:
function AddHeroGlow(unit)
    if IsUnitType(unit, UNIT_TYPE_HERO) then
        RPGMinimap.AddIconTarget(unit, "MinimapTextures\\HeroGlow.blp", size, heroLevel - 1, {
            name = "",
            color = PLAYER_COLORS_RGB[GetConvertedPlayerId(GetOwningPlayer(unit))])
        })
    end
end

ALICE_OnWidgetEvent({
    onUnitEnter = AddHeroGlow,
    onUnitRevive = AddHeroGlow
})
This will add a hero glow automatically to all heroes as they enter the map and as they are revived.

You should do all of this during map initialization before ALICE initializes. You find the full documentation of these functions under ALICE API.

You can modify the properties of minimap icons by adding additional flags to the flags table in AddIconLoc and AddIconTarget. They will be passed on to ALICE. For example, by setting the persistOnDeath flag, the minimap icon will persist as the unit it's attached to dies.

You can also make any table object (gizmo) you register with ALICE be drawn on the minimap simply by adding the "drawable" identifier. In fact, the AddIcon functions are simply wrappers around ALICE_Create. The table needs to have coordinate fields x and y, as well as fields for texture, size, and level.

Waypoint Markers

You can add waypoint markers to objects. This will make those objects visible through the fog of war and create an arrow pointing towards their position as long as they're outside of the minimap area.

To create a waypoint marker, do:
Lua:
RPGMinimap.AddWaypointMarker(whichObject, color)
whichObject is the object the waypoint marker is anchored to and color is a table with red, green, and blue values (0-255) controlling the tinting color of the marker.

You cannot anchor a waypoint marker to objects that are not being drawn on the minimap. For example, if you create a quest for an NPC and add the minimap icon manually with AddIconTarget, then the waypoint marker has to be anchored to that minimap icon instead of the NPC.

The waypoint marker uses an array of textures covering all possible angles. If you want to use your own texture, create different versions with the angle as an integer suffix, starting from 0, and set the MINIMAP_MARKER_ANGLE_SPACING constant to the angle difference between two versions.

Translocators

Imagine you have a building in which a quest NPC is located in. You enter the building via a circle of power, which teleports the hero to a different part of the map, where the indoor terrain is located. If you create a waypoint marker for that NPC, that marker would point to his location inside the building on the map, which would make no sense to players in the overworld.

This problem is addressed with translocator zones. To create a translocator zone, you need two rects; one for the origin and one for the target. Any minimap icon inside the origin rect will be cloned to also appear in the target rect. Meanwhile, the original will be hidden to all players who are not themselves inside the origin rect. This way, the quest marker will appear at the position of the building in the overworld for all players currently in the overworld. For all players inside the building, the location of the markers will remain unchanged.

If the cloned minimap icon itself is in another translocator zone, it will be cloned again. This chain will continue until the last clone appears in the overworld. This means that objects can be in a second room that is accessible via another teleporter and still appear at the correct position in the overworld.

You have the option to define an exit for a translocator zone. If you do, any object that has a waypoint marker and is in a zone that can be reached by going through the exit will appear on the minimap, with the marker pointing towards the exit. For example, a quest NPC in the overworld may ask you to kill a boss inside a cave. Once you kill the boss, you want to create a waypoint marker pointing to the quest NPC. As long as you are still in the cave, the waypoint marker will point towards the exit.

To create a translocator zone, do:
Lua:
RPGMinimap.CreateTranslocatorZone(originRect, targetRect, exit, parent)
originRect and targetRect can either be rects (useful if you want to draw them with the World Editor) or tables with the minX, minY, maxX, and maxY fields. Exit can either be a rect, which will use its center as the exit location, or a table containing a coordinate pair. If the exit does not lead to the overworld, you have to provide the parent of the zone, which you get from the return value of this function.

UI Adjustments

There are a few UI adjustments needed to make the minimap work. RPG Minimap creates frames that are moving beyond the minimap area border. For them to remain below the frame, their level must be lower than that of the Console UI. Because the highest terrain frame level is 3, the Console UI level has to be increased to 4, which is done in the AdjustUI function.

This now leads to the problem that the Console UI is obfuscating various UI elements, such as gold and lumber text. There are two solutions to this problem:
  • Increase the level of every UI frame that was obfuscated.
  • Make the Console UI transparent at the necessary locations
I was too lazy for option 1, so I went with option 2, but if you already have the frames compiled into a list, it might be more convenient.

Variants of the default race UIs with transparency are included in the test map. If you're using a custom UI, you need to make it transparent manually. To do so, export the texture files, and convert them to png with blpLab.

The Paint version included in Windows 11 supports transparency and is very convenient for this task. Open the png-file and use the fill tool to paint the black areas that need to become transparent white. Now create a second image file with the same dimensions as the UI texture file, then make it transparent with Ctrl + A, then Delete. Finally, copy and paste the UI texture over and select "Transparent Selection" at the top.

If you're using a heavily altered UI, you might need to adjust the AdjustUI function in the config.


Credits

Showcase Map
Outdoor Area - Ultimate Terraining Map
Indoor Area - EmberCraft

Quest Completed model by @Maximal
Healing Potion minimap icon by quellion
Contents

PlayerColors (Binary)

RegionTitles (Binary)

RPG Minimap v1.4 (Map)

RPGMinimap (Binary)

RPGMinimap Assets (Binary)

TerrainTextureColors (Binary)

Reviews
Wrda
For some reason I thought MINIMAP_WIDGET_TYPE_EXCEPTIONS was seperate from the other tables...brainfart. That's fine then. It's like learning a musical instrument, if you can do it fast, you can do it slow 😅 This deserves a place in the sky. High...
Level 4
Joined
Jul 28, 2024
Messages
76
Ehm, if map is generated via code, will it be rendered somehow?
I think this is not possible
 
Level 4
Joined
Jul 28, 2024
Messages
76
Hmmm, i'm using jass...
As far as i understand this library is the only way to redraw a minimap in wc3 if I textured it dynamically during first 0.5 seconds of the game
 
Level 4
Joined
Jul 28, 2024
Messages
76
I think ability to redraw map is supervaluable. If it was available in jass... see...
 
Absolutely Amazing, we needed this!
Thank you! :psmile: Let's make some ambitious RPG maps!

I think ability to redraw map is supervaluable. If it was available in jass... see...
Alright, I'll work on it after my next update/when @Wrda approves it. Don't have to do the changes twice then.
 

Wrda

Spell Reviewer
Level 27
Joined
Nov 18, 2012
Messages
1,951
Lua:
--[[
    
Set the values for size, texture, visibilityRadius and level for the minimap icons of different widget types (fourCC codes).


    Size                        The size of the minimap icon in screen coordinates.
    Texture                     The path to the texture for the minimap icon.
    VisibilityRadius            If set, the minimap icon will only be visible up to the specified distance from the camera. Set to -1 for no visibility radius.
    Level                       The level of the created frame. Frames with a higher level occlude frames with a lower level. Setting the level to a negative number
                                or to a value too high will crash the game.
    ]]


    MINIMAP_WIDGET_TYPE_TEXTURE                 = {
        Etyr = "TyrandeMinimap.blp",
        phea = "HealingPotionMinimap.blp"
    }
    MINIMAP_WIDGET_TYPE_SIZE                    = {
    }
    MINIMAP_WIDGET_TYPE_VISIBILITY_RADIUS       = {
    }
    MINIMAP_WIDGET_TYPE_LEVEL                   = {
    }
    MINIMAP_WIDGET_TYPE_COLOR                   = {
    }
I believe this is rather awkward to expect the user to add widget types this way, even if they can be declared anywhere, when the list comes big it's just a mess to work with. Why not have some sort of a function such as
RPGMinimap.RegisterWidgetType(fourCCString, texture, size, visibility, level, colour)? Seems faster, clear and simpler. Obviously the tables can the remain as they are.

Lua:
local char = string.char
Unused at the moment.

local function DrawMinimapIconOnReset and InitDrawWaypointMarker have unused parameters, but this definetely must be because of the pairs done in ALICE, I presume.
Unused minimapArtist parameter.

Lua:
local index = (math.floor((bj_RADTODEG*angle) / WAYPOINT_MARKER_ANGLE_SPACING + 0.5))*WAYPOINT_MARKER_ANGLE_SPACING
Lua ad: Hey friend! Are you tired of using BJs and JASS pain and nonsense? Try math.deg(radians) and it will make your day bright! It's on a 95% sale, don't miss your shot! Best regards from Lua Cult!

Lua:
---@param translocator Translocator
    ---@param drawable any
    ---@data table
    local function TranslocateMinimapIconOnReset(translocator, drawable, data)
        if translocationZoneOf[drawable] == translocator then
            translocationZoneOf[drawable] = nil
            translocatedCloneOf[drawable] = nil
        end
        ALICE_Kill(data.clone)
        data.clone = nil
    end
Missed "param" on annotation 😜

Another powerful resource that expands the horizons and let people dream. Just make that a function to register the widgets easier and then it's instant upgrade!

Approved
 
I believe this is rather awkward to expect the user to add widget types this way, even if they can be declared anywhere, when the list comes big it's just a mess to work with. Why not have some sort of a function such as
RPGMinimap.RegisterWidgetType(fourCCString, texture, size, visibility, level, colour)? Seems faster, clear and simpler. Obviously the tables can the remain as they are.
I think you're misunderstanding the purpose of these tables. You don't have to set the values for every widget type. They are just the types for which the configurations you set further up shouldn't apply. They are also only one of the many options you have to control the properties, as you can write anything into the functions further down. Nonetheless, a function to modify widget types is a good idea and I wrote it such that it can be called even after icons are already being drawn.
Lua:
        ---Assigns to all widgets with the specified code the properties in the provided table. The possible keys of the property table are texture, size, level, visibiltiyRadius, color, and exception (which can be true or false).
        ---@param fourCC string | integer
        ---@param propertyTable table
        ModifyWidgetType = function(fourCC, propertyTable)
            fourCC = type(fourCC) == "string" and fourCC or string.pack(">I4", fourCC)
            local key = minimapPreInit and FourCC(fourCC) or fourCC

            if propertyTable.texture then
                MINIMAP_WIDGET_TYPE_TEXTURE[key] = propertyTable.texture
            end
            if propertyTable.size then
                MINIMAP_WIDGET_TYPE_SIZE[key] = propertyTable.size
            end
            if propertyTable.level then
                MINIMAP_WIDGET_TYPE_SIZE[key] = propertyTable.level
            end
            if propertyTable.visibilityRadius then
                MINIMAP_WIDGET_TYPE_SIZE[key] = propertyTable.visibilityRadius
            end
            if propertyTable.color then
                MINIMAP_WIDGET_TYPE_SIZE[key] = propertyTable.color
            end
            if propertyTable.exception then
                ---@diagnostic disable-next-line: assign-type-mismatch
                MINIMAP_WIDGET_TYPE_EXCEPTIONS[key] = propertyTable.exception
            end

            if minimapInitialized then
                ALICE_ForAllObjectsDo(ClearAllCaches, fourCC)
                if propertyTable.exception == true then
                    ALICE_ForAllObjectsDo(AddDrawableIdentifier, fourCC)
                elseif propertyTable.exception == false then
                    ALICE_ForAllObjectsDo(RemoveDrawableIdentifier, fourCC)
                end
            end
        end,

local function DrawMinimapIconOnReset and InitDrawWaypointMarker have unused parameters, but this definetely must be because of the pairs done in ALICE, I presume.
Unused minimapArtist parameter.
Yes, the argument order in ALICE interaction function calls is (male, female) and (male, female, dataTable) in all callback functions.

Lua:
local index = (math.floor((bj_RADTODEG*angle) / WAYPOINT_MARKER_ANGLE_SPACING + 0.5))*WAYPOINT_MARKER_ANGLE_SPACING
Lua ad: Hey friend! Are you tired of using BJs and JASS pain and nonsense? Try math.deg(radians) and it will make your day bright! It's on a 95% sale, don't miss your shot! Best regards from Lua Cult!
Why do you want me to make my code slower? 🧐

Lua:
---@param translocator Translocator
    ---@param drawable any
    ---@data table
    local function TranslocateMinimapIconOnReset(translocator, drawable, data)
        if translocationZoneOf[drawable] == translocator then
            translocationZoneOf[drawable] = nil
            translocatedCloneOf[drawable] = nil
        end
        ALICE_Kill(data.clone)
        data.clone = nil
    end
Missed "param" on annotation 😜
Good catch.

Another powerful resource that expands the horizons and let people dream. Just make that a function to register the widgets easier and then it's instant upgrade!
inaros.png
 
Last edited:

Wrda

Spell Reviewer
Level 27
Joined
Nov 18, 2012
Messages
1,951
I think you're misunderstanding the purpose of these tables. You don't have to set the values for every widget type. They are just the types for which the configurations you set further up shouldn't apply. They are also only one of the many options you have to control the properties, as you can write anything into the functions further down.
For some reason I thought MINIMAP_WIDGET_TYPE_EXCEPTIONS was seperate from the other tables...brainfart.
That's fine then.

Why do you want me to make my code slower? 🧐
It's like learning a musical instrument, if you can do it fast, you can do it slow 😅 Lua you failed me this time

This deserves a place in the sky.

High Quality
 
Updated to v1.3:
  • Added the CAMERA_IS_EXPLORER config option. The minimap area around the camera will only be revealed automatically if this option is set.
  • Added the RPGMinimap.SetExplorer function, which causes an object to reveal the minimap around itself. This can be used to share exploration between players and makes RPG Minimap fully multiplayer viable!
  • Changed the RPGMinimap.ModifyWidgetType function documentation, clarifying that it only modifies the config tables and won't have an effect unless their values are used.
  • Updated ALICE to 2.4.2.

For some reason I thought MINIMAP_WIDGET_TYPE_EXCEPTIONS was seperate from the other tables...brainfart.
That's fine then.
It is different because it is used in the internals, unlike the other tables.

This deserves a place in the sky.

High Quality
Thank you! (147, 101, 184), good color! :plol:
 
Top