Retro Remakes 2006

Previous topic - Next topic

Kitty Hello


Baggi

Hört sich nicht schlecht an der Wettbewerb.

Baggi

Hey Gernot,

es gibt bei dem Wettbewerb ja ein GLBasic zu gewinnen, cool.

Ich würde gerne mitmachen, habe auch schon eine Idee und auch schon den Helden des Spiels modelliert, aber wahrscheinlich bekomme ich das Spiel nicht fertig.

Machst du mit?

Kitty Hello

Klar. Mit einem Freund zusammen. Such mal nach "Rock Bolt"

Baggi

Wow, das sieht ja richtig geil aus. Bin gespannt.

Ich kenn das original Spiel nicht?

Kitty Hello


mannybass

Hi Gernot, das Spiel scheint toll geworden zu sein. Die Screenshots sehen klasse aus. Kann man den  endgültigen source code irgendwo bekommen?

Kitty Hello

Hm... Der Code ist hier:
Code (glbasic) Select
// --------------------------------- //
// Project: Rock 'N Bolt
// Start: Monday, June 05, 2006
// IDE Version: 3.138


// Drehricthung!



// That thingy is a platform. Moving/Locked/static - anything
TYPE PLATFORM
// position (currently)
x
y
// how much did the PF move this frame?
dx; dy
// state bits (see ShowLevel)
state

direction // positive or negative

// 1=left.top, 2=bottom.right
fixbits

// minimum/maximum position
// plafrom will move in a since curve between these
minx; miny
maxx; maxy

// extension of the platform (should be >= 1 )
extx; exty
ENDTYPE

// This is about the player(s)?
TYPE player
x; y; dir  // x,y pos, direction
anitime
drillx; drilly // where he is after drilling
life  // lives
state // state bits - see MovePlayers
on_pf // on what platform have I been -> don't fall!
drilltime // how much time left for drilling (-1/+1 if any)
drilldir  // what direction to rotate
ENDTYPE

// This is just a game structure to keep things at one place
TYPE GAME
pads[] AS PLATFORM
plys[] AS player
startx; starty // starting position (that is: the elevator)
level          // level index
mapview        // 0 normal, 1 mapview
leveldone      // done?
remote_pos     // ypos of remote (1=off, 0=on)

forcemap       // must assemble correctly
levelokani     // a counter from 0-1if the level is done
timeleft       // how  much time is left [sec]
timepanik      // playing panic music?
startlevel     // 0,1,2 -> start at different stages
difficulty=1   // 0,1,2 -> just the time factor
life           // number of lives
dollars        // day's wage
details=1      // true/false for city
ENDTYPE

GLOBAL thegame AS GAME
GLOBAL gameon // or gameover?
GLOBAL screenx, screeny
GLOBAL thistime
GETSCREENSIZE screenx, screeny

// load + Display Splash screen at first thing you do
BLACKSCREEN
SHOWSCREEN
LOADBMP "gfx/splash.bmp"
SHOWSCREEN
LOCAL thistime = GETTIMERALL()+5000

X_LOADOBJ "gfx/stahltraeger.ddd", 0;  LOADSPRITE "gfx/stahltraeger.bmp", 0
X_LOADOBJ "gfx/stahltraeger_mitte.ddd", 1;  LOADSPRITE "gfx/stahltraeger_static.bmp", 1
X_LOADOBJ "gfx/stahltraeger_seite.ddd", 2
X_LOADOBJ "gfx/boden.ddd", 3
X_LOADOBJ "gfx/aufzug.ddd", 4
X_LOADOBJ "gfx/remote.ddd", 5 ; LOADSPRITE "gfx/remote.bmp", 5
X_LOADOBJ "gfx/schraube.ddd",     10; LOADSPRITE "gfx/schraube.bmp", 10

// show splash screen (at least 5 secs)
LOCAL fps
GETFILE "limitfps.txt", 0, fps
IF fps <> 0 THEN LIMITFPS fps
WHILE GETTIMERALL() < thistime AND KEY(57)=FALSE AND MOUSEAXIS(3)=FALSE
SHOWSCREEN
WEND

// fading from splash is not allowed...
BlendBmp("", "gfx/GMDesign.bmp")
 LOADSPRITE "gfx/schraube_doof.bmp", 11
X_LOADOBJ "gfx/rodney.ddd",     20;   LOADSPRITE "gfx/rodney.bmp", 20
// map = 100
X_LOADOBJ "gfx/skydome.ddd",   200;   LOADSPRITE "gfx/hintergrund.bmp", 200
X_LOADOBJ "gfx/skydome-sky.ddd",   201; LOADSPRITE "gfx/hintergrund_sky.bmp", 201
X_LOADOBJ "gfx/skydome-superman.ddd",   202; LOADSPRITE "gfx/superman.bmp", 202
X_LOADOBJ "gfx/Stadt.ddd", 203; LOADSPRITE "gfx/Stadt.bmp", 203


BlendBmp("gfx/GMDesign.bmp", "gfx/Credits.bmp")

X_LOADOBJ "gfx/logo.ddd",   300

X_LOADOBJ "gfx/status_01.ddd", 301 // life
X_LOADOBJ "gfx/status_02.ddd", 302 // time
LOADSPRITE "gfx/wecker.bmp", 302
X_LOADOBJ "gfx/status_03.ddd", 303 // $

BlendBmp("gfx/Credits.bmp", "gfx/hintergrund.bmp")
LOADSOUND "sfx/festmachen.wav", 0,2
LOADSOUND "sfx/loesen.wav", 1,2
LOADSOUND "sfx/elevator.wav", 2,1
LOADSOUND "sfx/bell.wav", 3,4




// MAINGAME
// -----------------------------

WHILE TRUE
TitleScreen()
MainGame()
WEND



// -----------------------------
// Like Blendscreen
// -----------------------------
FUNCTION BlendBmp: fileold$, filenew$
GLOBAL skip_blend
LOCAL good[], img, dt, start, best, time
DIM good[2]
BLACKSCREEN
IF skip_blend THEN RETURN

IF DOESFILEEXIST(fileold$)
LOADSPRITE fileold$, 500
ELSE
GRABSPRITE 500,0,0,16,16
ENDIF

IF DOESFILEEXIST(filenew$)
LOADSPRITE filenew$, 501
ELSE
GRABSPRITE 501,0,0,16,16
ENDIF

start = GETTIMERALL()
time=start
best = start + 3000

WHILE time IF Joypad(0, 2) THEN skip_blend  =TRUE
IF skip_blend THEN RETURN
dt = MIN(1, (time-start)/(best-start))
FOR img=0 TO 1
IF img = 0 THEN ALPHAMODE MIN(-.01, MAX(-1, -(1 - dt) ))
IF img = 1 THEN ALPHAMODE MIN(-.01, MAX(-1,     - dt  ))
STRETCHSPRITE 500+img, 0, 0, screenx, screeny
ALPHAMODE 0
NEXT

SHOWSCREEN
time = GETTIMERALL()
WEND
ALPHAMODE 0
ENDFUNCTION


// -----------------------------
// MAINGAME
// -----------------------------
FUNCTION MainGame:
GLOBAL gameon
LOCAL time$, mins, secs, lasttime

LOADFONT "bigfont.bmp", 0

thegame.life = 3
thegame.dollars = 0
thegame.level = thegame.startlevel * 5 +1
LoadLevel(thegame.level)

gameon  = TRUE
WHILE gameon
lasttime = thistime
thistime = GETTIMERALL()
MovePlatforms()
MovePlayers(thistime - lasttime)
ShowLevel3D(0)
// X_MAKE2D; ShowLevel(0)

X_MAKE2D
PRINT "Crsr  to Move", 0,0
PRINT "LCtrl to Screw", 0,20

SHOWSCREEN
WEND
ENDFUNCTION


// -----------------------------------------
// Sketch - Draw a "free hand line"
// -----------------------------------------
FUNCTION Sketch: x1,y1, dx, dy, striplen, overlen, noise, col
LOCAL phi, dist, cx, cy, noisex, noisey
phi=ATAN(dy,dx) + (RND(2000)/1000 -1 )*noise
dist=SQR(dx*dx+dy*dy) * 0.5
cx=x1+dx/2
cy=y1+dy/2

IF dist*2 > striplen AND striplen > 1
dx=dx/2
dy=dy/2
Sketch(x1,y1, dx,dy, striplen, overlen, noise, col)
Sketch(cx,cy, dx,dy, striplen, overlen, noise, col)
DRAWLINE x1,y1, x1+dx, y1+dy, col
RETURN
ENDIF

INC dist, overlen
noisex = SIN(phi)*(RND(2000)/800-1)
noisey = COS(phi)*(RND(2000)/800-1)

DRAWLINE cx,cy, cx+COS(phi)*dist+noisex, cy+SIN(phi)*dist+noisey, col
DRAWLINE cx,cy, cx-COS(phi)*dist+noisex, cy-SIN(phi)*dist+noisey, col
ENDFUNCTION

// -----------------------------------------
// SkArrow - Draw a "free hand arrow" from x1 to x2
// -----------------------------------------
FUNCTION SkArrow: x1,y1, x2,y2, striplen, overlen, noise, col
LOCAL dx, dy, l, i
dx = x2-x1
dy = y2-y1
Sketch(x1,y1, dx, dy, striplen, overlen, noise, col)

l = SQR(dx*dx + dy*dy)
dx=dx*4/l
dy=dy*4/l
FOR i=0 TO 32
Sketch(x1,y1, dx, dy, dx+dy, 0, 65, col)
Sketch(x2,y2,-dx,-dy, dx+dy, 0, 65, col)
NEXT
ENDFUNCTION

// -----------------------------------------
// GETPOW2 - Get smallest number that's 2^m and >= n
// -----------------------------------------
FUNCTION GetPow2: n
LOCAL x
x=1
WHILE x x=x+x
WEND
RETURN x
ENDFUNCTION

// -----------------------------------------
// CREATEMAP
// -----------------------------------------
FUNCTION CreateMap: spr_id
LOCAL i, scale, x,y, sx, sy, fix$
LOCAL col_bk, col_drw, col_arr
LOCAL overlen, striplen, noise, iy, ix
LOCAL sprx, spry, q

col_bk =  RGB(0x00, 0x00, 0xf0)
col_drw = RGB(0x60, 0x60, 0xf6)
col_arr = RGB(0xff, 0xff, 0xff)

// platform collision = 1x1 unit
// scaling of gfx is just for better visibility
scale = screenx/32

FILLRECT 0,0,screenx, screeny, col_bk

// pads
overlen = scale*.08
striplen= scale*.7
noise   = 1

FOR i=0 TO BOUNDS(thegame.pads[], 0)-1
sx= thegame.pads[i].extx
sy= thegame.pads[i].exty

q=4
// move-to position
IF thegame.pads[i].minx<>thegame.pads[i].maxx OR thegame.pads[i].miny<>thegame.pads[i].maxy
x = INTEGER(thegame.pads[i].maxx * scale)+1
y = INTEGER(thegame.pads[i].maxy * scale)+1
Sketch(x,y, sx*scale-q, 0, striplen, overlen, noise, col_drw)
Sketch(x,y, 0, sy*scale-q, striplen, overlen, noise, col_drw)
Sketch(x,y+sy*scale-q, sx*scale-q, 0, striplen, overlen, noise, col_drw)
Sketch(x+sx*scale-q,y, 0, sy*scale-q, striplen, overlen, noise, col_drw)
Sketch(x,y, sx*scale-q, sy*scale-q, striplen, overlen, noise, col_drw)
ENDIF

// must be position / or static one
x = INTEGER((thegame.pads[i].minx+.1) * scale)+1
y = INTEGER((thegame.pads[i].miny+.1) * scale)+1
Sketch(x,y, sx*scale-q, 0, striplen, overlen, noise, col_arr)
Sketch(x,y, 0, sy*scale-q, striplen, overlen, noise, col_arr)
Sketch(x,y+sy*scale-q, sx*scale-q, 0, striplen, overlen, noise, col_arr)
Sketch(x+sx*scale-q,y, 0, sy*scale-q, striplen, overlen, noise, col_arr)

// moving arrow
IF thegame.pads[i].minx<>thegame.pads[i].maxx OR thegame.pads[i].miny<>thegame.pads[i].maxy
x = INTEGER((thegame.pads[i].minx+.1) * scale)+1
y = INTEGER((thegame.pads[i].miny+.1) * scale)+1
INC x, sx/2*scale
INC y, sy/2*scale
ix = INTEGER((thegame.pads[i].maxx+sx/2) * scale)
iy = INTEGER((thegame.pads[i].maxy+sy/2) * scale)
SkArrow(x,y,ix,iy,striplen*2, overlen/2, noise/2, col_drw)
ENDIF

// hatching of static position
IF thegame.forcemap
x = INTEGER((thegame.pads[i].minx+.1) * scale)+1
y = INTEGER((thegame.pads[i].miny+.1) * scale)+1
VIEWPORT x+1,y+1,sx*scale-q, sy*scale-q
FOR iy=-(sx+sy)*scale TO sy*scale STEP scale/4
IF thegame.pads[i].minx<>thegame.pads[i].maxx OR thegame.pads[i].miny<>thegame.pads[i].maxy
Sketch(0,iy,sx*scale,sx*scale, striplen, overlen, noise, col_drw)
ELSE
// Sketch(0,iy,sx*scale,sx*scale*.5, striplen, overlen, noise, col_arr)
INC iy, scale/6
ENDIF
NEXT
VIEWPORT 0,0,0,0
ENDIF

// FILLRECT x, y, x+sx*scale, y+sy*scale, col_drw
// FILLRECT x+1, y+1, x+sx*scale-2, y+sy*scale-2, col_bk
NEXT

GRABSPRITE spr_id, 0,0, 31*scale, 11*scale

sprx = 31*scale / GetPow2(31*scale)
spry = 11*scale / GetPow2(11*scale)

scale = 2 // block scale in 3D view
i=RGB(255,255,255)
X_OBJSTART 100
X_OBJADDVERTEX -scale*.5  , 0,-scale*  .5, 0   ,-spry,i
X_OBJADDVERTEX -scale*.5  , 0, scale*10.5, 0   ,0    ,i
X_OBJADDVERTEX  scale*30.5, 0,-scale*  .5, sprx,-spry,i
X_OBJADDVERTEX  scale*30.5, 0, scale*10.5, sprx,0    ,i
X_OBJEND
ENDFUNCTION


// -----------------------------------------
// Check if the level is OK this way
// -----------------------------------------
FUNCTION IsLevelDone:
LOCAL i, posbad
// pads (0=elevator!!)
FOR i=1 TO BOUNDS(thegame.pads[], 0)-1
posbad = ABS(thegame.pads[i].x - thegame.pads[i].minx) + ABS (thegame.pads[i].y-thegame.pads[i].miny)
IF thegame.forcemap=FALSE AND posbad
posbad = ABS(thegame.pads[i].x - thegame.pads[i].maxx) + ABS(thegame.pads[i].y-thegame.pads[i].maxy)
ENDIF

// not on good position?
IF posbad
RETURN FALSE
ELSE
// moving but not locked?
IF thegame.pads[i].minx<>thegame.pads[i].maxx OR thegame.pads[i].miny<>thegame.pads[i].maxy
IF thegame.pads[i].fixbits=0 THEN RETURN FALSE
ENDIF
ENDIF

NEXT
RETURN TRUE
ENDFUNCTION


// -----------------------------------------
// SHOWLEVEL - guess what? It draws everything
// -----------------------------------------
FUNCTION ShowLevel: nstorey
LOCAL i, scale, x,y, sx, sy, fix$

// platform collision = 1x1 unit
// scaling of gfx is just for better visibility
scale = 16

// pads
FOR i=0 TO BOUNDS(thegame.pads[], 0)-1
x = INTEGER(thegame.pads[i].x * scale)
y = INTEGER(thegame.pads[i].y * scale)
sx= thegame.pads[i].extx
sy= thegame.pads[i].exty
FILLRECT x, y, x+sx*scale, y+sy*scale, RGB(0x00, 0x80, 0xff)

fix$="O"
IF bAND(thegame.pads[i].fixbits, 2) THEN fix$="X"
PRINT fix$, x+(sx-1)*scale+6, y+(sy-1)*scale+6

fix$="O"
IF bAND(thegame.pads[i].fixbits, 1) THEN fix$="X"
PRINT fix$, x+6, y+6

NEXT

// players
FOR i=0 TO BOUNDS(thegame.plys[], 0)-1
PRINT "P"+(i+1), thegame.plys[i].x*scale, thegame.plys[i].y*scale
NEXT
ENDFUNCTION


// -----------------------------------------
// convert x,y to x,y,z (storey) and drop a X_MOVEMNT line
// pos[3] = camera rotation angle!
// -----------------------------------------
FUNCTION xtranslate: x,y, pos[]
LOCAL gx,gy,gz,storey, xzscale
DIM pos[3]

xzscale= 2 // size of a block
pos[0] = x*xzscale
pos[1] = 0
pos[2] = y*xzscale
ENDFUNCTION


// -----------------------------------------
// Assemble a girder from the parts we have
// -----------------------------------------
FUNCTION DrawGirder: posx, posy, dx, dy, shift_level, fixed
//X_LOADOBJ "gfx/stahltraeger.ddd", 0;  LOADSPRITE "gfx/stahltraeger.bmp", 0
//X_LOADOBJ "gfx/stahltraeger_mitte.ddd", 1
//X_LOADOBJ "gfx/stahltraeger_seite.ddd", 2

LOCAL x, y, rot, tile, pos[]
DEC dx, 1
DEC dy, 1
X_CULLMODE 1

IF fixed
X_SETTEXTURE -1,-1
ELSE
X_SETTEXTURE 0,-1
ENDIF
X_SCALING 1.01, 1.01, 1.01
IF dy>=dx
FOR x=0 TO dx
FOR y=0 TO dy
tile=1; rot=0
IF dy>0 AND y=dy THEN tile=2
IF dy>0 AND y=0; tile=2; rot=180; ENDIF
IF dy=0 THEN tile=0
xtranslate(posx+x, posy+y+shift_level, pos[])
X_MOVEMENT pos[0], pos[1], pos[2]
X_ROTATION rot, 0,1,0
IF fixed THEN tile = 3
X_DRAWOBJ tile, 0
NEXT
NEXT
ELSE
FOR x=0 TO dx
FOR y=0 TO dy
tile=1; rot=0
IF dx>0 AND x=dx THEN tile=2
IF dx>0 AND x=0; tile=2; rot=180; ENDIF
IF dx=0 THEN tile=0
xtranslate(posx+x, posy+y, pos[])
X_MOVEMENT pos[0], pos[1]+shift_level, pos[2]
X_ROTATION rot+90, 0,1,0
IF fixed THEN tile = 3
X_DRAWOBJ tile, 0
NEXT
NEXT
ENDIF
ENDFUNCTION

// -----------------------------------------
// Show the whole level in 3D
// -----------------------------------------
FUNCTION ShowLevel3D: nstorey
LOCAL i, j, x,y, sx, sy, dx, dy, pos[], d, rot, fixed
LOCAL ani, fullani, from, upto, time, t$
LOCAL secs, mins
LOCAL shift_level, cam_pos[]
LOCAL fog_col

fog_col = RGB(0xaa, 0xaa, 0xff)
DIM cam_pos[3]
DIM pos[3]

IF thegame.details
FILLRECT 0,0,screenx, screeny, fog_col
ELSE
X_MAKE3D .1, 200, 45

X_CAMERA 0,5*thegame.mapview,2-2*thegame.mapview+.1, 0,0,0
X_CULLMODE 1
X_MOVEMENT 0,0,0
X_ROTATION (thegame.plys[0].x-thegame.plys[0].y)*8+180, 0,1,0
X_SETTEXTURE 200,-1
X_DRAWOBJ 200,0
IF thegame.mapview
X_CLEAR_Z
ALPHAMODE -thegame.mapview*.9
X_SETTEXTURE 201,-1
X_DRAWOBJ 201,0
ALPHAMODE 0
ENDIF
X_CLEAR_Z
ENDIF

// star-dome, level done
IF thegame.levelokani
X_MAKE3D .1, 200, 45
X_CAMERA 0,5*thegame.mapview,2-2*thegame.mapview+.1, 0,0,0
X_CULLMODE 1
ALPHAMODE MAX(-1, -thegame.levelokani)
X_SETTEXTURE 202,-1
X_SETTEXTUREOFFSET 0, thegame.levelokani*3
X_DRAWOBJ 202,0
X_SETTEXTUREOFFSET 0, 0
ALPHAMODE 0
X_CLEAR_Z
ENDIF

// 80 enough for game
X_MAKE3D .5, 200, 45
X_CULLMODE 1
d = 9
xtranslate(thegame.plys[0].x, thegame.plys[0].y, pos[])
X_CAMERAUP -1,1,-1
cam_pos[0] = pos[0]+d*(1-thegame.mapview)
cam_pos[1] = pos[1]+d*.75+20*thegame.mapview
cam_pos[2] = pos[2]+d*(1-thegame.mapview)
X_CAMERA cam_pos[0],cam_pos[1],cam_pos[2], pos[0],pos[1]+d*.25,pos[2]
// zoom level down when done
shift_level = -(1-COS(MIN(1, thegame.levelokani*2)*90)) * 20

IF thegame.details
// 3D city
X_SPOT_LT 0, RGB(0xff,0xff,0xff), pos[0]+350,pos[1]+250,pos[2]+50, 0,1,0,360
X_FOG RGB(0xb0, 0xb0, 0xff), FALSE, 30, 50
X_MOVEMENT cam_pos[0]/2, shift_level*1.5, cam_pos[2]/2
X_SETTEXTURE 203,-1
X_DRAWOBJ 203, 0
X_SPOT_LT 0, 0, 0,0,0, 0,1,0,0
ENDIF

// Cel Shading
X_SPOT_LT -2, RGB(0xff,0xff,0xff), pos[0]+350,pos[1]+250,pos[2]+50, 0,1,0,360

// Life/Clock/$$$
IF thegame.difficulty
secs = INTEGER(thegame.timeleft)
mins = INTEGER(thegame.timeleft/60)
secs = secs - mins*60
t$=FORMAT$(2,0,mins)+":"+FORMAT$(2,0,secs)

rot = GETTIMERALL() / 30
X_MOVEMENT pos[0]-20, pos[1]+6, pos[2]-10
X_ROTATION SIN(rot+120)*45+45, .05,1,.1
X_SETTEXTURE 302,-1
X_DRAWOBJ 302, 0
X_PRINT t$, pos[0]-20, pos[1]+4.0, pos[2]-10, 0

X_MOVEMENT pos[0]-15, pos[1]+5, pos[2]-15
X_ROTATION SIN(rot)*45+90, .1,1,.05
X_SETTEXTURE 20,-1
X_DRAWOBJ 301, 0
X_PRINT "x"+thegame.life, pos[0]-15, pos[1]+4, pos[2]-15, 0

X_MOVEMENT pos[0]-10, pos[1]+6, pos[2]-20
X_ROTATION SIN(rot+240)*45-25, .1,1,-.05
X_SETTEXTURE -1,-1
X_DRAWOBJ 303, 0
X_PRINT FORMAT$(0,2,thegame.dollars), pos[0]-10, pos[1]+4.0, pos[2]-20, 0
ENDIF

// Fog
X_FOG fog_col, FALSE, 20, 40

// pads (0=elevator!!)
FOR i=1 TO BOUNDS(thegame.pads[], 0)-1
x = thegame.pads[i].x
y = thegame.pads[i].y
sx= thegame.pads[i].extx
sy= thegame.pads[i].exty

X_CULLMODE 1
// first the screws
IF thegame.forcemap
IF thegame.pads[i].x = thegame.pads[i].minx AND thegame.pads[i].y=thegame.pads[i].miny
X_SETTEXTURE 10, -1 // good one
ELSE
X_SETTEXTURE 11, -1 // bad one
ENDIF
ELSE
X_SETTEXTURE 10, -1 // any one
ENDIF

IF bAND(thegame.pads[i].fixbits, 2)
xtranslate(x+(sx-1), y+(sy-1), pos[] )
X_MOVEMENT pos[0], pos[1]+shift_level, pos[2]
X_ROTATION i*35+15,0,1,0
X_DRAWOBJ 10,0
ENDIF

IF bAND(thegame.pads[i].fixbits, 1)
xtranslate(x,y, pos[] )
X_MOVEMENT pos[0], pos[1]+shift_level, pos[2]
X_ROTATION i*35,0,1,0
X_DRAWOBJ 10,0
ENDIF

fixed=0
IF thegame.pads[i].minx=thegame.pads[i].maxx AND _
thegame.pads[i].miny=thegame.pads[i].maxy THEN fixed=1
DrawGirder(x, y, sx, sy, shift_level, fixed)
X_SCALING 1,1,1
NEXT

// Elevator - #need y pos
X_SETTEXTURE -1,-1
xtranslate(thegame.pads[0].x, thegame.pads[0].y, pos[] )
X_SCALING .95,1,.95
X_MOVEMENT pos[0], pos[1], pos[2]
X_ROTATION 180,0,1,0
X_DRAWOBJ 4, 0
X_SCALING 1,1,1

// remote control
IF thegame.remote_pos<>1
X_MOVEMENT pos[0], pos[1]+thegame.remote_pos*8.0 + SIN(thistime/10)*.1, pos[2]
X_ROTATION 180+SIN(thistime/15)*5,0,1,0
X_SETTEXTURE 5,-1
X_DRAWOBJ 5, 0
ENDIF

// players
X_MOVEMENT 0,0,0
FOR i=0 TO BOUNDS(thegame.plys[], 0)-1
xtranslate(thegame.plys[i].x-.5, thegame.plys[i].y-.5, pos[] )
X_SETTEXTURE 20,-1
X_SCALING .32, .32, .32
X_MOVEMENT pos[0], pos[1], pos[2]

// Superman - animation
IF thegame.levelokani
from=1; upto = 5
ani = MIN(1, thegame.levelokani*3)
X_DRAWANIM 20,from,upto,ani, FALSE

X_MAKE2D
ALPHAMODE .5
ELSE
// is drilling (rotation)
IF thegame.plys[i].drilltime<>0
ani = MIN(1, (1000-ABS(thegame.plys[i].drilltime))/500)
fullani=FALSE
from = 1
upto = 4
d=ani
IF thegame.plys[i].drilltime<0
d=-ani
upto=3
X_ROTATION SIN(d*90) * 360, 0,1,0
ENDIF
X_ROTATION SIN(d*90) * 360, 0,1,0
ELSE
fullani=TRUE
from = 0
upto = 2
time=MOD(thistime - thegame.plys[i].anitime +250, 1000)
// ping-pong
ani = (1+COS(time/1000*360))/2
ENDIF

X_ROTATION thegame.plys[i].dir, 0,1,0
X_DRAWANIM 20,from,upto,ani, fullani
ENDIF

NEXT

// draw the map object
X_FOG -1, FALSE, 0,0
X_SPOT_LT -2, 0, 0,0,0, 0,0,0, 0

IF thegame.mapview
// X_CAMERA pos[0],pos[1]+d*.75+40,pos[2], pos[0],pos[1]+d*.25,pos[2]
X_CULLMODE 0
X_SCALING 1,1,1
X_SETTEXTURE 100, -1
X_MOVEMENT 0,.05,0
ALPHAMODE -thegame.mapview*.8
X_DRAWOBJ 100,0
ALPHAMODE 0
ENDIF

X_MAKE2D
PRINT "Level"+thegame.level, 0,100
ENDFUNCTION


// -----------------------------------------
// MOVEPLATFORMS - update platform positions if they move
// -----------------------------------------
FUNCTION MovePlatforms:
LOCAL i, j, len_path, dx, dy, plat AS PLATFORM
LOCAL pos, oldx, oldy, dtime, vel
FOR i=0 TO BOUNDS(thegame.pads[], 0)-1
plat = thegame.pads[i]
thegame.pads[i].dx = 0
thegame.pads[i].dy = 0
IF plat.fixbits = 0 // moving
dx = plat.maxx-plat.minx
dy = plat.maxy-plat.miny
IF dx<>0 OR dy<>0
len_path=SQR(dx*dx + dy*dy)

// pos = GETTIMERALL()/len_path * .1
// pos = (1+SIN(pos))/2.0 // [0;1]
// thegame.pads[i].x = (plat.maxx - plat.minx) * pos + plat.minx
// thegame.pads[i].y = (plat.maxy - plat.miny) * pos + plat.miny

IF len_path=0 THEN CONTINUE

// if this copy of a platform is flipped
// then just flip it for interpolation
IF plat.minx>plat.maxx
pos = plat.minx
plat.minx=plat.maxx
plat.maxx=pos
ENDIF
IF plat.miny>plat.maxy
pos = plat.miny
plat.miny=plat.maxy
plat.maxy=pos
ENDIF


IF plat.minx<>plat.maxx
pos = (plat.x-plat.minx) / ABS(plat.maxx - plat.minx)
ELSE
pos = (plat.y-plat.miny) / ABS(plat.maxy - plat.miny)
ENDIF

dtime  =GETTIMER() / (1000*len_path)
IF plat.direction>=0
vel = (SIN(pos*180) + .1) * dtime
ELSE
vel = -(SIN((1-pos)*180) + .1) * dtime
ENDIF

oldx = plat.x
oldy = plat.y
INC plat.x, vel*(plat.maxx - plat.minx)
INC plat.y, vel*(plat.maxy - plat.miny)
IF plat.x>plat.maxx OR plat.y>plat.maxy
plat.x = plat.maxx
plat.y = plat.maxy
plat.direction = -1
ENDIF

IF plat.x plat.x = plat.minx
plat.y = plat.miny
plat.direction = 1
ENDIF

// this get's headache due to the flip above
plat.minx = thegame.pads[i].minx
plat.miny = thegame.pads[i].miny
plat.maxx = thegame.pads[i].maxx
plat.maxy = thegame.pads[i].maxy
thegame.pads[i] = plat

// store relative movement for later player movement
thegame.pads[i].dx = thegame.pads[i].x - oldx
thegame.pads[i].dy = thegame.pads[i].y - oldy
ENDIF
ENDIF
NEXT
ENDFUNCTION


// -----------------------------------------
// return platform index or -1 for point x,y
// -----------------------------------------
FUNCTION IsThereAPlatform: x, y
LOCAL i, col
FOR i=0 TO BOUNDS(thegame.pads[],0)-1
BOXCOLL col, x,y,0,0, thegame.pads[i].x,thegame.pads[i].y, thegame.pads[i].extx,thegame.pads[i].exty
IF col THEN RETURN i
NEXT
RETURN -1
ENDFUNCTION


// -----------------------------------------
// Shift the player if possible
// and also shift due to moving platforms
// -----------------------------------------
FUNCTION ShiftPlayer: nply, dx, dy
LOCAL x, y, i, xy
i = thegame.plys[nply].on_pf
IF i>=0
// Move player with the platform
INC thegame.plys[nply].x, thegame.pads[i].dx
INC thegame.plys[nply].y, thegame.pads[i].dy
INC thegame.plys[nply].drillx, thegame.pads[i].dx
INC thegame.plys[nply].drilly, thegame.pads[i].dy
ENDIF

FOR xy=0 TO 1
x = thegame.plys[nply].x
y = thegame.plys[nply].y
IF xy
x = thegame.plys[nply].x + dx
ELSE
y = thegame.plys[nply].y + dy
ENDIF

i = IsThereAPlatform(x,y)
IF i>=0
thegame.plys[nply].on_pf = i
IF xy
thegame.plys[nply].x = x
ELSE
thegame.plys[nply].y = y
ENDIF
ENDIF
NEXT

// change walking direction
IF dx OR dy THEN thegame.plys[nply].dir = (thegame.plys[nply].dir+ATAN(-dy,dx))/2
ENDFUNCTION


// -----------------------------------------
// DRILLPLATFORMAT
// -----------------------------------------
FUNCTION DrillPlatformAt: nply, x,y
LOCAL i, plat AS PLATFORM, fix, drillpos, delta
LOCAL tighten
i = IsThereAPlatform(x,y)
IF i<0 THEN RETURN FALSE

// See if platform is close to ends
plat = thegame.pads[i]

delta=0.1 // how close must you stand?
// can't lock a static platform
IF plat.minx=plat.maxx AND plat.miny=plat.maxy THEN RETURN FALSE
IF (ABS(plat.x-plat.minx) IF (ABS(plat.x-plat.maxx)
tighten = TRUE // put a screw in

IF fix
// Pin fixbit '1' (lower, left corner)
IF x IF bAND(plat.fixbits, 1)
tighten=FALSE
DEC plat.fixbits, 1
thegame.plys[nply].drilldir=1
ELSE
INC plat.fixbits, 1
thegame.plys[nply].drilldir=-1
ENDIF
ELSE
IF x>plat.x+plat.extx-1 AND y>plat.y+plat.exty-1
// Pin fixbit '2'
IF bAND(plat.fixbits, 2)
tighten=FALSE
DEC plat.fixbits, 2
ELSE
INC plat.fixbits, 2
ENDIF
drillpos = 1
ELSE
RETURN FALSE // x,y is not close to a fixbit
ENDIF
ENDIF

// Finally put the platform to its locked position
thegame.pads[i].fixbits = plat.fixbits
IF fix = 1
thegame.pads[i].x = plat.minx
thegame.pads[i].y = plat.miny
ELSE
thegame.pads[i].x = plat.maxx
thegame.pads[i].y = plat.maxy
ENDIF

// Center the player on the bolt
thegame.plys[nply].drillx = thegame.pads[i].x+drillpos*(plat.extx-1) + .5
thegame.plys[nply].drilly = thegame.pads[i].y+drillpos*(plat.exty-1) + .5
thegame.leveldone = IsLevelDone()
IF tighten
PLAYSOUND 0, 0,1
INC thegame.dollars, 2.5
thegame.plys[nply].drilltime = 1000
ELSE
PLAYSOUND 1, 0,1
thegame.dollars = MAX(0, thegame.dollars-2.5)
thegame.plys[nply].drilltime = -1000
ENDIF
ENDIF

RETURN FALSE
ENDFUNCTION


// -----------------------------------------
// JOYPAD - wrapper for user input
// -----------------------------------------
FUNCTION Joypad: npad, mode
SELECT mode
CASE 0; RETURN KEY(205)-KEY(203) + GETJOYX(0)
CASE 1; RETURN KEY(208)-KEY(200) + GETJOYY(0)
CASE 2; RETURN KEY(29)           + GETJOYBUTTON(0, 2) // LCtrl - drill
CASE 3; RETURN KEY(50)           + GETJOYBUTTON(0, 0) // M - map
ENDSELECT
ENDFUNCTION

// -----------------------------------------
// MOVEPLAYERS - handle user input
// -----------------------------------------
FUNCTION MovePlayers: dtime
LOCAL i, dx, dy
GLOBAL trigga_down
IF thegame.difficulty AND thegame.levelokani<=0
thegame.timeleft = MAX(0, thegame.timeleft - dtime/1000)
IF thegame.timeleft = 0
thegame.timeleft = 1000
DEC thegame.life, 1
IF thegame.life<0 THEN gameon=FALSE
ENDIF
ENDIF

IF thegame.levelokani <=0 THEN Music()
dtime = dtime/500.0

// Mapview
IF Joypad(0, 3)
thegame.mapview = MIN(thegame.mapview+dtime/3, 1)
ELSE
thegame.mapview = MAX(thegame.mapview-dtime/3, 0)
ENDIF

// position of remote control for exit
IF thegame.leveldone
thegame.remote_pos = MAX(0, thegame.remote_pos-dtime/3)
ELSE
thegame.remote_pos = MIN(1, thegame.remote_pos+dtime/2)
ENDIF

FOR i=0 TO BOUNDS(thegame.plys[], 0)-1
// is the level complete?
IF thegame.leveldone
IF IsThereAPlatform(thegame.plys[i].x, thegame.plys[i].y) = 0 // on exit
// Center the player on the bolt
thegame.plys[i].drillx = thegame.pads[0].x+ .5
thegame.plys[i].drilly = thegame.pads[0].y+ .5
IF thegame.levelokani = 0
PLAYSOUND 2,0,1 // elevator
FMod_Stop()
ENDIF
INC thegame.levelokani, dtime/4

// Add score for time left, when level done
IF thegame.levelokani>2
IF thegame.timeleft>0
thegame.timeleft = MAX(0, thegame.timeleft-GETTIMER()/100 )
INC thegame.dollars, thegame.timeleft/60
PLAYSOUND 3,0,1 // bell
ENDIF
ENDIF

// after ani - load level+go
IF thegame.levelokani > 5
INC thegame.level, 1
LoadLevel(thegame.level)
g_nSongPlay=-1
Music()
ENDIF
RETURN
ENDIF
ENDIF

SELECT thegame.plys[i].state
CASE 0 // player
IF thegame.plys[i].drilltime<>0
INC thegame.plys[i].x, (thegame.plys[i].drillx - thegame.plys[i].x)*dtime*2
INC thegame.plys[i].y, (thegame.plys[i].drilly - thegame.plys[i].y)*dtime*2

ShiftPlayer(i, 0, 0) // platform might have started to move
IF thegame.plys[i].drilltime>0
thegame.plys[i].drilltime = MAX(0, thegame.plys[i].drilltime-GETTIMER())
ELSE
thegame.plys[i].drilltime = MIN(0, thegame.plys[i].drilltime+GETTIMER()/2)
ENDIF
ELSE
dx = Joypad(i, 0)
dy = Joypad(i, 1)
dx = dx * dtime*1.2
dy = dy * dtime*1.2

ShiftPlayer(i, dx, dy)
// no animation
IF dx=0 AND dy=0 THEN thegame.plys[i].anitime = thistime

IF trigga_down=FALSE AND Joypad(i, 2)
trigga_down = TRUE
DrillPlatformAt(i, thegame.plys[i].x, thegame.plys[i].y)
ENDIF
IF Joypad(i, 2) = FALSE THEN trigga_down=FALSE
ENDIF
ENDSELECT
NEXT
ENDFUNCTION


// -----------------------------------------
// LOADLEVEL
// -----------------------------------------
FUNCTION LoadLevel: nlevel
LOCAL i, npads
INIOPEN "level"+nlevel+".ini"
npads = INIGET$("global", "padcount")
DIM thegame.pads[MAX(1, npads)]
DIM thegame.plys[1]

thegame.forcemap = INIGET$("global", "forcemap")

FOR i=0 TO npads-1
thegame.pads[i].state=0
thegame.pads[i].minx=INIGET$("pads"+i, "minx")
thegame.pads[i].miny=INIGET$("pads"+i, "miny")
thegame.pads[i].maxx=INIGET$("pads"+i, "maxx")
thegame.pads[i].maxy=INIGET$("pads"+i, "maxy")

thegame.pads[i].x=thegame.pads[i].minx
thegame.pads[i].y=thegame.pads[i].miny

thegame.pads[i].extx=INIGET$("pads"+i, "extx")
thegame.pads[i].exty=INIGET$("pads"+i, "exty")
NEXT


thegame.plys[0].x = thegame.pads[0].minx+.5
thegame.plys[0].y = thegame.pads[0].miny+.5

thegame.levelokani=0
thegame.leveldone=0
thegame.mapview=1
thegame.timepanik = FALSE

thegame.timeleft = (3-thegame.difficulty)*60

CreateMap(100)
BLACKSCREEN
ENDFUNCTION



// -----------------------------------------
// SAVELEVEL
// -----------------------------------------
FUNCTION SaveLevel: nlevel
LOCAL i, n
KILLFILE "level"+nlevel+".ini"
INIOPEN "level"+nlevel+".ini"

n  = BOUNDS(thegame.pads[],0)
INIPUT "global", "padcount", n
INIPUT "global", "forcemap", thegame.forcemap
FOR i=0 TO n-1
INIPUT "pads"+i, "minx", thegame.pads[i].minx
INIPUT "pads"+i, "miny", thegame.pads[i].miny
INIPUT "pads"+i, "maxx", thegame.pads[i].maxx
INIPUT "pads"+i, "maxy", thegame.pads[i].maxy
INIPUT "pads"+i, "extx", thegame.pads[i].extx
INIPUT "pads"+i, "exty", thegame.pads[i].exty
NEXT
ENDFUNCTION



// -----------------------------------------
// EDITOR
// -----------------------------------------
FUNCTION Editor:
LOCAL i, nlevel
LOCAL x,y, sx,sy, ex,ey, fx,fy, downx, downy, bdown
LOCAL current, scale, plat AS PLATFORM, col, col2, in_dlg
LOCAL b1,b2, mx, my
scale = INTEGER(screenx / 40)
nlevel = 1 // 0=temp

// #NEED: Bug in GLBasic - DDgui is one color else
X_MAKE3D 1,100,45
X_CAMERA 0,0,0, 0,0,-1
X_SETTEXTURE -1, -1
X_DRAWOBJ 300,0
X_MAKE2D
X_CULLMODE 0

LOADFONT "smalfont.bmp", 0
LoadLevel(nlevel)

GETFONTSIZE fx,fy
BLACKSCREEN

FMod_Stop()

@refresh:
DDgui_pushdialog(screenx*.65,0,screenx/4, screeny*.75)
DDgui_set("SCALEABLE", TRUE)
DDgui_set("MOVEABLE", TRUE)

DDgui_button("bt_leveldn", "-", 0,0)
DDgui_widget("st_level", "Level "+nlevel,0,0)
DDgui_button("bt_levelup", "+", 0,0)
DDgui_spacer(10000,0)


DDgui_button("bt_add", "Add", 0,0)
DDgui_button("bt_del", "Del", 0,0)
DDgui_button("bt_start", "Start", 0,0)
DDgui_button("bt_flip", "Flip", 0,0)
DDgui_spacer(10000,0)
DDgui_button("bt_test", "-TEST-", 0,0)
DDgui_button("bt_save", "Save", 0,0)
DDgui_spacer(10000,0)
DDgui_checkbox("cb_forcemap", "Has Map", 0,0)
DDgui_set("cb_forcemapCHECKED", thegame.forcemap)
DDgui_spacer(10000,0)
DDgui_widget("", "Move current",0,0)
DDgui_spacer(10000,0)
DDgui_spacer(fx*2,0)
DDgui_button("bt_mvup", "^",0,0)
DDgui_spacer(10000,0)
DDgui_button("bt_mvleft", "<-",0,0)
DDgui_button("bt_mvright", "->",0,0)
DDgui_spacer(10000,0)
DDgui_spacer(fx*2,0)
DDgui_button("bt_mvdown", "v",0,0)

DDgui_spacer(10000,0)
DDgui_widget("", "Size current",0,0)
DDgui_spacer(10000,0)
DDgui_spacer(fx*2,0)
DDgui_button("bt_szy-", "smaller",0,0)
DDgui_spacer(10000,0)
DDgui_button("bt_szx-", "-> <-",0,0)
DDgui_button("bt_szx+", "<- ->",0,0)
DDgui_spacer(10000,0)
DDgui_spacer(fx*2.5,0)
DDgui_button("bt_szy+", "bigger",0,0)

DDgui_spacer(10000,0)
DDgui_widget("", "Current move",0,0)
DDgui_spacer(10000,0)
DDgui_spacer(fx*2,0)
DDgui_button("bt_mxy-", "^",0,0)
DDgui_spacer(10000,0)
DDgui_button("bt_mxx-", "<-",0,0)
DDgui_button("bt_mxx+", "->",0,0)
DDgui_spacer(10000,0)
DDgui_spacer(fx*2,0)
DDgui_button("bt_mxy+", "v",0,0)

current=2

WHILE TRUE
MOUSESTATE mx,my,b1,b2

BOXCOLL in_dlg, mx,my,1,1, DDgui_get("XPOS"), DDgui_get("YPOS"), DDgui_get("WIDTH"), DDgui_get("HEIGHT")

// Grid - dots
FOR x=0.5 TO 29.5
FOR y=0.5 TO 9.5
SETPIXEL x*scale, y*scale, RGB(255,255,255)
NEXT
NEXT

// Pads
FOR i=0 TO BOUNDS(thegame.pads[],0)-1
plat = thegame.pads[i]
x = INTEGER(plat.minx * scale)
y = INTEGER(plat.miny * scale)
sx= plat.extx
sy= plat.exty
IF in_dlg=FALSE AND b1
BOXCOLL col, mx,my,1,1, x,y,sx*scale,sy*scale
IF col THEN current = i
ENDIF

// exit
IF plat.minx<>plat.maxx OR plat.miny<>plat.maxy
col = RGB(0x80, 0x80, 0xff)
col2= RGB(0x00, 0x80, 0xff)
ELSE
col = RGB(0x80, 0xff, 0x80)
col2= RGB(0x00, 0xff, 0x80)
ENDIF
IF i=current THEN col = RGB(0xff, 0xff, 0x40)
FILLRECT x, y, x+INTEGER(sx*scale)-2, y+INTEGER(sy*scale)-2, col
FILLRECT x+1, y+1, x+INTEGER(sx*scale)-3, y+INTEGER(sy*scale)-3, col2
IF i=0
PRINT "UP", x+fx/4,y
ENDIF

// line - connections
IF plat.minx<>plat.maxx OR plat.miny<>plat.maxy
ex = INTEGER(plat.maxx * scale)
ey = INTEGER(plat.maxy * scale)
ALPHAMODE .2
FILLRECT ex, ey, ex+sx*scale-2, ey+sy*scale-2, RGB(0x00, 0x80, 0xff)
ALPHAMODE .1
FILLRECT x, y, ex+sx*scale-2, ey+sy*scale-2, RGB(0x80, 0x80, 0xff)
INC x, scale/2 + (sx-1)/2*scale
INC y, scale/2 + (sy-1)/2*scale
INC ex, scale/2+ (sx-1)/2*scale
INC ey, scale/2+ (sy-1)/2*scale
ALPHAMODE 0
DRAWLINE x, y, ex, ey, RGB(0xff, 0xff, 0x40)
ENDIF
NEXT

// Grid for next-screen
FOR x=0.5 TO 2.5
SETPIXEL (x+ 6)*scale, 2.5*scale, RGB(255,96,96)
SETPIXEL (x+ 9)*scale, 6.5*scale, RGB(255,96,96)
SETPIXEL (x+15)*scale, 2.5*scale, RGB(255,96,96)
SETPIXEL (x+18)*scale, 6.5*scale, RGB(255,96,96)
NEXT

// Dialog messages
DDgui_show(TRUE)

thegame.forcemap = DDgui_get$("cb_forcemapCHECKED")
IF DDgui_get("bt_leveldnCLICKED")
nlevel = MAX(1, nlevel-1)
LoadLevel(nlevel)
GOTO refresh
ENDIF

IF DDgui_get("bt_levelupCLICKED")
nlevel = MIN(99, nlevel+1)
LoadLevel(nlevel)
GOTO refresh
ENDIF


IF DDgui_get("bt_addCLICKED")
i = BOUNDS(thegame.pads[],0)
REDIM thegame.pads[i+1]
thegame.pads[i].extx=1
thegame.pads[i].exty=1
current = i
ENDIF

IF DDgui_get("bt_delCLICKED") OR KEY(211)
WHILE KEY(211); WEND
i = BOUNDS(thegame.pads[],0)
IF current>=0 AND current thegame.pads[current] = thegame.pads[i-1]
REDIM thegame.pads[i-1]
current=i-2
ENDIF
ENDIF
IF DDgui_get("bt_startCLICKED")
i = current
IF i>0 AND i plat = thegame.pads[current]
thegame.pads[current] = thegame.pads[0]
thegame.pads[0] = plat
ENDIF
ENDIF
IF DDgui_get("bt_flipCLICKED")
i = current
IF i>0 AND i x = thegame.pads[i].minx; thegame.pads[i].minx=thegame.pads[i].maxx; thegame.pads[i].maxx=x
y = thegame.pads[i].miny; thegame.pads[i].miny=thegame.pads[i].maxy; thegame.pads[i].maxy=y
ENDIF
ENDIF
IF DDgui_get("bt_testCLICKED")
x = thegame.level
thegame.level = 0
SaveLevel(0); LoadLevel(0); MainGame();
LoadLevel(0)
thegame.level = x
ENDIF
IF DDgui_get("bt_saveCLICKED"); SaveLevel(nlevel); ENDIF

// don't let start be scaled
thegame.pads[0].extx=1
thegame.pads[0].exty=1
thegame.pads[0].maxx=thegame.pads[0].minx
thegame.pads[0].maxy=thegame.pads[0].miny

IF current>=0 AND current // pos
IF DDgui_get("bt_mvleftCLICKED") OR KEY(203) ;WHILE KEY(203);WEND;DEC thegame.pads[current].minx,1; DEC thegame.pads[current].maxx,1;ENDIF
IF DDgui_get("bt_mvrightCLICKED")OR KEY(205) ;WHILE KEY(205);WEND;INC thegame.pads[current].minx,1; INC thegame.pads[current].maxx,1;ENDIF
IF DDgui_get("bt_mvupCLICKED" )  OR KEY(200) ;WHILE KEY(200);WEND;DEC thegame.pads[current].miny,1; DEC thegame.pads[current].maxy,1;ENDIF
IF DDgui_get("bt_mvdownCLICKED") OR KEY(208) ;WHILE KEY(208);WEND;INC thegame.pads[current].miny,1; INC thegame.pads[current].maxy,1;ENDIF

// ext
IF DDgui_get("bt_szx-CLICKED") THEN DEC thegame.pads[current].extx,1
IF DDgui_get("bt_szx+CLICKED") THEN INC thegame.pads[current].extx,1
IF DDgui_get("bt_szy-CLICKED") THEN DEC thegame.pads[current].exty,1
IF DDgui_get("bt_szy+CLICKED") THEN INC thegame.pads[current].exty,1
thegame.pads[current].extx = MAX(1, thegame.pads[current].extx)
thegame.pads[current].exty = MAX(1, thegame.pads[current].exty)

// max
IF DDgui_get("bt_mxx-CLICKED") THEN DEC thegame.pads[current].maxx,1
IF DDgui_get("bt_mxx+CLICKED") THEN INC thegame.pads[current].maxx,1
IF DDgui_get("bt_mxy-CLICKED") THEN DEC thegame.pads[current].maxy,1
IF DDgui_get("bt_mxy+CLICKED") THEN INC thegame.pads[current].maxy,1
ENDIF

PRINT BOUNDS(thegame.pads[],0), 100, 100
SHOWSCREEN
HIBERNATE
WEND
ENDFUNCTION



// -----------------------------------------
// MUSIC - this keep tha sound alive
// -----------------------------------------
FUNCTION Music:
GLOBAL g_nSong, g_nSongPlay, fmod_init
LOCAL isong
IF thegame.difficulty AND thegame.timeleft<60
IF thegame.timepanik=FALSE
thegame.timepanik=TRUE
FMod_Load("music\\RB_8.IT")
FMod_Play()
ENDIF
RETURN
ENDIF

IF FMod_IsFinished()
IF g_nSongPlay<=0
g_nSongPlay = 1
isong = g_nSong
WHILE isong = g_nSong
isong = RND(6)+1 // song 8 = timeout
WEND
g_nSong = isong
FMod_Load("music\\RB_"+isong+".IT")
ELSE
DEC g_nSongPlay, 1
ENDIF
FMod_Play()
ENDIF
ENDFUNCTION


// -----------------------------------------
// TitleScreen + Game Select
// -----------------------------------------
FUNCTION TitleScreen:
LOCAL start, pos, flicker, x, y
LOCAL flickerperc
LOCAL diff$[], tim$[], detl$[], sel$[], cursel
LOADFONT "bigfont.bmp", 0

cursel = 3
DIM diff$[3]
diff$[0] = "Dumb"
diff$[1] = "Okay"
diff$[2] = "Hard"
DIM tim$[3]
tim$[0] = "None"
tim$[1] = "Okay"
tim$[2] = "Run!"
DIM detl$[2]
detl$[0]= "C 64"
detl$[1]= "Whee"

flickerperc = 0.005

thegame.timeleft=1000 // no panic song!

FMod_Load("music\\RB_6.IT"); FMod_Play()

start = GETTIMERALL()
WHILE pos<1
pos = (GETTIMERALL()-start)/2000
flicker = ((1+SIN(pos*4000))/2*flickerperc+(1-flickerperc)) * (1-MAX(0, COS(pos*140)) )

STRETCHSPRITE 200, 0,0,screenx, screeny
X_MAKE3D 1,100,45
X_CAMERA 0,0,0, 0,0,-1
X_SPOT_LT -2, 1, 45,20,35, -.1,-.1,-1, 360
X_CULLMODE 1
X_MOVEMENT 0,0,-107 + flicker*100
X_DRAWOBJ 300,0
X_MAKE2D
IF pos>=1 THEN USEASBMP
SHOWSCREEN
WEND

y = -600
WHILE TRUE
IF y<-180 THEN y=y+GETTIMER()/10
ALPHAMODE -.6
FILLRECT 184, 394+y, screenx-184, 564+y, RGB(0,0,0)
// selection
FILLRECT 184, 414+y+cursel*30, screenx-184, 443+y+cursel*30, RGB(255,255,255)
ALPHAMODE 0

PRINT "[F1] Startlevel    - "+diff$[thegame.startlevel], 204,414+y
PRINT "[F2] Timer         - "+ tim$[thegame.difficulty], 204,444+y
PRINT "[F3] GFX - Details - "+detl$[thegame.details   ], 204,474+y
PRINT "[F4] Rock the Bolt - Yay!", 204,504+y
PRINT "[F5] Edit Levels   - Tick", 204,534+y
SHOWSCREEN

// up/dn
pos = Joypad(0, 1)
IF pos
cursel = MIN(4, MAX(0, cursel + pos) )
WHILE Joypad(0, 1)<>0; WEND
ENDIF
// select
pos = Joypad(0, 2)
IF pos
WHILE Joypad(0, 2)<>0; WEND
ENDIF

IF KEY(59) OR (pos AND cursel=0) THEN thegame.startlevel = MOD(1+thegame.startlevel, 3)
IF KEY(60) OR (pos AND cursel=1) THEN thegame.difficulty = MOD(1+thegame.difficulty, 3)
IF KEY(61) OR (pos AND cursel=2) THEN thegame.details    = 1-thegame.details

WHILE KEY(59); WEND
WHILE KEY(60); WEND
WHILE KEY(61); WEND

// F4
IF KEY(62) OR (pos AND cursel=3)
WHILE KEY(62); WEND
RETURN
ENDIF

IF KEY(63) OR (pos AND cursel=4) THEN Editor()
WEND
ENDFUNCTION
Und benötigt die Datei: Projects/Common/DDGui.gbas im Projekt (ausser Du schmeisst den Editor raus)
Nützt das was, oder soll ich alles komplett hochladen?

EDIT: Ich hwar bei dem Prjekt unter Zeitdruck. Der Code ist u.U. kein Spaß zum Lesen und teilweise suboptimal implementiert. Gerne mal reinschauen, aber nicht entmutigen, wenn man's nicht blickt. Die Kommentare sind (wenn überhaupt) sehr dürftig.

mannybass

Komplett hochladen wär klasse.