Zwiebelchen
Hosted Project GR
- Joined
- Sep 17, 2009
- Messages
- 7,234
Here's a new thing I'm working on...
Basicly, it's a game engine based on a node system with multiple-choice dialogue intended for rogue-like or text-adventure games.
The idea behind this was to use .TGA as highres image backdrops which can be assigned on a per-scene base. The backdrop will remain active until a new backdrop information is called by a scene.
Then I have actors which will serve as objects that can be placed dynamically over the backdrop. Those will also be images, however, also have a dummy unit associated with them that can be accessed to display a portrait.
It is not MPI by design (who would want to play multiplayer adventures anyway?).
Basicly, it's a game engine based on a node system with multiple-choice dialogue intended for rogue-like or text-adventure games.
The idea behind this was to use .TGA as highres image backdrops which can be assigned on a per-scene base. The backdrop will remain active until a new backdrop information is called by a scene.
Then I have actors which will serve as objects that can be placed dynamically over the backdrop. Those will also be images, however, also have a dummy unit associated with them that can be accessed to display a portrait.
JASS:
library TextAdventure initializer init uses ArrowKeyEvent, ImageTools
/*
requires ArrowKeyEvent by Bribe, which can be found here:
[url]http://www.hiveworkshop.com/forums/jass-resources-412/system-arrowkeyevent-205650/[/url]
requires ImageTools, which can be found here:
[url]http://www.hiveworkshop.com/forums/submissions-414/imagetools-271099/[/url]
*/
globals
private constant real BACKGROUND_RESOLUTION = 1024
private constant real BACKGROUND_X = 0
private constant real BACKGROUND_Y = 0
private constant real CAM_DISTANCE = 1000
private constant real CAM_ANGLE = 270
private constant string PRESELECT_SOUND = "Sound\\Interface\\PickUpItem.wav"
private constant string SELECT_SOUND = "Sound\\Interface\\GamePause.wav"
private boolean IsEngineEnabled = false
private constant integer DUMMY_RAW = 'hfoo'
private real DUMMY_X = 0
private real DUMMY_Y = 0
private unit DUMMY
endglobals
private function EnableCinematicMode takes nothing returns nothing
local real x = BACKGROUND_X+BACKGROUND_RESOLUTION/2
local real y = BACKGROUND_Y+BACKGROUND_RESOLUTION/2
if not IsEngineEnabled then
//create a dummy unit to fix an annoying bug in WC3 in which the first image created is bugged
set DUMMY = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_RAW, DUMMY_X, DUMMY_Y, 0)
call PauseUnit(DUMMY, true)
call UnitAddAbility(DUMMY, 'Aloc')
call ShowUnit(DUMMY, false)
set IsEngineEnabled = true
call CinematicModeExBJ(true, GetForceOfPlayer(GetLocalPlayer()), 0)
call EnableUserControl(true)
call SetCameraPosition(x, y)
call SetCameraBounds(x, y, x, y, x, y, x, y)
call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, CAM_ANGLE, 0)
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, CAM_DISTANCE, 0)
endif
endfunction
private function DisableCinematicMode takes nothing returns nothing
local real x1
local real x2
local real y1
local real y2
if IsEngineEnabled then
call RemoveUnit(DUMMY)
set x1 = GetRectMinX(bj_mapInitialPlayableArea)
set x2 = GetRectMaxX(bj_mapInitialPlayableArea)
set y1 = GetRectMinY(bj_mapInitialPlayableArea)
set y2 = GetRectMaxY(bj_mapInitialPlayableArea)
call CinematicModeExBJ(false, GetForceOfPlayer(GetLocalPlayer()), 0)
call SetCameraBounds(x1, y1, x1, y2, x2, y2, x2, y1)
call ResetToGameCamera(0)
set IsEngineEnabled = false
endif
endfunction
struct Actor
integer portrait
image picture
string picturepath
boolean show
string title
private real x
private real y
private real z
private real sizeX
private real sizeY
static method create takes string name, string imagefile, integer portraitraw, real X, real Y, real Z, real SizeX, real SizeY returns thistype
local thistype this = thistype.allocate()
set this.portrait = portraitraw
set this.picturepath = imagefile
set this.picture = null
set this.title = name
set this.show = false
set this.x = X
set this.y = Y
set this.z = Z
set this.sizeX = SizeX
set this.sizeY = SizeY
return this
endmethod
method draw takes boolean display returns nothing
if display then
if this.picture != null then
call ReleaseImage(this.picture)
if this.picturepath != "" then
set this.picture = NewImage(this.picturepath, this.sizeX, this.sizeY, BACKGROUND_X+this.x, BACKGROUND_Y+this.y, this.z, 2)
call SetImageRenderAlways(this.picture, true)
else
set this.picture = null
endif
else
set this.picture = NewImage(this.picturepath, this.sizeX, this.sizeY, BACKGROUND_X+this.x, BACKGROUND_Y+this.y, this.z, 2)
call SetImageRenderAlways(this.picture, true)
endif
else
if this.picture != null then
call ReleaseImage(this.picture)
set this.picture = null
endif
endif
endmethod
method setPosition takes real X, real Y, real Z returns nothing
set this.x = X
set this.y = Y
set this.z = Z
endmethod
method onDestroy takes nothing returns nothing
if this.picture != null then
call ReleaseImage(this.picture)
endif
set this.picture = null
set this.picturepath = ""
set this.portrait = 0
set this.title = ""
endmethod
endstruct
private struct Node
static thistype current = 0
static integer selected = 0
stub method draw takes nothing returns nothing
endmethod
endstruct
struct Scene extends Node
static thistype lastCreated = 0
string txt
Node nxt
Actor act
static image lastBackground = null
private static thistype previous = 0
private Actor array acts[4]
private boolean clear
private sound audio
private boolean audiocutoff
private image background
private string backgroundpath
private boolean clearbackground
private trigger ondraw
private triggeraction ondrawact
private static Actor array lastAct[4]
static method add takes string text, Actor talker returns thistype
local thistype t = thistype.create()
set thistype.lastCreated = t
set t.txt = text
set t.nxt = 0
set t.act = talker
set t.audio = null
set t.audiocutoff = false
set t.background = null
set t.backgroundpath = ""
set t.clearbackground = false
set t.acts[0] = 0
set t.acts[1] = 0
set t.acts[2] = 0
set t.acts[3] = 0
set t.clear = false
set t.ondraw = null
set t.ondrawact = null
return t
endmethod
method link takes Node next returns thistype
set this.nxt = next
return this
endmethod
method setActors takes Actor first, Actor second, Actor third, Actor fourth returns nothing
set this.acts[0] = first
set this.acts[1] = second
set this.acts[2] = third
set this.acts[3] = fourth
set this.clear = true
endmethod
method registerOnDraw takes code func returns nothing
if this.ondraw != null then
call TriggerRemoveAction(this.ondraw, this.ondrawact)
else
set this.ondraw = CreateTrigger()
endif
set this.ondrawact = TriggerAddAction(this.ondraw, func)
endmethod
method setBackground takes string path returns nothing
set this.backgroundpath = path
set this.clearbackground = true
endmethod
method setAudio takes string path, boolean stopWhenSkipped, integer volume returns nothing
set this.audio = CreateSound(path, false, false, false, 0, 0, "DefaultEAXON")
call SetSoundVolume(this.audio, volume)
set this.audiocutoff = stopWhenSkipped
endmethod
method draw takes nothing returns nothing
local integer i = 0
call EnableCinematicMode()
set Node.current = this
if this.act != 0 then
call SetCinematicScene(this.act.portrait, ConvertPlayerColor(GetPlayerId(GetLocalPlayer())), this.act.title, this.txt, 1000, 0)
else
call SetCinematicScene(0, ConvertPlayerColor(GetPlayerId(GetLocalPlayer())), "", this.txt, 1000, 0)
endif
if this.clear then
loop
exitwhen i >= 4
if thistype.lastAct[i] != 0 then
call thistype.lastAct[i].draw(false)
endif
if this.acts[i] != 0 then
call this.acts[i].draw(true)
set thistype.lastAct[i] = this.acts[i]
endif
set i = i + 1
endloop
endif
if this.clearbackground and thistype.lastBackground != null and thistype.lastBackground != this.background then
call ReleaseImage(thistype.lastBackground)
set thistype.lastBackground = null
endif
if this.backgroundpath != "" then
if this.background != null then
call ReleaseImage(this.background)
endif
set this.background = NewImage(this.backgroundpath, BACKGROUND_RESOLUTION, BACKGROUND_RESOLUTION, BACKGROUND_X, BACKGROUND_Y, 0, 2)
call SetImageRenderAlways(this.background, true)
set thistype.lastBackground = this.background
endif
if this.previous.audio != null and this.previous.audiocutoff then
if GetSoundIsPlaying(this.previous.audio) or GetSoundIsLoading(this.previous.audio) then
call StopSound(this.previous.audio, false, true)
endif
endif
if this.audio != null then
call StartSound(this.audio)
endif
if this.ondraw != null then
call TriggerExecute(this.ondraw)
endif
endmethod
method onDestroy takes nothing returns nothing
set this.txt = ""
set this.nxt = 0
set this.act = 0
set this.acts[0] = 0
set this.acts[1] = 0
set this.acts[2] = 0
set this.acts[3] = 0
set this.clear = false
if this.audio != null then
call KillSoundWhenDone(this.audio)
endif
set this.audio = null
set this.background = null
if this.ondraw != null then
call TriggerRemoveAction(this.ondraw, this.ondrawact)
call DestroyTrigger(this.ondraw)
set this.ondraw = null
set this.ondrawact = null
endif
endmethod
endstruct
struct Choice extends Node
Scene array choices[4]
static Scene parent = 0
static constant sound SELECT = CreateSound(SELECT_SOUND, false, false, true, 12700, 12700, "")
static constant sound PRESELECT = CreateSound(PRESELECT_SOUND, false, false, true, 12700, 12700, "")
method link takes Scene first, Scene second, Scene third, Scene fourth returns thistype
set this.choices[0] = first
set this.choices[1] = second
set this.choices[2] = third
set this.choices[3] = fourth
return this
endmethod
method draw takes nothing returns nothing
local integer i = 0
local string new = ""
set Node.current = this
set new = thistype.parent.txt + "\n"
loop
exitwhen i >= 4
if this.choices[i] != 0 then
if this.selected == i then
set new = new + "\n|cffffcc00> " + this.choices[i].txt + "|r"
else
set new = new + "\n " + this.choices[i].txt
endif
endif
set i = i + 1
endloop
if this.parent.act != 0 then
call SetCinematicScene(this.parent.act.portrait, ConvertPlayerColor(GetPlayerId(GetLocalPlayer())), this.parent.act.title, new, 1000, 0)
else
call SetCinematicScene(0, ConvertPlayerColor(GetPlayerId(GetLocalPlayer())), "", new, 1000, 0)
endif
set new = ""
endmethod
method onDestroy takes nothing returns nothing
set this.choices[0] = 0
set this.choices[1] = 0
set this.choices[2] = 0
set this.choices[3] = 0
endmethod
endstruct
//=================================================
private function enter takes nothing returns nothing
local Scene s
local Choice c
if IsEventArrowKeyPressed() then
if GetEventArrowKey() == ARROW_KEY_RIGHT then
if Node.current != 0 then
if Node.current.getType() == Scene.typeid then
set s = Node.current
if s.nxt != 0 then
if s.nxt.getType() == Scene.typeid then
call s.nxt.draw()
elseif s.nxt.getType() == Choice.typeid then
set c = s.nxt
set Choice.selected = 0
set Choice.parent = s
call c.draw()
endif
else
set Choice.selected = 0
set Choice.parent = 0
set Node.current = 0
call DisableCinematicMode()
endif
elseif Node.current.getType() == Choice.typeid then
set c = Node.current
set s = c.choices[Choice.selected]
if s != 0 then
call s.nxt.draw()
call StartSound(Choice.SELECT)
else
set Choice.selected = 0
set Choice.parent = 0
set Node.current = 0
call DisableCinematicMode()
endif
endif
endif
elseif GetEventArrowKey() == ARROW_KEY_DOWN then
if Node.current.getType() == Choice.typeid then
set c = Node.current
if Choice.selected < 3 and c.choices[Choice.selected+1] != 0 then
set Choice.selected = Choice.selected + 1
call StartSound(Choice.PRESELECT)
endif
call c.draw()
endif
elseif GetEventArrowKey() == ARROW_KEY_UP then
if Node.current.getType() == Choice.typeid then
set c = Node.current
if Choice.selected > 0 then
set Choice.selected = Choice.selected - 1
call StartSound(Choice.PRESELECT)
endif
call c.draw()
endif
endif
endif
endfunction
//=================================================
private function init takes nothing returns nothing
call RegisterArrowKeyEvent(function enter)
endfunction
endlibrary
It is not MPI by design (who would want to play multiplayer adventures anyway?).
Last edited: