Ive been using an older version of dark basic because my current computer cant support newer versions of DX, and because of that the code snippets below compiled without error, I just realized now that I access types not yet declared in the beginning of the code, which should produce an error, but never did, so I didnt notice.
Im in the process of rewriting the entire engine to work more efficiently with functions instead of jumbled of code snippets in sequencial order, and should be done by tomorrow, at which time Ill rewrite this entire thread to be more concise and to the point.
Gibble Blops
by RUCCUS
Am I hosting right now? No
Am I awaiting players right now? No
IP? N/A
-----------------------------------------
Download Gibble Blops Here (Tempest.dll Inside)
Or read on for the source code to paste into Dark Basic.
Gibble Blops is a small side project of mine Ive been programming (well, just last night so far, but hopefully more and more each week) while I take small breaks from my larger FPS Tutorial project. Ive been trying to keep the game simple and crisp as much as possible, which is one of the main reasons why it doesnt use any media.
For the time being, Ill release the source code for free, its stable and is in itself a complete game (connecting, battle, deaths, etc. ), but if I work on the project further and implement a few weapons that will take quite a long time to make, I might only release the executables at that stage.
Screenshots (Newest at Top)
Showing drowning (with bubbles!)
The newly added grapple hook seen here
Major update in graphics and gameplay
The first successful multiplayer run
Controls
A/D: Move your blob left and right
W: Make your blob jump. Press W while in air to perform a double jump.
S: Make your blob perform a smash attack, only works while in air. Great way to get to the ground fast.
Spacekey: Shoot a bullet
Source Code
Here's version 0.1's source code, feel free to change it however you like, post new attacks or ideas you've come up with (Im not asking for them, but if you want to go right ahead), or try to learn from the code. Right now its not very commented, and has a few too many variables than needed. As well (sorry TDK
) Ive got a bunch of floats in there that could be integers, but I only did so knowing there might be a chance where I needed to fill the variables with a float later on.
Version 0.2 (latest stable release)
Updates:
- Fixed Bullet Freezing bug
- Possibly fixed boot screen bug
- Added health bars
- Added scalable ground, and death from falling off a ledge
- Added side transfering (jump out of the screen to the left and appear at the far right)
- Added eyes to the blobs
- Added admin command "set score" to limit games
- Added winning/losing
```````````````````````````````````````````````````````````````
`Gibble Blops``````````````````````````````````````````````````
```````````````````````````````````````````````````````````````
SET DISPLAY MODE 640,480,32
SET TEXT FONT "Courier New":SET TEXT SIZE 15
health = 100
fieldWidth = 10
score = 3
GLOBAL screenWidth
screenWidth = SCREEN WIDTH()
GLOBAL screenHeight
screenHeight = SCREEN HEIGHT()
TLogOff
`Network Setup Input
PRINT "Gibble-Blop!"
PRINT "---------------"
PRINT ""
INPUT "User Name: ",usr.name$
INPUT "IP Address: ",usr.IP$
INPUT "Client or Host? (H/C): ",usr.status$
IF usr.name$ = "" THEN usr.name$ = "Guest"
IF usr.IP$ = "" THEN usr.IP$ = "127.0.0.1"
usr.status$ = UPPER$(usr.status$)
`Network Connection
IF usr.status$ = "C"
connected = TJoin(usr.IP$,usr.name$)
ELSE
INPUT "Score to Win: ",score
IF score <= 0 THEN score = 5
INPUT "Playing Field Size (1-4): ",fieldSize#
IF fieldSize# = 1
fieldSize# = SCREENWIDTH/4
ELSE
IF fieldSize# = 2
fieldSize# = SCREENWIDTH/3
ELSE
IF fieldSize# = 3
fieldSize# = SCREENWIDTH/2
ELSE
fieldSize# = SCREENWIDTH
ENDIF
ENDIF
ENDIF
connected = THost(usr.IP$,2,usr.name$)
ENDIF
`Connection Success Check
IF connected
PRINT "Connection Established"
WAIT 2000
ELSE
PRINT "Failure to connect"
WAIT 4000
END
ENDIF
`App Settings
SYNC ON:SYNC RATE 0
BACKDROP ON:COLOR BACKDROP RGB(255,255,255)
INK RGB(000,000,000),RGB(255,255,255)
`User Type
TYPE usrT
x#,y#
xRad,yRad
speed#
jumping
jumpSpeed#
gravSpeed#
gravRate#
defGravSpeed#
yRadChange
smashRad
secondJump
direction
bulletRad
bulletX#
bulletY#
bulletSpeed#
bulletAlive
bulletDirection
name$,IP$,status$
health
gravRateChange#
freeze
frozen
kills
smashDamage,shootDamage
ENDTYPE
GLOBAL usr AS usrT
usr.x# = SCREENWIDTH/2
usr.y# = SCREENHEIGHT/2
usr.xRad = 10
usr.yRad = 8
usr.speed# = 0.5
usr.jumpSpeed# = 1
usr.gravSpeed# = 0
usr.defGravSpeed# = 0.005
usr.gravRate# = usr.defGravSpeed#
usr.smashRad = -5
usr.direction = 1
usr.bulletRad = 5
usr.bulletSpeed# = 2
usr.bulletAlive = 1
usr.bulletDirection = usr.direction
usr.health = 100
usr.smashDamage = 20
usr.shootDamage = 5
math_setup()
DO
IF NOT usr.frozen
`Movement: X-Axis
IF KEYSTATE(30) <> KEYSTATE(32)
usr.direction = (KEYSTATE(32)-KEYSTATE(30))
INC usr.x#, usr.direction*usr.speed#
ENDIF
`Movement: Y-Axis
IF SPACEKEY() AND usr.bulletAlive = 1 THEN usr.bulletAlive = 0:usr.bulletX# = usr.x#+(usr.direction*usr.xRad)+(usr.direction*usr.bulletRad):usr.bulletY# = usr.y#-usr.yRad:usr.bulletDirection = usr.direction
`Bullet Shooting
IF usr.bulletAlive = 0
INC usr.bulletX#, usr.bulletDirection*usr.bulletSpeed#
CIRCLE usr.bulletX#,usr.bulletY#,usr.bulletRad
IF usr.bulletX# < 0 OR usr.bulletX# > SCREENWIDTH THEN usr.bulletAlive = 1
ENDIF
`Double Jump Routine
IF INT(usr.gravSpeed#*100) > 0 AND usr.secondJump = 0 THEN usr.jumping = 0:usr.secondJump = 1
IF KEYSTATE(17) AND usr.jumping = 0 THEN usr.gravSpeed# = -usr.jumpSpeed#:usr.jumping = 1
`Gravity
INC usr.y#,usr.gravSpeed#
INC usr.gravSpeed#, usr.gravRate#+usr.gravRateChange#
`Smash Attack
IF KEYSTATE(31) THEN usr.yRadChange = usr.smashRad ELSE usr.yRadChange = 0
`Ground Collision
IF usr.y# > SCREENHEIGHT/2
IF usr.x# >= (SCREENWIDTH/2)-(fieldSize#/2) AND usr.x# <= (SCREENWIDTH/2)+(fieldSize#/2)
IF usr.y# < (SCREENHEIGHT/2)+fieldWidth
usr.gravSpeed# = usr.defGravSpeed#
usr.y# = SCREENHEIGHT/2
usr.jumping = 0
usr.yRadChange = 0
usr.secondJump = 0
usr.gravRateChange# = 0
ENDIF
ENDIF
ELSE
IF usr.yRadChange <> usr.smashRad
usr.yRadChange = 5
ELSE
usr.gravRateChange# = 0.05
ENDIF
ENDIF
IF usr.y# > SCREENHEIGHT
DEC usr.health,1
ENDIF
`Wall Collision (Side Switching)
IF usr.x# < -usr.xRad
usr.x# = SCREENWIDTH
ENDIF
IF usr.x# > SCREENWIDTH+usr.xRad
usr.x# = 0
ENDIF
ELSE
CIRCLE usr.x#,usr.y#+(usr.yRad/2),20
LINE usr.x#,usr.y#,x#,y#
ENDIF
`Death Check
IF usr.health <= 0
usr.health = 100
usr.bulletx# = 0
usr.bullety# = 0
usr.bulletAlive = 1
usr.x# = SCREENWIDTH/2
usr.y# = -50
usr.gravSpeed# = usr.defGravSpeed#
usr.secondJump = 1
usr.jumping = 1
usr.yRadChange = 0
INC kills,1
ENDIF
`Network Routine
admin()
INC sendDelay
IF sendDelay >= 5
`Network: Send Data
TPutFloat usr.x#
TPutFloat usr.y#
TPutInt usr.yRadChange
TPutFloat usr.bulletx#
TPutFloat usr.bullety#
TPutInt usr.health
TPutInt usr.freeze
TPutInt usr.bulletAlive
TPutInt kills
TPutFloat fieldSize#
TPutInt usr.direction
TPutInt score
TSendAll
sendDelay = 0
`Network: Recieve data
REPEAT
msg = TGetMessage()
IF msg
x# = TGetFloat()
y# = TGetFloat()
yOffset = TGetInt()
bulletx# = TGetFloat()
bullety# = TGetFloat()
health = TGetInt()
usr.frozen = TGetInt()
bulletAlive = TGetInt()
usr.kills = TGetInt()
tempFieldSize# = TGetFloat()
direction = TGetInt()
tempScore = TGetInt()
senderID = TGetSender()
IF senderID = 1 then fieldSize# = tempFieldSize#:score = tempScore
IF yOffset = usr.smashRad
colDist# = math_getDist2D(usr.x#,usr.y#,x#,y#)
IF colDist# < usr.yRad*2
DEC usr.health,usr.smashDamage
ENDIF
ENDIF
IF bulletAlive = 0
colDist# = math_getDist2D(usr.x#,usr.y#,bulletx#,bullety#)
IF colDist# < usr.yRad*2
DEC usr.health,usr.shootDamage
ENDIF
ENDIF
`Check if a player has won
IF usr.kills >= score
CLS
INK RGB(255,255,255),0
PRINT "You Win!"
PRINT "---------"
PRINT "Press any key to exit"
WAIT KEY
END
ENDIF
IF kills >= score
CLS
INK RGB(255,255,255),0
PRINT "You Lose!"
PRINT "---------"
PRINT "Press any key to exit"
WAIT KEY
END
ENDIF
ENDIF
UNTIL NOT msg
ENDIF
`Draw enemy
IF TPlayerExist (2/TGetThisID())
CIRCLE bulletx#,bullety#,usr.bulletRad
ELLIPSE x#,y#-usr.yRad-yOffset,usr.xRad,usr.yRad+yOffset
CENTER TEXT x#,y#-50,TGetPlayerName(senderID)
BOX x#-(25),y#-35,x#+(0.5*((health-50))),y#-30,RGB(128,128,128),RGB(128,128,128),RGB(192,192,192),RGB(192,192,192)
TEXT 0,SCREENHEIGHT-100,"PLAYERS"
TEXT 0,SCREENHEIGHT-100,"_____"
TEXT 0,SCREENHEIGHT-70,TGetPlayerName(senderID)+": "+STR$(kills)
eyeX# = x# + (direction * (usr.xRad/2))
eyeY# = y# - (usr.yRad + yOffset)
BOX eyeX#-1,eyeY#-1,eyeX#+1,eyeY#+1
IF usr.freeze = 1
CIRCLE x#,y#+(usr.yRad/2),20
LINE usr.x#,usr.y#,x#,y#
ENDIF
ENDIF
`Remove booted players from game screen
IF TConnected() = 0
CLS
INK RGB(255,255,255),0
PRINT "- Connection Lost -"
PRINT "You may be experiencing this problem if: "
PRINT "- The host shut down the server"
PRINT "- The host kicked you from the server"
PRINT ""
PRINT "Press any key to exit"
WAIT KEY
END
ENDIF
`Draw User
ELLIPSE usr.x#,usr.y#-(usr.yRad+usr.yRadChange),usr.xRad,usr.yRad+usr.yRadChange
`Draw Eyes
eyeX# = usr.x# + (usr.direction * (usr.xRad/2))
eyeY# = usr.y# - (usr.yRad + usr.yRadChange)
BOX eyeX#-1,eyeY#-1,eyeX#+1,eyeY#+1
`Display User Name
CENTER TEXT usr.x#,usr.y#-50,usr.name$
BOX usr.x#-(25),usr.y#-35,usr.x#+(0.5*((usr.health-50))),usr.y#-30,RGB(128,128,128),RGB(128,128,128),RGB(192,192,192),RGB(192,192,192)
`Display User Kills
TEXT 0,SCREENHEIGHT-100,"PLAYERS"
TEXT 0,SCREENHEIGHT-100,"________"
TEXT 0,SCREENHEIGHT-85,usr.name$+": "+STR$(usr.kills)
`Draw Ground
BOX (SCREENWIDTH/2)-(fieldSize#/2)-1,(SCREENHEIGHT/2)-1,(SCREENWIDTH/2)+(fieldSize#/2)+1,(SCREENHEIGHT/2)+fieldWidth+1
BOX (SCREENWIDTH/2)-(fieldSize#/2),SCREENHEIGHT/2,(SCREENWIDTH/2)+(fieldSize#/2),(SCREENHEIGHT/2)+fieldWidth,RGB(255,255,255),RGB(192,192,192),RGB(192,192,192),RGB(255,255,255)
`Display Game Info
TEXT (SCREENWIDTH/2)+100,SCREENHEIGHT + 400,"Score to Win: "+STR$(score)
`Display FPS
TEXT 0,0,"FPS: "+STR$(SCREEN FPS())
`Refresh (screen and tempest)
TSYNC
SYNC
LOOP
FUNCTION admin()
`Host commands
`If the user is the host
IF TGetThisID() = 1
TEXT 0,SCREENHEIGHT-30,"Admin Commands"
TEXT 0,SCREENHEIGHT-30,"______________"
TEXT 0,SCREENHEIGHT-15,"1: Kick Enemy 2: Shutdown Server 3: Freeze Enemy 4: Unfreeze Enemy"
IF KEYSTATE(2) THEN TKillPlayer 2
IF KEYSTATE(3) THEN TDisconnect
IF KEYSTATE(4) THEN usr.freeze = 1
IF KEYSTATE(5) THEN usr.freeze = 0
ENDIF
ENDFUNCTION
FUNCTION math_setup()
`setup required vectors for distance calculations
null = MAKE VECTOR3(1)
null = MAKE VECTOR2(2)
#CONSTANT vecDist3D = 1
#CONSTANT vecDist2D = 2
ENDFUNCTION
FUNCTION math_getDist2D(X1#,Y1#,X2#,Y2#)
SET VECTOR2 vecDist2D,X1#-X2#,Y1#-Y2#
dist# = LENGTH VECTOR2(vecDist2D)
ENDFUNCTION dist#
Version 0.1
```````````````````````````````````````````````````````````````
`Gibble Blops``````````````````````````````````````````````````
```````````````````````````````````````````````````````````````
SET DISPLAY MODE 640,480,32
TLogOff
`Network Setup Input
PRINT "Gibble-Blop!"
PRINT "---------------"
PRINT ""
INPUT "User Name: ",usr.name$
INPUT "IP Address: ",usr.IP$
INPUT "Client or Host? (H/C): ",usr.status$
usr.status$ = UPPER$(usr.status$)
`Network Connection
IF usr.status$ = "C"
connected = TJoin(usr.IP$,usr.name$)
ELSE
connected = THost(usr.IP$,2,usr.name$)
ENDIF
`Connection Success Check
IF connected
PRINT "Connection Established"
WAIT 2000
ELSE
PRINT "Failure to connect"
WAIT 4000
END
ENDIF
`App Settings
SYNC ON:SYNC RATE 0
BACKDROP ON:COLOR BACKDROP RGB(255,255,255)
INK RGB(000,000,000),0
`User Type
TYPE usrT
ox#,oy#
x#,y#
xRad,yRad
speed#
jumping
jumpSpeed#
gravSpeed#
gravRate#
defGravSpeed#
yRadChange
smashRad
secondJump
direction
bulletRad
bulletX#
bulletY#
bulletSpeed#
bulletAlive
bulletDirection
name$,IP$,status$
health
gravRateChange#
freeze
frozen
kills
smashDamage,shootDamage
ENDTYPE
GLOBAL usr AS usrT
usr.x# = SCREEN WIDTH()/2
usr.y# = SCREEN HEIGHT()/2
usr.xRad = 10
usr.yRad = 8
usr.speed# = 0.5
usr.jumpSpeed# = 1
usr.gravSpeed# = 0
usr.defGravSpeed# = 0.005
usr.gravRate# = usr.defGravSpeed#
usr.smashRad = -5
usr.direction = 1
usr.bulletRad = 5
usr.bulletSpeed# = 2
usr.bulletAlive = 1
usr.bulletDirection = usr.direction
usr.health = 100
usr.smashDamage = 20
usr.shootDamage = 5
health = 100
math_setup()
DO
IF NOT usr.frozen
`Store user's old position
usr.ox# = usr.x#
usr.oy# = usr.y#
`Movement: X-Axis
IF KEYSTATE(30) OR KEYSTATE(32)
usr.direction = (KEYSTATE(32)-KEYSTATE(30))
INC usr.x#, usr.direction*usr.speed#
ENDIF
`Movement: Y-Axis
IF SPACEKEY() AND usr.bulletAlive = 1 THEN usr.bulletAlive = 0:usr.bulletX# = usr.x#+(usr.direction*usr.xRad)+(usr.direction*usr.bulletRad):usr.bulletY# = usr.y#-usr.yRad:usr.bulletDirection = usr.direction
`Bullet Shooting
IF usr.bulletAlive = 0
INC usr.bulletX#, usr.bulletDirection*usr.bulletSpeed#
CIRCLE usr.bulletX#,usr.bulletY#,usr.bulletRad
IF usr.bulletX# < 0 OR usr.bulletX# > SCREEN WIDTH() THEN usr.bulletAlive = 1
ENDIF
`Double Jump Routine
IF INT(usr.gravSpeed#*100) > 0 AND usr.secondJump = 0 THEN usr.jumping = 0:usr.secondJump = 1
IF KEYSTATE(17) AND usr.jumping = 0 THEN usr.gravSpeed# = -usr.jumpSpeed#:usr.jumping = 1
`Gravity
INC usr.y#,usr.gravSpeed#
INC usr.gravSpeed#, usr.gravRate#+usr.gravRateChange#
`Smash Attack
IF KEYSTATE(31) THEN usr.yRadChange = usr.smashRad ELSE usr.yRadChange = 0
`Ground Collision
IF usr.y# > SCREEN HEIGHT()/2
usr.gravSpeed# = usr.defGravSpeed#
usr.y# = SCREEN HEIGHT()/2
usr.jumping = 0
usr.yRadChange = 0
usr.secondJump = 0
usr.gravRateChange# = 0
ELSE
IF usr.yRadChange <> usr.smashRad
usr.yRadChange = 5
ELSE
usr.gravRateChange# = 0.05
ENDIF
ENDIF
ENDIF
`Death Check
IF usr.health <= 0
usr.health = 100
usr.bulletx# = 0
usr.bullety# = 0
usr.bulletAlive = 1
usr.x# = SCREEN WIDTH()/2
usr.y# = SCREEN HEIGHT()/2
usr.gravSpeed# = usr.defGravSpeed#
usr.yRadChange = 0
INC kills,1
ENDIF
`Network Routine
admin()
INC sendDelay
IF sendDelay >= 5
`Network: Send Data
TPutFloat usr.x#
TPutFloat usr.y#
TPutInt usr.yRadChange
TPutFloat usr.bulletx#
TPutFloat usr.bullety#
TPutInt usr.health
TPutInt usr.freeze
TPutFloat usr.ox#
TPutFloat usr.oy#
TPutInt usr.bulletAlive
TPutInt kills
TSendAll
sendDelay = 0
`Network: Recieve data
REPEAT
msg = TGetMessage()
IF msg
x# = TGetFloat()
y# = TGetFloat()
yOffset = TGetInt()
bulletx# = TGetFloat()
bullety# = TGetFloat()
health = TGetInt()
usr.frozen = TGetInt()
ox# = TGetFloat()
oy# = TGetFloat()
bulletAlive = TGetInt()
usr.kills = TGetInt()
senderID = TGetSender()
IF yOffset = usr.smashRad
colDist# = math_getDist2D(usr.x#,usr.y#,x#,y#)
IF colDist# < usr.yRad*2
DEC usr.health,usr.smashDamage
ENDIF
ENDIF
IF bulletAlive = 0
colDist# = math_getDist2D(usr.x#,usr.y#,bulletx#,bullety#)
IF colDist# < usr.yRad*2
DEC usr.health,usr.shootDamage
ENDIF
ENDIF
ENDIF
UNTIL NOT msg
ENDIF
`Draw enemy
IF TPlayerExist (2/TGetThisID())
CIRCLE bulletx#,bullety#,usr.bulletRad
ELLIPSE x#,y#-usr.yRad-yOffset,usr.xRad,usr.yRad+yOffset
CENTER TEXT x#,y#-50,TGetPlayerName(senderID)
CENTER TEXT x#,y#-35,STR$(health)
TEXT 0,SCREEN HEIGHT()-100,"SCORE"
TEXT 0,SCREEN HEIGHT()-100,"_____"
TEXT 0,SCREEN HEIGHT()-70,TGetPlayerName(senderID)+": "+STR$(kills)
ENDIF
`Draw User
ELLIPSE usr.x#,usr.y#-(usr.yRad+usr.yRadChange),usr.xRad,usr.yRad+usr.yRadChange
`Display User Name
CENTER TEXT usr.x#,usr.y#-50,usr.name$
CENTER TEXT usr.x#,usr.y#-35,STR$(usr.health)
`Display User Kills
TEXT 0,SCREEN HEIGHT()-100,"SCORE"
TEXT 0,SCREEN HEIGHT()-100,"_____"
TEXT 0,SCREEN HEIGHT()-85,usr.name$+": "+STR$(usr.kills)
`Draw Ground
LINE 0,SCREEN HEIGHT()/2,SCREEN WIDTH(),SCREEN HEIGHT()/2
`Display FPS
TEXT 0,0,"FPS: "+STR$(SCREEN FPS())
`Remove booted players from game screen
IF TConnected() = 0
CLS
INK RGB(255,255,255),0
PRINT "- Connection Lost -"
PRINT "You may be experiencing this problem if: "
PRINT "- The host shut down the server"
PRINT "- The host kicked you from the server"
PRINT ""
PRINT "Press any key to exit"
WAIT KEY
END
ENDIF
`Refresh (screen and tempest)
TSYNC
SYNC
LOOP
FUNCTION admin()
`Host commands
`If the user is the host
IF TGetThisID() = 1
TEXT 0,SCREEN HEIGHT()-30,"Admin Commands"
TEXT 0,SCREEN HEIGHT()-30,"______________"
TEXT 0,SCREEN HEIGHT()-15,"1: Kick Enemy 2: Shutdown Server 3: Freeze Enemy 4: Unfreeze Enemy"
IF KEYSTATE(2) THEN TKillPlayer 2
IF KEYSTATE(3) THEN TKillPlayer 2:TDisconnect
IF KEYSTATE(4) THEN usr.freeze = 1
IF KEYSTATE(5) THEN usr.freeze = 0
ENDIF
ENDFUNCTION
FUNCTION math_setup()
`setup required vectors for distance calculations
null = MAKE VECTOR3(1)
null = MAKE VECTOR2(2)
#CONSTANT vecDist3D = 1
#CONSTANT vecDist2D = 2
ENDFUNCTION
FUNCTION math_getDist2D(X1#,Y1#,X2#,Y2#)
SET VECTOR2 vecDist2D,X1#-X2#,Y1#-Y2#
dist# = LENGTH VECTOR2(vecDist2D)
ENDFUNCTION dist#
Connecting/Requirements
To compile the code, you'll need Darkbasic Pro (Darkbasic Classic
might work) and the latest release of
Benjamin's Tempest plugin. I also recommend you switch the project to Windowed Mode, so you can easily switch back and forth between it.
Connecting is pretty self explanatory.
a) Enter your desired user name
b) If you will be hosting, enter your IP Address, if you'll be joining a game, enter the host's IP Address. You can get your IP from
www.whatismyip.com. If you want to test the game with yourself, use the loopback address, 127.0.0.1
c) Enter H for host or C for client (join)
Connection Notes
Last off, make sure that both the host and client have the program in the allow list of their firewalls if they have a firewall set up. Also, being behind a router *may* cause connection problems as well, if thats the case, try joining someone else's game who is not behind a router, usually you can join but not host if behind one.
Also, the engine only supports 2 players. Dont try to connect with 3 players, a connection failure will occur for the 3rd player. Modding the source to allow for more than 2 players requires quite a big overhaul in converting a bunch of variables into arrays and data types.
------------------
Have fun, Ill try to keep the source updated and Ill get to commenting/debugging later this weekend hopefully. Post any comments/ideas/questions here, and feel free to use the source code in any of your games if you see fit.
- RUC'