Subversion Repositories forest

Compare Revisions

Regard whitespace Rev 1 → Rev 2

/trunk/Forest.DBA
0,0 → 1,1424
rem Nightmare Forest by Daniel Marschall
rem Revision: 31 May 2018
 
rem ---------------------
 
rem SPRUNG-PHYSIK:
rem - wenn man auf einem baum landet, kann man von dort aus nicht springen, und glitched manchmal auf dem boden
rem - im baum wird man trotzdem von skorpionen angefressen
rem ... scheinbar ist die jumpheight = 0 dann!
 
rem Der Himmel ist zu niedrig. Die Tannen sieht man nicht bis ganz oben
 
rem TODO: clone -> INSTANCE
 
rem TODO: scorpion schiebt stehenden spieler nicht weg
 
rem TODO: scorpion soll nicht so nah rankommen, sodass er im spieler stehen würde, wenn der spieler eingeklemmt ist
 
rem TODO: ambient light wird falsch verwendet. es ist viel zu blau, und alle objekte haben es deaktiviert, weil es die farben zerstört
 
rem TODO: screen or desktop?
rem TODO: mehr konfigurierbar machen
rem TODO: alles einrücken
 
rem TODO: lahm?
rem TODO: map außenlinie ist nicht gesperrt mit bäumen
rem TODO: überall float verwenden
 
rem TODO
rem - HUD
rem - schwimmen
rem - im wasser langsamer
rem - menü am anfang und pause mit maus bedienen
rem - rascheln im busch
rem - die gegner kommen erst nach einer bestimmten zeit. spawnen weit weg vom spieler
rem - tag und nachtzeiten?
 
rem NICE TO HAVE
rem - radar breitbild
rem - wassermatrix bewegt sich nur in 1 richtung
rem - mausumkehrung einstellbar
rem - stars.bmp (5000px) braucht lange zum laden. 1000px ist verpixelt
rem - besserer bluteffekt
 
rem ToDo:
rem Radar wackelt
rem :startgame weglassen
rem Streifen am Boden und am Himmel...
rem Baum teiltransparenz
rem Radar lieber als Matrix. Viele Probleme wie z.B. mit Skorpion transparenz
rem Unscharfes Radar, Radar ganz dyn. zeichnen? Rader stay on top
rem Menü: musik aus --> an: loop von position 0!
 
// --------------------------------
// Numerical Resources
// --------------------------------
rem TODO: vervollständigen
rem TODO: auch dateinamen als konstanten
 
#constant IMG_ForestFloor 1
#constant IMG_Stars 2
#constant IMG_Water 3
#constant IMG_Tree 4
#constant IMG_MapBackground 5
#constant IMG_PauseScreen 95
#constant IMG_TitleScreen 96
#constant IMG_BLOOD 97
 
#constant OBJ_Skybox 2
#constant OBJ_Tent 10
#constant OBJ_MapGhostObject 51
#constant OBJ_TreeTemplate 52
#constant OBJ_CollissionDummy 53
#constant OBJ_BloodParticle_Base 100
#constant OBJ_Monster_Base 1000
#constant OBJ_Tree_Base 1500
 
#constant MSH_TreeTemplate 52
 
#constant MAT_Ground 1
#constant MAT_Water 3
 
#constant SFX_ForestBG 1
#constant SFX_PauseMusic 5
#constant SFX_Walk_Earth 10
#constant SFX_Walk_Water 11
#constant SFX_Attack_Base 20
#constant SFX_Monster_Base 1000
 
#constant DLL_MapGen 1
#constant DLL_DBIni 2
#constant DLL_Resize32 3
#constant MEM_Map 1
#constant MEM_ResizeSrc 2
#constant MEM_ResizeDest 3
 
// --------------------------------
// File names
// --------------------------------
 
#constant FN_DLL_Resize32 "dll_resize\Resize32.dll"
#constant FN_DLL_MapGen32 "mapgen\mapgen32.dll"
#constant FN_DLL_DBIni "cfgread\dbini32.dll"
 
#constant FN_SFX_ForestBG "sound\forestbg.wav"
#constant FN_SFX_PauseMusic "music\pause.wav"
#constant FN_SFX_Walk_Earth "sound\walk.wav"
#constant FN_SFX_Walk_Water "sound\walk_water.wav"
#constant FN_SFX_ScorpWalk "test.wav"
#constant FN_SFX_ScorpionAttack1 "sound\scorpionAttack\attack1.wav"
#constant FN_SFX_ScorpionAttack2 "sound\scorpionAttack\attack2.wav"
#constant FN_SFX_ScorpionAttack3 "sound\scorpionAttack\attack3.wav"
#constant FN_SFX_ScorpionAttack4 "sound\scorpionAttack\attack4.wav"
 
#constant FN_OBJ_ScorpIdle "obj\scorpion\ScorpIdle.x"
#constant FN_OBJ_ScorpWalk "obj\scorpion\ScorpWalk.x"
#constant FN_OBJ_Tent "obj\tent\Tent.x"
#constant FN_GFX_PauseScreen "bitmap\titlescreen.jpg"
 
#constant FN_GFX_MapBackground "map\ST01L01a.bmp"
#constant FN_GFX_TitleScreen "bitmap\titlescreen.jpg"
#constant FN_GFX_FloorTexture "bitmap\forest_floor_texture.jpg"
#constant FN_GFX_Stars "bitmap\stars.bmp"
#constant FN_GFX_Water "bitmap\water.bmp"
#constant FN_GFX_Tree "bitmap\tree.bmp"
#constant FN_GFX_BLOOD "bitmap\blood.png"
 
// --------------------------------
// Language specific
// --------------------------------
 
rem TODO: vervollständigen. multilang per DLL
#constant LNG_StartingGame "Starting game..."
 
// --------------------------------
// Read configuration
// --------------------------------
 
load dll FN_DLL_DBIni, DLL_DBIni
call dll DLL_DBIni, "LoadINI", "forest.ini"
framerate = call dll(DLL_DBIni, "ReadInt", "Game", "framerate", 0)
clockSpeedFactor = call dll(DLL_DBIni, "ReadInt", "Game", "clockSpeedFactor", 0)
clockBlinksPerSecond = call dll(DLL_DBIni, "ReadInt", "Game", "clockBlinksPerSecond", 0)
clockShowSeconds = call dll(DLL_DBIni, "ReadInt", "Game", "clockShowSeconds", 0)
beginClockSeconds = call dll(DLL_DBIni, "ReadInt", "Game", "beginClockSeconds", 0)
enemyRotateSmoothness = call dll(DLL_DBIni, "ReadInt", "Game", "enemyRotateSmoothness", 0)
maxRunEnergy = call dll(DLL_DBIni, "ReadInt", "Game", "maxRunEnergy", 0)
waterLevel = call dll(DLL_DBIni, "ReadInt", "Game", "waterLevel", 0)
sound3dVolumeCor = call dll(DLL_DBIni, "ReadInt", "Game", "sound3dVolumeCor", 0)
invertMouse = call dll(DLL_DBIni, "ReadInt", "Game", "invertMouse", 0)
test = call dll(DLL_DBIni, "ReadInt", "Game", "test", 0)
camerarange = call dll(DLL_DBIni, "ReadInt", "Game", "camerarange", 0)
fogdistance = call dll(DLL_DBIni, "ReadInt", "Game", "fogdistance", 0)
waterMovementMaxDistance = call dll(DLL_DBIni, "ReadInt", "Game", "waterMovementMaxDistance", 0)
gravity# = call dll(DLL_DBIni, "ReadFloat", "Game", "gravity", 0.0)
JumpStartVelocity# = call dll(DLL_DBIni, "ReadFloat", "Game", "JumpStartVelocity", 0.0)
MinFallVelocity# = call dll(DLL_DBIni, "ReadFloat", "Game", "MinFallVelocity", 0.0)
collissionboxsize# = call dll(DLL_DBIni, "ReadFloat", "Game", "collissionboxsize", 0.0)
playerEyeHeight# = call dll(DLL_DBIni, "ReadFloat", "Game", "playerEyeHeight", 0.0)
cMaxTrees = call dll(DLL_DBIni, "ReadInt", "Game", "cMaxTrees", 0)
cMapSizeX = call dll(DLL_DBIni, "ReadInt", "Game", "cMapSizeX", 0)
cMapSizeZ = call dll(DLL_DBIni, "ReadInt", "Game", "cMapSizeZ", 0)
cTreeRadius = call dll(DLL_DBIni, "ReadInt", "Game", "cTreeRadius", 0)
cMaxEnemies = call dll(DLL_DBIni, "ReadInt", "Game", "cMaxEnemies", 0)
HitInterval = call dll(DLL_DBIni, "ReadInt", "Game", "HitInterval", 0)
initialEnemySafezone# = call dll(DLL_DBIni, "ReadFloat", "Game", "InitialEnemySafezone", 0.0)
cEnemySpawnMapBorderPadding = call dll(DLL_DBIni, "ReadInt", "Game", "EnemySpawnMapBorderPadding", 0)
call dll DLL_DBIni, "UnloadINI"
delete dll DLL_DBIni
 
rem Setup & Startbildschirm
if check display mode( desktop width(), desktop height(), screen depth() )
set display mode desktop width(), desktop height(), screen depth()
endif
hide mouse
 
Sync On
Sync Rate framerate
 
LoadImageFullscreen(FN_GFX_TitleScreen, IMG_TitleScreen)
 
PASTE IMAGE IMG_TitleScreen, 0, 0
 
rem Sync twice at application start for friendliness with dbpro's double buffering
rem (Required for newer versions of DB Pro)
sync : sync
 
gosub _menu
 
_startgame:
 
ink rgb(255, 230, 0), 0
PASTE IMAGE IMG_TitleScreen, 0, 0
text 28, 550, LNG_StartingGame
 
sync
 
randomize timer()
 
rem Working variables ONLY
JumpKeyStatePrev = 0
JumpPosition# = 0.0
onGround = 1
velocityY# = 0.0
runEnergy# = maxRunEnergy
clockSeconds = beginClockSeconds
collcounter = 0
hits = 0
LastAttackSound = 0
 
draw to front
 
gosub _setup_camera
gosub _create_floor
gosub _setup_player_position
gosub _create_sky
gosub _create_trees
gosub _draw_trees
gosub _create_water
gosub _create_radar
 
rem Bildschirm neu aufbauen
cls
sync
 
rem Lichtversuch
make light 1
 
rem Radar vorbereiten
radarpointcolor = 150
 
gosub _create_enemies
gosub _setupClock
gosub _setup_blood
 
Rem Forest atmo
load sound FN_SFX_ForestBG, SFX_ForestBG
load sound FN_SFX_PauseMusic, SFX_PauseMusic
load sound FN_SFX_Walk_Earth, SFX_Walk_Earth
load sound FN_SFX_Walk_Water, SFX_Walk_Water
 
#constant NumberOfAttackSounds 4
load sound FN_SFX_ScorpionAttack1, SFX_Attack_Base+0
load sound FN_SFX_ScorpionAttack2, SFX_Attack_Base+1
load sound FN_SFX_ScorpionAttack3, SFX_Attack_Base+2
load sound FN_SFX_ScorpionAttack4, SFX_Attack_Base+3
 
LoadImageFullscreen(FN_GFX_PauseScreen, IMG_PauseScreen)
 
#constant SPREAD1_MAX 10
#constant SPREAD2_MAX 15
 
Disable EscapeKey
 
loop sound SFX_ForestBG
 
rem Hauptschleife
do
gosub _handle_weather
gosub _handle_player
gosub _update_trees
gosub _handle_radar
gosub _handle_enemies
gosub _handleClock
gosub _handle_blood
rem TODO: does not work. There is always an attack!
set object collision on OBJ_CollissionDummy
position object OBJ_CollissionDummy, camera position x(), camera position y(), camera position z()
for t = 0 to cMaxEnemies-1
if object collision(OBJ_CollissionDummy, OBJ_Monster_Base+t) = 1
collcounter = collcounter + 1
print "Attacking enemy: ", t
endif
NEXT
print "Collision counter: ", collcounter
set object collision off OBJ_CollissionDummy
if collcounter >= HitInterval
collcounter = 0
inc hits, 1
gosub _play_attack_sound
gosub _splat_blood
endif
print "Hits: ", hits
if EscapeKey() = 1
repeat
sync
until not (EscapeKey() = 1)
gosub _pausemenu
endif
sceneInitialized=1
sync
loop
 
_pausemenu:
gosub _stop_game_sounds
loop sound SFX_PauseMusic
show mouse
repeat
cls
paste image IMG_PauseScreen, 0, 0
rem Text
ink rgb(255,255,255),1
text 100,100,"text"
text 28, 550, "Pause. ESC=Weiter. Runter=Ende."
sync
if DownKey() = 1
goto _exit
ENDIF
UNTIL EscapeKey() = 1
repeat
sync
until not (EscapeKey() = 1)
hide mouse
stop sound SFX_PauseMusic
loop sound SFX_ForestBG
rem TODO: das bringt nix. wenn man die maus bewegt, wird nach der pause die kamera gescrollt
set cursor 0, 0
return
 
_setup_camera:
Set camera range 1, camerarange
AUTOMATIC CAMERA COLLISION 0,collissionboxsize#,0 : rem scorpione stoßen den spieler nicht weg, wenn keine taste gedrückt wird? syntax mit 4 parametern funktioniert im neuen dbpro free nicht!
Autocam off
rem TODO: zylinder
MAKE OBJECT SPHERE OBJ_CollissionDummy, collissionboxsize#
rem hide object OBJ_CollissionDummy
set object collision off OBJ_CollissionDummy
return
 
_setup_player_position:
X# = cMapSizeX / 2
Y# = floorHeight#(X#, Z#) + playerEyeHeight
Z# = cMapSizeZ / 2
position camera X#, Y#, Z#
rem TODO zelt ist winzig klein!
rem TODO zelt ist schwarz schattiert
rem TODO zelt beleuchten
Load object FN_OBJ_Tent, OBJ_Tent
show object OBJ_Tent
scale object OBJ_Tent, 10000, 5000, 5000
position object OBJ_Tent, X#-20, Y#, Z#-10
return
 
_handle_weather:
rem Wetter
color ambient light rgb(64,64,128)
rem set ambient light 1
set ambient light 50
if fog available() = 1
fog on
fog distance fogdistance
fog color rgb(0, 0, 0)
endif
if test = 1
SET MATRIX WIREFRAME ON MAT_Ground
SET MATRIX WIREFRAME ON MAT_Water
endif
rem Stars are moving
scroll object texture OBJ_Skybox, 0.00002, 0
rem Water movement
rem TODO: wasser soll sich langsamer bewegen, aber das ist schwierig. wenn man die bewegung nur zu bestimmten ticks
rem durchführt, dann ruckelt es.
waterdir = (waterdir + 1) mod 360;
watermov = 0 + cos(waterdir)*waterMovementMaxDistance
position matrix MAT_Water, watermov, waterLevel, watermov
return
 
_handle_enemies:
pX# = Camera Position X()
pZ# = Camera Position Z()
rem TODO: gegner sollen sich nicht überschneiden
for t = 0 to cMaxEnemies-1
eX# = Object Position X(OBJ_Monster_Base+t)
eY# = Object Position Y(OBJ_Monster_Base+t)
eZ# = Object Position Z(OBJ_Monster_Base+t)
eRX# = Object Angle X(OBJ_Monster_Base+t)
eRY# = Object Angle Y(OBJ_Monster_Base+t)
eRZ# = Object Angle Z(OBJ_Monster_Base+t)
deltaX# = pX#-eX#
deltaZ# = pZ#-eZ#
 
rem TODO: cor file
yPosOffset# = 20
dist# = sqrt( deltaX#*deltaX# + deltaZ#*deltaZ# )
if clockSeconds > 1
if not sound playing(SFX_Monster_Base+t)
set sound volume SFX_Monster_Base+t, 0
rem TODO: beliebiges startoffset?
loop sound SFX_Monster_Base+t
endif
endif
rem The mixing of 3dsound is bullshit (too loud from far distance, and not very loud on close distance),
rem so we mix the volume ourself
if sound3dVolumeCor>0 and dist#<sound3dVolumeCor then set sound volume SFX_Monster_Base+t, (1-(dist#/sound3dVolumeCor))*100
rem TODO: 100 dynamisch machen
rem at least a distance of 10 so that atanfull() does not bug, when deltas becomes 0
rem Verhindern, dass der Skorpion in einem "drin" steht. Er soll mit den Scheren angreifen
scorpMinDistance = 100
if dist# > scorpMinDistance
if dist# < enemy(t).AwarenessRadius
enemy(t).Angle = atanfull(deltaX#, deltaZ#)
enemy(t).Angle = WrapValue(enemy(t).Angle+180)
enemy(t).CurSpeed = enemy(t).MaxSpeed
else
if enemy(t).WalkTimeout <= 0
enemy(t).WalkTimeout = RndBetween(enemy(t).WalkTimeoutMin, enemy(t).WalkTimeoutMax)
enemy(t).Angle = RndBetween(0,359)
enemy(t).CurSpeed = RndBetween(0, enemy(t).MaxSpeed)
ENDIF
enemy(t).WalkTimeout = enemy(t).WalkTimeout - 1
endif
if enemy(t).CurSpeed = 0
gosub scorpChangeToIdle
else
gosub scorpChangeToWalk
rem TODO: also make animation slower/faster
endif
 
a# = WrapValue(enemy(t).Angle + 180)
XTest# = Newxvalue(eX#, a#, enemy(t).CurSpeed)
ZTest# = Newzvalue(eZ#, a#, enemy(t).CurSpeed)
if XTest# > 0 and XTest# < cMapSizeX then eX# = XTest#
if ZTest# > 0 and ZTest# < cMapSizeZ then eZ# = ZTest#
if XTest# <= 0 or XTest# >= cMapSizeX or ZTest# <= 0 or ZTest# >= cMapSizeZ
rem Kehrtwende, um den Kartenrand zu verlassen
enemy(t).Angle = WrapValue(enemy(t).Angle+180)
enemy(t).WalkTimeout = RndBetween(enemy(t).WalkTimeoutMin, enemy(t).WalkTimeoutMax)
enemy(t).CurSpeed = RndBetween(0, enemy(t).MaxSpeed)
endif
eY# = floorHeight#(eX#, eZ#) + yPosOffset#
Position Object OBJ_Monster_Base+t, eX#, eY#, eZ#
Position Sound SFX_Monster_Base+t, eX#, eY#, eZ#
eRY# = smoothRotate#(eRY#, enemy(t).Angle, enemyRotateSmoothness)
rotate object OBJ_Monster_Base+t, eRX#, eRY#, eRZ#
endif
next
return
 
#constant GROUNDTYPE_AIR 0
#constant GROUNDTYPE_EARTH 1
#constant GROUNDTYPE_WATER 2
rem #constant GROUNDTYPE_DEEPWATER 3
function groundType(onGround, waterLevel)
if onGround = 0
ret = GROUNDTYPE_AIR
else
X# = camera position x()
Z# = camera position z()
if floorHeight#(X#,Z#) > waterLevel
ret = GROUNDTYPE_EARTH
else
ret = GROUNDTYPE_WATER
endif
endif
endfunction ret
 
_handle_player:
set cursor 0, 0
oldcAY# = cAY#
oldcAX# = cAX#
X# = camera position x()
Y# = camera position y()
Z# = camera position z()
 
if invertMouse = 1
cAX# = WrapValue(cAX# - MousemoveY() * 0.2)
else
cAX# = WrapValue(cAX# + MousemoveY() * 0.2)
endif
cAY# = WrapValue(cAY# + MousemoveX() * 0.2)
cAZ# = Camera angle Z()
 
rem Sprungroutine
rem TODO: + Anlaufsprung
JumpKeyStateNow=jumpPressed()
if (JumpKeyStatePrev=0) and (JumpKeyStateNow=1)
gosub PressJumpKey
ENDIF
if (JumpKeyStatePrev=1) and (JumpKeyStateNow=0)
gosub ReleaseJumpKey
ENDIF
JumpKeyStatePrev = JumpKeyStateNow
gosub JumpUpdate
rem Laufen
speedboost# = 1
gt = groundType(onGround, waterLevel)
if upPressed()+downPressed()+leftPressed()+rightPressed() = 0
runEnergy# = runEnergy# + 2
stop sound SFX_Walk_Earth
stop sound SFX_Walk_Water
else
if gt = GROUNDTYPE_EARTH
stop sound SFX_Walk_Water
if not sound playing(SFX_Walk_Earth)
loop sound SFX_Walk_Earth
endif
endif
if gt = GROUNDTYPE_WATER
stop sound SFX_Walk_Earth
if not sound playing(SFX_Walk_Water)
loop sound SFX_Walk_Water
endif
endif
if gt = GROUNDTYPE_AIR
stop sound SFX_Walk_Earth
stop sound SFX_Walk_Water
endif
energyChanged = 0
if ShiftKey()+ControlKey() = 1 : rem shift+control at the same time = walk normal
rem TODO: es ruckelt trotzdem noch
if ControlKey()=1 and runEnergy#>0 : rem Energy >1 , damit es nicht ruckelt (run-walk-run-walk-run-walk) . 3 = walk regain
speedboost# = 2
runEnergy# = runEnergy# - 1
energyChanged = 1
endif
if ShiftKey()=1
speedboost# = 0.5
runEnergy# = runEnergy# + 0.5
energyChanged = 1
endif
endif
if not energyChanged then runEnergy# = runEnergy# + 1
if upPressed()
XTest# = Newxvalue(X#, cAY#, 7*speedboost#)
ZTest# = Newzvalue(Z#, cAY#, 7*speedboost#)
gosub _WorldBoundCheck
endif
if downPressed()
XTest# = Newxvalue(X#, Wrapvalue(cAY# - 180), 5*(speedboost#/2))
ZTest# = Newzvalue(Z#, Wrapvalue(cAY# - 180), 5*(speedboost#/2))
gosub _WorldBoundCheck
endif
if leftPressed()
XTest# = Newxvalue(X#, Wrapvalue(cAY# - 90), 5*(speedboost#/1.3))
ZTest# = Newzvalue(Z#, Wrapvalue(cAY# - 90), 5*(speedboost#/1.3))
gosub _WorldBoundCheck
endif
if rightPressed()
XTest# = Newxvalue(X#, Wrapvalue(cAY# + 90), 5*(speedboost#/1.3))
ZTest# = Newzvalue(Z#, Wrapvalue(cAY# + 90), 5*(speedboost#/1.3))
gosub _WorldBoundCheck
endif
endif
if runEnergy# > maxRunEnergy then runEnergy# = maxRunEnergy
print "Run energy: ", runEnergy#
 
Rem Rotate camera
cTestX# = WrapValue(cAX# - 180)
if cTestX# > 225 then cAX# = 45
if cTestX# < 135 then cAX# = 315
YRotate camera CurveAngle(cAY#, oldcAY#, 24)
XRotate camera CurveAngle(cAX#, oldcAX#, 24)
 
Rem Position Camera
if onGround=1
Y#=floorHeight#(X#, Z#)
else
Y#=JumpPosition#
ENDIF
inc Y#, playerEyeHeight#
Position Camera X#, Y#, Z#
 
Rem Position Listener
Position Listener X#, Y#, Z#
Rotate Listener 0, cAY#, 0 : rem todo warum 0 statt cAZ# etc ?
 
rem Sky sphere follows player
rem position object OBJ_Skybox, X#, Y#, Z#
position object OBJ_Skybox, X#, FloorHeight#(X#,Z#), Z#
rem Sollte man aus irgendeinem Grund die Skybox verlassen, soll man trotzdem zur Erde schauen können
backdrop on
color backdrop rgb(0,0,128) : rem TODO: schwarz + auslagern
set object cull OBJ_Skybox, 1
 
rem texture backdrop IMG_Stars
rem hide object OBJ_Skybox
rem set object fog OBJ_Skybox, 0
 
rem TEST: extend skybox if player jumps
if onGround = 0
jumpheight#=Y#-FloorHeight#(X#,Z#)
else
jumpheight#=0
endif
 
rem TODO: beim springen sieht man am boden den backdrop
rem 500 = die originalgröße der box, vor der ersten scalisierung (setup sky)
rem 600,120,600 = die originale skalierung als referenz
rem *2 , da es von beiden seiten erweitert wird
scalX# = 100.0*(500.0*6.00 + jumpheight#*2)/500.0
scalY# = 100.0*(500.0*1.20 + jumpheight#*2)/500.0
scalZ# = 100.0*(500.0*6.00 + jumpheight#*2)/500.0
scale object OBJ_Skybox, scalX#, scalY#, scalZ#
return
 
_WorldBoundCheck:
if XTest# > 0 and XTest# < cMapSizeX then X# = XTest#
if ZTest# > 0 and ZTest# < cMapSizeZ then Z# = ZTest#
return
_update_trees:
if (ceil(X#) mod 10 = 0) or (ceil(Z#) mod 10 = 0) or (sceneInitialized=0)
for t = 0 to cMaxTrees-1
rx = tree(t).x
rz = tree(t).z
incircle = IsInCircle(rx, rz, X#, Z#, camerarange)
rem incircle = IsInCircle(rx, rz, X#, Z#, fogdistance)
if incircle <> tree(t).drawn
if incircle = 1
if object exist(OBJ_Tree_Base+t)
show object OBJ_Tree_Base+t
else
make object OBJ_Tree_Base+t, MSH_TreeTemplate, IMG_Tree
position object OBJ_Tree_Base+t, rx, floorHeight#(rx, rz)+190, rz
set object OBJ_Tree_Base+t, 1, 1, 0
rotate object OBJ_Tree_Base+t, 0, RndBetween(0,359), 0
endif
else
delete object OBJ_Tree_Base+t
rem hide object OBJ_Tree_Base+t
endif
ENDIF
tree(t).drawn = incircle
next t
endif
return
 
_fademenu:
if fade# > 100 then fadedir = 0
if fade# < 50 then fadedir = 1
if fadedir = 1
fade# = fade# + 2.5
else
fade# = fade# - 2.5
endif
rem Beleuchtet
ink rgb(255, fade#, 0), 0
set text font "Tahoma"
set text size 26
if menu = 1
if pos = 1 then text 260, 255, "Neues Spiel starten"
if pos = 2 then text 260, 285, "Spiel laden"
if pos = 3 then text 260, 315, "Einstellungen"
if pos = 4 then text 260, 345, "Spiel beenden"
endif
if menu = 3
if pos = 1
if sound = 1 then text 260, 255, "Ton: An"
if sound = 0 then text 260, 255, "Ton: Aus"
endif
if pos = 2
if music = 1 then text 260, 285, "Musik: An"
if music = 0 then text 260, 285, "Musik: Aus"
endif
if pos = 3 then text 260, 315, "Hauptmenü"
endif
rem Normal
ink rgb(255, 230, 0), 0
if menu = 1
if pos <> 1 then text 260, 255, "Neues Spiel starten"
if pos <> 2 then text 260, 285, "Spiel laden"
if pos <> 3 then text 260, 315, "Einstellungen"
if pos <> 4 then text 260, 345, "Spiel beenden"
endif
if menu = 3
if pos <> 1
if sound = 1 then text 260, 255, "Ton: An"
if sound = 0 then text 260, 255, "Ton: Aus"
endif
if pos <> 2
if music = 1 then text 260, 285, "Musik: An"
if music = 0 then text 260, 285, "Musik: Aus"
endif
if pos <> 3 then text 260, 315, "Hauptmenü"
endif
sync
return
 
_handle_radar:
rem TODO: the player dot should always stay at the same position
rem TODO: don't show far away enemies
rem Leuchtpunkt
if radarpointrev = 0
inc radarpointcolor, 3
else
dec radarpointcolor, 3
endif
if radarpointcolor > 255
radarpointrev = 1
radarpointcolor = 254
endif
if radarpointcolor < 150
radarpointrev = 0
radarpointcolor = 149
endif
rem Bäume
for t = 0 to cMaxTrees-1
if tree(t).drawn
x = tree(t).x
y = tree(t).z
 
x0 = camera position x()
y0 = camera position z()
ang = camera angle y()
tx = x0 + (x-x0)*cos(ang) - (y-y0)*sin(ang)
ty = y0 + (x-x0)*sin(ang) + (y-y0)*cos(ang)
x = tx
y = ty
x = (x / 62.5) + 7.5
y = screen height() - 7.5 - (y / 62.5)
rem ink rgb(0, radarpointcolor, 0), 0
ink rgb(0, 50, 0), 0
circle x, y, 1
circle x, y, 0
endif
next i
rem Player
x = (X# / 62.5) + 7.5
y = screen height() - 7.5 - (Z# / 62.5)
ink rgb(0, 0, radarpointcolor), 0
circle x, y, 1
circle x, y, 0
rem Enemies
for t = 0 to cMaxEnemies-1
x = object position x(OBJ_Monster_Base+t)
y = object position z(OBJ_Monster_Base+t)
x0 = camera position x()
y0 = camera position z()
ang = camera angle y()
tx = x0 + (x-x0)*cos(ang) - (y-y0)*sin(ang)
ty = y0 + (x-x0)*sin(ang) + (y-y0)*cos(ang)
x = tx
y = ty
x = (x / 62.5) + 7.5
y = screen height() - 7.5 - (y / 62.5)
ink rgb(radarpointcolor, 0, 0), 0
circle x, y, 1
circle x, y, 0
next
return
 
_draw_trees:
rem TODO: da ist ein baum an offset 0,0,0
load image FN_GFX_Tree, IMG_Tree
make object plain OBJ_TreeTemplate, 2*cTreeRadius, 400
make mesh from object MSH_TreeTemplate, OBJ_TreeTemplate
add limb OBJ_TreeTemplate, 1, MSH_TreeTemplate
rotate limb OBJ_TreeTemplate, 1, 0, 90, 0
make mesh from object MSH_TreeTemplate, OBJ_TreeTemplate
delete object OBJ_TreeTemplate
return
 
_create_trees:
dim tree(cMaxTrees-1) as treeType
remstart
for t = 0 to cMaxTrees-1
tree(t).x = RndBetween(0, cMapSizeX)
tree(t).z = RndBetween(0, cMapSizeZ)
tree(t).drawn = 0
NEXT
remend
rem TODO: wegbreite definieren
load dll FN_DLL_MapGen32, DLL_MapGen
call dll DLL_MapGen, "LoadParametersFromINI", "forest.ini"
 
load dll FN_DLL_DBIni, DLL_DBIni
call dll DLL_DBIni, "LoadINI", "seed.ini"
onetimeseed = call dll(DLL_DBIni, "ReadInt", "Seed", "onetime", 0)
staticseed = call dll(DLL_DBIni, "ReadInt", "Seed", "value", 0)
seedactive = call dll(DLL_DBIni, "ReadInt", "Seed", "active", 0)
IF (onetimeseed = 1) AND (seedactive = 1)
call dll DLL_DBIni, "WriteInt", "Seed", "active", 0
ENDIF
IF seedactive
call dll DLL_MapGen, "UseSeed", staticseed
ELSE
call dll DLL_MapGen, "RandomSeed"
ENDIF
call dll DLL_DBIni, "UnloadINI"
delete dll DLL_DBIni
make memblock MEM_Map, cMaxTrees*8
call dll DLL_MapGen, "GenerateMap", cMaxTrees, cTreeRadius, cMapSizeX, cMapSizeZ, get memblock ptr(MEM_Map), 0
for t = 0 to cMaxTrees-1
tree(t).x = memblock dword(MEM_Map, t*8)
tree(t).z = memblock dword(MEM_Map, t*8+4)
tree(t).drawn = 0
NEXT
delete memblock MEM_Map
delete dll DLL_MapGen
return
 
_menu:
PASTE IMAGE IMG_TitleScreen, 0, 0
set text font "times"
set text size 27
fade = 100
pos = 1
menu = 1
sound = 1
do
gosub _fademenu
if ( downkey() = 1 and pos < 4 and menu = 1 ) or ( downkey() = 1 and pos < 3 and menu = 3 )
inc pos
while downkey() = 1
gosub _fademenu
endwhile
endif
if upkey() = 1 and pos > 1
dec pos
while upkey() = 1
gosub _fademenu
endwhile
endif
if returnkey() = 1
if menu = 1
if pos = 1 then gosub _startgame
if pos = 2
rem PASTE IMAGE IMG_TitleScreen, 0, 0
rem menu = 2
rem pos = 1
endif
if pos = 3
PASTE IMAGE IMG_TitleScreen, 0, 0
menu = 3
pos = 1
endif
if pos = 4 then end
else
if menu = 3
if pos = 1
if sound = 1
sound = 0
else
sound = 1
endif
PASTE IMAGE IMG_TitleScreen, 0, 0
endif
if pos = 2
if music = 1
music = 0
else
music = 1
endif
PASTE IMAGE IMG_TitleScreen, 0, 0
endif
if pos = 3
PASTE IMAGE IMG_TitleScreen, 0, 0
menu = 1
pos = 1
endif
endif
endif
while returnkey() = 1
gosub _fademenu
endwhile
endif
loop
return
 
_create_enemies:
dim enemy(cMaxEnemies-1) as enemyType
for t = 0 to cMaxEnemies-1
if t=0
Load 3Dsound FN_SFX_ScorpWalk,SFX_Monster_Base+t
else
Clone Sound SFX_Monster_Base+t, SFX_Monster_Base
endif
 
pX# = Camera Position X()
pY# = Camera Position Y()
pZ# = Camera Position Z()
 
repeat
eX# = RndBetween(cEnemySpawnMapBorderPadding, cMapSizeX-cEnemySpawnMapBorderPadding)
eZ# = RndBetween(cEnemySpawnMapBorderPadding, cMapSizeZ-cEnemySpawnMapBorderPadding)
deltaX# = pX#-eX#
deltaZ# = pZ#-eZ#
dist# = sqrt( deltaX#*deltaX# + deltaZ#*deltaZ# )
rem Prevent that the enemies spawn right at the player (5000/5000)
until dist# >= initialEnemySafezone#
enemy(t).AwarenessRadius = RndBetween(600, 1300)
enemy(t).MaxSpeed = RndBetween(1, 4)
enemy(t).WalkTimeoutMin = 200
enemy(t).WalkTimeoutMax = 300
if t = 0
animScorpIdleStart = 0
Load object FN_OBJ_ScorpIdle, OBJ_Monster_Base+t
animScorpIdleEnd = total object frames(OBJ_Monster_Base+t)
animScorpWalkStart = animScorpIdleEnd+1
Append object FN_OBJ_ScorpWalk, OBJ_Monster_Base+t, animScorpWalkStart
animScorpWalkEnd = total object frames(OBJ_Monster_Base+t)
else
Clone Object OBJ_Monster_Base+t, OBJ_Monster_Base
endif
eY# = floorHeight#(eX#, eZ#) : rem TODO + yPosOffset#
position object OBJ_Monster_Base+t, eX#, eY#, eZ#
Position Sound SFX_Monster_Base+t, eX#, eY#, eZ#
fix object pivot OBJ_Monster_Base+t
gosub scorpChangeToWalk
set object collision on OBJ_Monster_Base+t
NEXT
return
 
scorpChangeToIdle:
rem TODO: smoothness (interpolation)
if enemy(t).CurrentAnim <> 1
loop object OBJ_Monster_Base+t, animScorpIdleStart, animScorpIdleEnd
enemy(t).CurrentAnim = 1
endif
return
 
scorpChangeToWalk:
rem TODO: smoothness (interpolation)
if enemy(t).CurrentAnim <> 2
loop object OBJ_Monster_Base+t, animScorpWalkStart, animScorpWalkEnd
enemy(t).CurrentAnim = 2
endif
return
 
_setupClock:
set text font "arial" : set text size 30 : set text transparent
// Session variables
clockTickCounter=0
clockCurrentMidDot=0
clockTicksPerSecond = framerate
return
 
_handleClock:
if mod(clockTickCounter*clockBlinksPerSecond, clockTicksPerSecond) = 0
clockCurrentMidDot = 1 - clockCurrentMidDot
endif
if mod(clockTickCounter*clockSpeedFactor, clockTicksPerSecond) = 0
clockSeconds = clockSeconds + 1
endif
gosub _printClock
 
clockTickCounter = clockTickCounter + 1
RETURN
 
_create_water:
make matrix MAT_Water, cMapSizeX+2*waterMovementMaxDistance, cMapSizeZ+2*waterMovementMaxDistance, 15, 15
load image FN_GFX_Water, IMG_Water
prepare matrix texture MAT_Water, IMG_Water, 1, 1
fill matrix MAT_Water, 0, 1
position matrix MAT_Water, 0, waterLevel, 0
ghost matrix on MAT_Water
set matrix MAT_Water, 0, 0, 1, 1, 1, 1, 1
update matrix MAT_Water
return
 
_create_floor:
rem Boden
make matrix MAT_Ground, cMapSizeX, cMapSizeZ, 15, 15
 
load image FN_GFX_FloorTexture, IMG_ForestFloor
prepare matrix texture MAT_Ground, IMG_ForestFloor, 1, 1
fill matrix MAT_Ground, 0, 1
set matrix MAT_Ground, 0, 0, 1, 1, 1, 1, 1
randomize matrix MAT_Ground, 130
rem TEST
rem TODO: aber man kann 40,40 nicht updaten?!
set matrix height MAT_Ground, 10, 10, 1000
update matrix MAT_Ground
remstart
currentmatrix=1
for z=1 to 20
for x=1 to 20
rem Get matrix heights
rem print x, " - ", z
rem sync
rem sleep 100
h8#=get matrix height(currentmatrix,x,z-1)
h4#=get matrix height(currentmatrix,x-1,z)
h#=get matrix height(currentmatrix,x,z)
h2#=get matrix height(currentmatrix,x,z)
rem Calculate projected angle X using heights
x1#=(x-1)*25.0 : y1#=h#
x2#=(x+0)*25.0 : y2#=h4#
dx#=x2#-x1#
dy#=y2#-y1#
ax#=atanfull(dx#,dy#)
ax#=wrapvalue(90-ax#)
rem Calculate projected angle Z using heights
z1#=(z-1)*25.0 : y1#=h2#
z2#=(z+0)*25.0 : y2#=h8#
dz#=z2#-z1#
dy#=y2#-y1#
az#=atanfull(dz#,dy#)
az#=wrapvalue(90-az#)
rem Make normal from projected angle
nx#=sin(ax#)
ny#=cos(ax#)
nz#=sin(az#)
rem Setting matrix normal for smoothness
set matrix normal currentmatrix,x,z,nx#,ny#,nz#
next x
next z
update matrix currentmatrix
remend
return
 
_create_sky:
if test = 1
load image FN_GFX_Tree, IMG_Stars : rem Any small picture - it doesn't matter since we only show wireframe
else
load image FN_GFX_Stars, IMG_Stars
endif
 
rem TODO: landsize undefined
make object sphere OBJ_Skybox, (landsize * 2) - 500
 
rem make object sphere OBJ_Skybox, -4000
set object collision off OBJ_Skybox
rem scale object OBJ_Skybox, 2000, 750, 2000
scale object OBJ_Skybox, 600, 120, 600
set object OBJ_Skybox, 1, 0, 0, 0, 0, 1, 1
texture object OBJ_Skybox, IMG_Stars
rem fade object OBJ_Skybox, 0
if test = 1
backdrop on
set object wireframe OBJ_Skybox, 1
else
backdrop off
endif
return
 
_create_radar:
rem Karte - Abstand zur Kamera: 1.1
remstart
load image FN_GFX_MapBackground, IMG_MapBackground
make object plain OBJ_MapGhostObject, 0.352, 0.352
lock object on OBJ_MapGhostObject
position object OBJ_MapGhostObject, -0.6908, -0.4675, 1.1
ghost object on OBJ_MapGhostObject
texture object OBJ_MapGhostObject, IMG_MapBackground
remend
rem Karte - Abstand zur Kamera: 1.5
load image FN_GFX_MapBackground, IMG_MapBackground
make object plain OBJ_MapGhostObject, 0.48, 0.48
lock object on OBJ_MapGhostObject
position object OBJ_MapGhostObject, -0.942, -0.6375, 1.5
ghost object on OBJ_MapGhostObject
texture object OBJ_MapGhostObject, IMG_MapBackground
return
 
_printClock:
if clockCurrentMidDot = 0
middle$ = " "
else
middle$ = ":"
endif
mind = clockSeconds/60
hours = mind/60
if clockShowSeconds
secsText$ = middle$+TwoDigit$(mod(clockSeconds,60))
else
secsText$ = ""
endif
print "Time: ", TwoDigit$(mod(hours,24)), middle$, TwoDigit$(mod(mind,60)), secsText$
return
 
rem Rotate smooth, and rotate in the direction with the lowest distance
rem "turn object left" ist das kommando
function smoothRotate#(von#, nach#, smoothness)
if (von# > 270) and (nach# < 90)
ret# = WrapValue(von# + (360 - von# + nach#)/smoothness)
else
if (von# < 90) and (nach# > 270)
ret# = WrapValue(von# - (360 - nach# + von#)/smoothness)
else
ret# = von# + (nach# - von#)/smoothness
endif
endif
endfunction ret#
 
function floorHeight#(X#, Z#)
rem TODO: implement water
ret# = Get Ground Height(MAT_Ground, X#, Z#)
ENDFUNCTION ret#
 
function upPressed()
ret = UpKey()=1 or keystate(17)=1 or joystick up()=1
ENDFUNCTION ret
 
function leftPressed()
ret = LeftKey()=1 or keystate(30)=1 or joystick left()=1
ENDFUNCTION ret
 
function rightPressed()
ret = RightKey()=1 or keystate(32)=1 or joystick right()=1
ENDFUNCTION ret
 
function downPressed()
ret = DownKey()=1 or keystate(31)=1 or joystick down()=1
ENDFUNCTION ret
 
function jumpPressed()
ret = keystate(57)=1 or JOYSTICK FIRE A()=1
ENDFUNCTION ret
 
function TwoDigit$(value)
if value < 10
ret$ = "0"+STR$(value)
else
ret$ = STR$(value)
ENDIF
ENDFUNCTION ret$
 
function mod(num,modulus)
value=num-((num/modulus)*modulus)
endfunction value
 
function fileReadInt(fileNum)
read string 1, s$
ret=val(s$)
ENDFUNCTION ret
 
function fileReadFloat#(fileNum)
read string 1, s$
ret#=val(s$)
ENDFUNCTION ret#
 
function RndBetween(a,b)
ret = a+Rnd(b-a)
ENDFUNCTION ret
 
function isInCircle(pX#,pY#,cX#,cY#,cR#)
ret = sqrt( (pX#-cX#)*(pX#-cX#) + (pY#-cY#)*(pY#-cY#) ) <= cR#
ENDFUNCTION ret
 
_stop_game_sounds:
Stop Sound SFX_ForestBG
Stop Sound SFX_PauseMusic
Stop Sound SFX_Walk_Earth
Stop Sound SFX_Walk_Water
for t = 0 to cMaxEnemies-1
Stop Sound SFX_Monster_Base+t
next t
return
 
type treeType
x as float
z as float
drawn as boolean
endtype
 
type enemyType
Speed as float
WalkTimeout as float
WalkTimeoutMin as float
WalkTimeoutMax as float
AwarenessRadius as float
CurSpeed as float
MaxSpeed as float
Angle as float
CurrentAnim as float
endtype
 
PressJumpKey:
if onGround=1
rem TODO: absprungsound
JumpPosition#=floorHeight#(X#,Z#)
velocityY# = JumpStartVelocity#
onGround = 0
endif
return
 
ReleaseJumpKey:
if velocityY# > MinFallVelocity#
velocityY# = MinFallVelocity#
endif
return
 
JumpUpdate:
if onGround=0
dec velocityY#, gravity#
inc JumpPosition#, velocityY#
rem TODO: man kann sich dann durch die decke glitchen
curFloorHeight# = floorHeight#(X#,Z#)
if JumpPosition# < curFloorHeight#
rem TODO: aufprallsound
JumpPosition# = curFloorHeight#
velocityY# = 0.0
onGround = 1
endif
endif
return
 
function resizeImage(image as dword, width as dword, height as dword)
if DLL EXIST(DLL_Resize32) = 0
load dll FN_DLL_Resize32, DLL_Resize32
endif
make memblock from image MEM_ResizeSrc, image
size = call dll(DLL_Resize32, "DestSize", get memblock ptr(MEM_ResizeSrc), width, height)
make memblock MEM_ResizeDest, size
 
call dll DLL_Resize32, "Resize", get memblock ptr(MEM_ResizeSrc), get memblock ptr(MEM_ResizeDest), width, height
make image from memblock image, MEM_ResizeDest
delete memblock MEM_ResizeSrc
delete memblock MEM_ResizeDest
REM delete dll DLL_Resize
 
endfunction
 
function LoadImageFullscreen(imgFN as string, imgID)
Load Image imgFN, imgID
width = desktop width()
height = image height(imgID)*desktop width()/1.0/image width(imgID);
resizeImage(imgID, width, height)
ENDFUNCTION
 
_play_attack_sound:
repeat
r=RndBetween(0,NumberOfAttackSounds-1)
UNTIL (r <> LastAttackSound) or (NumberOfAttackSounds = 1)
LastAttackSound=r
play sound SFX_Attack_Base+r
return
 
_setup_blood:
// Make 100 particle objects
particleIndex = 0
#constant PARTICLEMAX = 500
dim particle(PARTICLEMAX) as particleType
rem TODO: mehr
rem http://nobacks.com/blood-splatter-eighty-eight/
load image FN_GFX_BLOOD, IMG_BLOOD
for i = 0 to PARTICLEMAX-1
make object plain OBJ_BloodParticle_Base+i, 2, 2
set object ambient OBJ_BloodParticle_Base+i, 0
set object collision off OBJ_BloodParticle_Base+i
rem color object OBJ_BloodParticle_Base+i, rgb(128, 0, 0)
texture object OBJ_BloodParticle_Base+i, IMG_BLOOD
set object cull OBJ_BloodParticle_Base+i, 0
set object transparency OBJ_BloodParticle_Base+i, 6
rem TEST
rem rotate object OBJ_BloodParticle_Base+i, RndBetween(0,359), RndBetween(0,359), RndBetween(0,359)
exclude object on OBJ_BloodParticle_Base+i
next i
return
 
_handle_blood:
// Update particles
for i = 0 to PARTICLEMAX-1
UpdateParticle(i)
next i
return
 
_splat_blood:
rem https://forum.thegamecreators.com/thread/160210#msg1886513 , modified
rem TODO: sieht einfach nur scheiße aus. außerdem ist der strahl in 2 himmelsrichtungen schmal (seitlich)
rem yoff = rnd(SPREAD1_MAX*2)-SPREAD1_MAX;
 
// Activate blood particles around box
for i = 0 to PARTICLEMAX-1
// The angle particles should fly
a#=camera angle y()
rem yAng# = a#+rnd(SPREAD2_MAX*2)-SPREAD2_MAX+yoff
yAng#=a#
 
// Calculate directions
xSpeed# = sin(yAng#)
zSpeed# = cos(yAng#)
// Calculate speeds
xSpeed# = xSpeed# * (rnd(20)/5.0)
ySpeed# = ((rnd(20)-rnd(20))/10.0)
zSpeed# = zSpeed# * (rnd(20)/5.0)
// Activate particle
x# = camera position x()
y# = camera position y()
z# = camera position z()
life = 30+rnd(30)
particleIndex = ActivateParticle(particleIndex, life, x#, y#, z#, xSpeed#, ySpeed#, zSpeed#)
next i
return
// Activate the specified particle and give it an initial position/velocity
function ActivateParticle(i, life, x#, y#, z#, xSpeed#, ySpeed#, zSpeed#)
// Cycle through the particle objects to use
inc i
if i > PARTICLEMAX-1 then dec i, PARTICLEMAX-1
// Set particle variables
particle(i).life = life
particle(i).x = x#
particle(i).y = y#
particle(i).z = z#
particle(i).xSpeed = xSpeed#
particle(i).ySpeed = ySpeed#
particle(i).zSpeed = zSpeed#
// Show particle object
exclude object off OBJ_BloodParticle_Base+i
endfunction i
// Update positioning for specified particle
function UpdateParticle(i)
// Only update particles that are alive
if particle(i).life > 0
// Apply gravity
rem dec particle(i).ySpeed, 0.098
dec particle(i).ySpeed, 0.200
// Move the particle
inc particle(i).x, particle(i).xSpeed
inc particle(i).y, particle(i).ySpeed
inc particle(i).z, particle(i).zSpeed
// Position particle
position object OBJ_BloodParticle_Base+i, particle(i).x, particle(i).y, particle(i).z
rem point object OBJ_BloodParticle_Base+i, camera position x(), camera position y(), camera position z()
 
 
// Lower particle's life
dec particle(i).life
// Hide particles when they die
if particle(i).life <= 0
exclude object on OBJ_BloodParticle_Base+i
endif
endif
endfunction
// Data type used by particles
type particleType
life as integer // Remaining life of particle (0=Dead)
x as float // Position
y as float // ...
z as float // ...
xSpeed as float // Velocity
ySpeed as float // ...
zSpeed as float // ...
endtype
 
rem -- MUST STAY AT THE END OF THE PROGRAM --
_exit:
exit