HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Map generation?

02-24-2009, 02:38 AM#1
Zandose
Hi, its been a while since I've posted on here, although I frequently check the forums. Anyways, I was wondering if anyone had thought of creating maps in this different method. Normally you create a map with the basics; terrain, destructables/doodads, units, and triggers (quests, systems, etc). I know something similar to this has been done before but, what about creating the whole map in the triggers and "loading/unloading" whatever you need. For instance, terrain can easily be generated, doodads can be changed to destructables, and terrain can be altered by deformations (hills, walls, cliffs and water /w model). Also, there are methods for saving and restoring map information. For instance, almost any information can be stored in game-cache, extracted, and put back into the map; like terrain. There's a program to extract destructable information from a map and convert it into triggers. If you've seen the weekly terraining section imagine: take those massive destructable buildings, extracting the destructables into triggers, and being able to load them into your map at anytime.

None of these triggers should work. They are either untested or not finished. I just put them up as examples.
Hidden information:
Collapse JASS:
//Basic random deformations.
library Deformation

globals
    private real array X
    private real array Y
    private real array Radius
    private real array Depth
endglobals

public function Create takes nothing returns nothing
    local integer i = 0
    local integer n = GetRandomInt(3, 10)
    loop
        set i = i + 1
        set X[i] = GetRandomReal(MinX, MaxX)
        set Y[i] = GetRandomReal(MinY, MaxY)
        set Radius[i] = GetRandomReal(256, 3072)
        set Depth[i] = GetRandomReal(MinY, MaxY)
        call TerrainDeformCrater(X[i], Y[i], Radius[i], Depth[i], 1, true)
        exitwhen i == n
    endloop
endfunction

endlibrary

Hidden information:
Collapse JASS:
library ESTerrain  initializer Init

globals
    public integer array Code
    public integer array Chance
    public integer       End
endglobals

public function Create takes nothing returns nothing
    local integer i
    local real x = MinX
    local real y = MinY
    local integer num = 0
    loop
        set num = num + 1
        exitwhen Code[num+1] == null or Code[num+1] == 0
    endloop
    loop
        loop
            set i = 0
            loop
                set i = i + 1
                exitwhen GetRandomInt(0, 100) <= Chance[i]
                if i == num then
                    set i = 0
                endif
            endloop
            call SetTerrainType(x, y, Code[i], -1, 1, 1)
            set y = y + 128
            exitwhen y > MaxY
        endloop
        set y = MinY
        set x = x + 128
        exitwhen x > MaxX
    endloop
endfunction

public function Remove takes nothing returns nothing
    local integer i = 0
    loop
        set i = i + 1
        exitwhen Code[i] == null or Code[i] == 0
        set Code[i] = 0
        set Chance[i] = 0
    endloop
endfunction

private function Init takes nothing returns nothing
    set Code[1] = 'Adrt' //Dirt
    set Chance[1] = 20
    set Code[2] = 'Adrd' //Rough Dirt
    set Chance[2] = 10
    set Code[3] = 'Agrs' //Grass
    set Chance[3] = 30
    set Code[4] = 'Arck' //Rock
    set Chance[4] = 5
    set Code[5] = 'Agrd' //Lumpy Grass
    set Chance[5] = 20
    set Code[6] = 'Avin' //Vines
    set Chance[6] = 10
    set Code[7] = 'Adrg' //Grassy Dirt
    set Chance[7] = 20
    set Code[8] = 'Alvd' //Leaves
    set Chance[8] = 20
    set End = 8
endfunction

endlibrary

Hidden information:
Collapse JASS:
library ESAnimals initializer Init

globals
    private integer array Code
    private unit    array Unit
    private real    array Size
endglobals

public function Create takes nothing returns nothing
    local integer i = 0
    local integer num = 0
    local integer numberOfAnimals = GetRandomInt(1, 8)
    loop
        set i = i + 1
        set Unit[i] = CreateUnit(Player(13), Code[GetRandomInt(1, num)], GetRandomReal(MinX, MaxX), GetRandomReal(MinY, MaxY), 0)
        exitwhen i == numberOfAnimals
    endloop
endfunction

public function Remove takes nothing returns nothing
    local integer i = 0
    loop
        set i = i + 1
        exitwhen Unit[i] == null
        call RemoveUnit(Unit[i])
        set Unit[i] = null
    endloop
    loop
        set i = i + 1
        exitwhen Code[i] == null or Code[i] == 0
        set Code[i] = 0
        set Size[i] = 0
    endloop
endfunction

private function Init takes nothing returns nothing
    set Code[1] = 'nech' //Chicken
    set Code[2] = 'nfro' //Frog
    set Code[3] = 'necr' //Rabbit
    set Code[4] = 'nrac' //Raccoon
    set Code[5] = 'nder' //Stag
endfunction

endlibrary

Hidden information:
Collapse JASS:
library ESDestructable initializer Init

globals
    public integer array    Code
    public integer array    Variations
    public real    array    Scale
    public integer array    Chance
    public boolean array    Transparent //Used by other trigger
    public integer          End
endglobals

private function DoTrue takes nothing returns boolean
    return true
endfunction

public function Create takes nothing returns nothing
    local integer i = 0
    local integer num = 0
    local real x = MinX
    local real y = MinY
    loop
        set num = num + 1
        exitwhen Code[num+1] == null or Code[num+1] == 0
    endloop
    loop
        loop
            set i = 0
            loop
                set i = i + 1
                exitwhen GetRandomInt(0, 100) <= Chance[i]
                if i == num then
                    set i = 0
                    set num = 0
                endif
            endloop
            if Scale[i] != 0 and Scale[i] != null then
                call CreateDestructable(Code[i], x+GetRandomReal(-256, 256), y+GetRandomReal(-256, 256), GetRandomReal(0, 360), Scale[i], GetRandomInt(1, Variations[i]))
            else
                call CreateDestructable(Code[i], x+GetRandomReal(-256, 256), y+GetRandomReal(-256, 256), GetRandomReal(0, 360), 1, GetRandomInt(1, Variations[i]))
            endif
            set y = y + 256
            exitwhen y > MaxY
        endloop
        set y = MinY
        set x = x + 256
        exitwhen x > MaxX
    endloop
endfunction

public function Remove_Action takes nothing returns nothing
    call RemoveDestructable(GetEnumDestructable())
endfunction

public function Remove takes nothing returns nothing
    local integer i = 0
    local rect r = GetWorldBounds()
    loop
        call EnumDestructablesInRect(r, Condition(function DoTrue), function Remove_Action)
    endloop
    call RemoveRect(r)
    set r = null
    loop
        set i = i + 1
        exitwhen Code[i] == null or Code[i] == 0
        set Code[i] = 0
        set Variations[i] = 0
        set Chance[i] = 0
        set Scale[i] = 0
    endloop
endfunction

private function Init takes nothing returns nothing
    set Code[1] = 'ATtc' //Tree
    set Variations[1] = 5 //Five variations
    set Scale[1] = 1.75
    set Transparent[1] = true
    set Chance[1] = 50
    set Code[2] = 'ATtr' //Tree
    set Variations[2] = 3
    set Scale[2] = 1.75
    set Transparent[2] = true
    set Chance[2] = 50
    set Code[3] = 'B001' //Fire pit
    set Variations[3] = 1
    set Chance[3] = 1
    set Code[4] = 'B002' //Bird
    set Variations[4] = 1 
    set Chance[4] = 10
    set Code[5] = 'B003' //Cattail
    set Variations[5] = 1 
    set Chance[5] = 5
    set Code[6] = 'B004' //Bush
    set Variations[6] = 1
    set Scale[6] = .10
    set Chance[6] = 100
    set Code[7] = 'B005' //Rock
    set Variations[7] = 1 
    set Chance[7] = 10
    set Code[8] = 'B006' //Shurb
    set Variations[8] = 3 
    set Chance[8] = 30
    set Code[9] = 'B007' //Stump Hollow
    set Variations[9] = 1 
    set Scale[9] = .5 //A scale/size of 0.05 compared to 1 (one is normal size)
    set Chance[9] = 2
    set Code[10] = 'B008' //Log Angled
    set Variations[10] = 1
    set Scale[10] = .5
    set Chance[10] = 2
    set Code[11] = 'B009' //Log Stright
    set Variations[11] = 1
    set Scale[11] = .5
    set Chance[11] = 2
    set Code[12] = 'B00A' //Mushroom
    set Variations[12] = 5 
    set Chance[12] = 10
    set Code[13] = 'B00B' //Flowers
    set Variations[13] = 4 
    set Chance[13] = 20
    set End = 13
endfunction

endlibrary


Based upon the above stuff take it one step further. For example, with a regular RPG map, you create the biggest map possible to fit the most possible into it. Instead, cut the map up into 64x64 parts and load whichever part you want. You can also create massive maps. Along with map generation, I can do basic quest generation (doesn't work yet):
Hidden information:
Collapse JASS:
//Random quest generation. These quests are pretty simple.
//These are just retrival quests
//Currently 480 possible quest combinations.
//Next version: Math, statagy, escort, kill, and keep alive/guard.
scope QuestManager initializer Init

private keyword Data

globals
    //World map size
    private constant real WMinX = -16384
    private constant real WMinY = -16384
    private constant real WMaxX = 16384
    private constant real WMaxY = 16384
    //The REAL map size
    private constant real MinX = -2048 //The real map size (32x32)
    private constant real MinY = -2048
    private constant real MaxX = 2048
    private constant real MaxY = 2048
    //
    private constant integer UID_DUMMY           = 'h003'
    private constant integer AID_LOCUS           = 'xxxx' //Fix
    //----------------------------------------------------
    private string array Object //Ex: Crystal, Stone, Rock
    private string array Name   //Ex: Ender, Zan, Harry
    private string array Abstract //Ex: Light, Dark, Mist
    private integer      Object_Num //Ex: Crystal, Stone, Rock
    private integer      Name_Num   //Ex: Ender, Zan, Harry
    private integer      Abstract_Num //Ex: Light, Dark, Mist
    private string array Object_Effect //Model path
    private string array Abstract_Effect //Model path
    private Data   array D
endglobals

//Stores the random quest information
private struct Data
    quest  quest = CreateQuest()
    string title
    string description = "BLACK"
    real npc_x //The one who gave the quest to you
    real npc_y //^
    //---
    real x
    real y
    integer counter //Number of whatever (items/kills/etc)
    unit dummy
    effect item //Placement: "Feet"
    effect pointer //Placement: "origin"
    
    method Create takes nothing returns nothing
    
    endmethod
    
endstruct

private function Conditions takes nothing returns boolean
    return true
endfunction

public function Create takes nothing returns nothing
    local integer i = 0
    local rect r
    local region reg
    //Random picking of quest display style and other stuff
    local integer t = GetRandomInt(1, 9)
    local integer n = GetRandomInt(1, Name_Num)
    local integer o = GetRandomInt(1, Object_Num)
    local integer a = GetRandomInt(1, Abstract_Num)
    loop
        set i = i + 1
        e//xitwhen not Data[i].isUsed
    endloop
    //The struct
    set Data[i].isUsed = true
    set Data[i].n = n
    set Data[i].o = o
    set Data[i].a = a
    //Different styles of displaying the quest
    if t == 1 then
        set Data[i].title = "The " + Object[o] + " of " + Name[n]
    elseif t == 2 then
        set Data[i].title = "The " + Object[o] + "'s of " + Name[n]
    elseif t == 3 then
        set Data[i].title = "The " + Object[o] + " of " + Abstract[a]
    elseif t == 4 then
        set Data[i].title = "The " + Object[o]
    elseif t == 5 then
        set Data[i].title = "The " + Name[n] + " " + Object[o]
    elseif t == 6 then
        set Data[i].title = "The " + Name[n] + " " + Object[o] + " of " + Abstract[a]
    elseif t == 7 then
        set Data[i].title = Name[n] + "'s " + Object[o]
    elseif t == 8 then
        set Data[i].title = Name[n] + "'s " + Object[o] + " " + Abstract[a]
    elseif t == 9 then
        set Data[i].title = Name[n] + "'s " + Object[o] + " of " + Abstract[a]
    endif
    //You know
    set Data[i].x = GetRandomReal(MinX, MaxX)
    set Data[i].y = GetRandomReal(MinY, MaxY)
    //Effects (at the place of the object/item)
    set Data[i].dummy1 = CreateUnit(Player(13), UID_DUMMY, Data[i].x, Data[i].y, GetRandomReal(0, 360))
    set Data[i].dummy2 = CreateUnit(Player(13), UID_DUMMY, Data[i].x, Data[i].y, GetRandomReal(0, 360))
    set Data[i].effect1 = AddSpecialEffectTarget(Object_Effect[o], Data[i].dummy1, "origin")
    set Data[i].effect2 = AddSpecialEffectTarget(Object_Effect[o], Data[i].dummy2, "origin")
    call UnitAddAbility(Data[i].dummy1, AID_LOCUS)
    call UnitAddAbility(Data[i].dummy2, AID_LOCUS)
    //Quest menu
    set Data[i].quest = CreateQuest()
    call QuestSetTitle(Data[i].quest, Data[i].title)
    call QuestSetDescription(Data[i].quest, Data[i].description)
    //Floating text
    set Data[i].tt = CreateTextTag()
    call SetTextTagText(Data[i].tt, "A " + Object[o], 2.3)
    call SetTextTagPosUnit(Data[i].tt, Data[i].dummy2, 0)
    call SetTextTagColor(Data[i].tt, 255, 255, 255, 255)
    //Rect event
    set r = Rect(Data[i].x-128, Data[i].y-128, Data[i].x+128, Data[i].y+128)
    set reg = CreateRegion()
    call RegionAddRect(reg, r)
    call TriggerRegisterEnterRegion(CreateTrigger(), reg, Condition(function Conditions))
endfunction

public function Remove takes integer i returns nothing
    call DestroyEffect(Data[i].effect1)
    call DestroyEffect(Data[i].effect2)
    set Data[i].effect1 = null
    set Data[i].effect2 = null
    call RemoveUnit(Data[i].dummy1)
    call RemoveUnit(Data[i].dummy2)
    set Data[i].dummy1 = null
    set Data[i].dummy2 = null
    call DestroyQuest(Data[i].quest)
    set Data[i].quest = null
    call DestroyQuest(Data[i].quest)
    set Data[i].quest = null
    call DestroyTextTag(Data[i].tt)
    set Data[i].tt = null
    set Data[i].isUsed = false
endfunction

private function Init takes nothing returns nothing
    local integer i
    set Object[1] = "Crystal"
    set Object[2] = "Flower"
    set Object[3] = "Stone"
    set Object[4] = "Tree"
    set Object[5] = "Urn (a pot/jug)"
    set Object[6] = "Staff"
    set Object[7] = "Shield"
    set Object[8] = "Rune (symbol)"
    set Object[9] = "Word"
    set Object[10] = "Arrow"
    set Name[1] = "Ender"
    set Name[2] = "wiggen"
    set Name[3] = "Harry"
    set Name[4] = "Dan"
    set Name[5] = "Uther"
    set Name[6] = "Zan"
    set Name[7] = "Clare"
    set Name[8] = "Smith"
    set Abstract[1] = "Light"
    set Abstract[2] = "Dark"
    set Abstract[3] = "Mist"
    set Abstract[4] = "Magic"
    set Abstract[5] = "Air"
    set Abstract[6] = "Time"
    set Object_Effect[1] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Object_Effect[2] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Object_Effect[3] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Object_Effect[4] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Object_Effect[5] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Object_Effect[6] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Object_Effect[7] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Object_Effect[8] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Object_Effect[9] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Object_Effect[10] = "Objects\\Invalidmodel\\Invalidmodel.mdl"
    set Abstract_Effect[1] = "Objects\\RandomObject\\RandomObject.mdl"
    set Abstract_Effect[2] = "Objects\\RandomObject\\RandomObject.mdl"
    set Abstract_Effect[3] = "Objects\\RandomObject\\RandomObject.mdl"
    set Abstract_Effect[4] = "Objects\\RandomObject\\RandomObject.mdl"
    set Abstract_Effect[5] = "Objects\\RandomObject\\RandomObject.mdl"
    set Abstract_Effect[6] = "Objects\\RandomObject\\RandomObject.mdl"
    set i = 0
    loop
        set i = i + 1
        exitwhen Object[i] == null
    endloop
    set Object_Num = i - 1
    set i = 0
    loop
        set i = i + 1
        exitwhen Name[i] == null
    endloop
    set Name_Num = i - 1
    set i = 0
    loop
        set i = i + 1
        exitwhen Abstract[i] == null
    endloop
    set Abstract_Num = i - 1
endfunction

endscope


So, any thoughts?

I have a partial demo map for terrain, destructables, and deformations. All very basic stuff. I can upload it later in the week. Need to test it make sure it works first :) I've toyed with much more complex stuff, but it's messed up so I won't post it (not even sure where it is anymore).
02-24-2009, 04:53 AM#2
Nuclear Arbitor
my brother did a very basic version of this once. it's actually very fun. his version had continually spawning trees and gold, not fast, and creeps. really extended game play and i liked it. we had it so u started with a mobile drop point and 5 peasants at the end of a path on the edge of a map and moved out from there.
02-24-2009, 05:20 AM#3
Ammorth
The Mapping constest (hosted here) had a map that used generation to create an rpg map on a small map (with zones).

As for terrain deformations, there is no way in hell to get them to work nicely. First, you need to use permanent deformations, and they cannot be removed (so each one leaks). Secondly, its reported that different computers will get different z values on deformed terrain, even if the terrain deformation is non-local.

I don't think quest generation would be that interesting. Quests are interesting when they tell a story and progress. Having quests that cause you to aimlessly wander around and collect items and kill creeps is not impressive. Generating terrain and spawns is alright, but the quests should have some static cohesion.
02-24-2009, 05:29 AM#4
ShadowWolf
Quote:
Originally Posted by Ammorth
Having quests that cause you to aimlessly wander around and collect items and kill creeps is not impressive.
Hey, add a PvP system and you could have WoW. Or every other MMORPG for that matter...

The thought of spontaneous map generation has always intrigued me in various ways. I think having the entire map in every aspect being generated is a bit overbearing, but implementing it in various aspects is promising. I'm currently working on a tweaked TS that uses random generation to counter the typical lane scheme.
02-24-2009, 06:09 AM#5
Earth-Fury
Quote:
Originally Posted by Ammorth
Secondly, its reported that different computers will get different z values on deformed terrain, even if the terrain deformation is non-local.
Doesn't that have to do solely with with people who set graphics details too low not having terrain deformations show? or is it just generally inconsistent?

In any case, that's not really an issue unless you intend to do things like custom-coding projectiles or physics objects.
02-24-2009, 06:21 AM#6
xombie
Yes, but custom coding projectiles is the only way I'm going to be able to replicate "Slow Time" from the Diablo III Wizard.