' After Dark ' ' A tunginobi mini-RPG written in FreeBASIC. ' Zombies, vampires and other ghoulish things. ' ' Controls: ' Cursor keys Move ' Escape Quit ' Space bar Confirm ' Enter Main menu ' a Move the NPC clone ' ' http://www.spheredev.net/~tunginobi/ ' tunginobi@hotmail.com ' #define GAME_VERSION "0.0.2" '#define DEBUG_MODE #define PI (4 * atn(1)) #define TileToPixelX(x) (x) * TILE_WIDTH #define TileToPixelY(y) ((y) + 1) * TILE_HEIGHT #define PlayerEquipWeight (player.gun.weight + player.arm.weight) #define PlayerTechLevel (player.gun.techLevel + player.arm.techLevel) #define PlayerAccMod (player.gun.accMod - iif(PlayerEquipWeight > player.com.level, PlayerEquipWeight - player.com.level, 0)) #define PlayerEvaMod (player.gun.evaMod + player.arm.evaMod - iif(PlayerEquipWeight > player.com.level, PlayerEquipWeight - player.com.level, 0)) #define PlayerSpdMod (player.gun.spdMod + player.arm.spdMod - iif(PlayerEquipWeight > player.com.level, PlayerEquipWeight - player.com.level, 0)) #define PlayerStrMod 0 #define PlayerDefMod player.arm.defMod #define PlayerAccFinal iif(player.com.acc + PlayerAccMod > 0, player.com.acc + PlayerAccMod, 1) #define PlayerEvaFinal iif(player.com.eva + PlayerEvaMod > 0, player.com.eva + PlayerEvaMod, 1) #define PlayerSpdFinal iif(player.com.spd + PlayerSpdMod > 0, player.com.spd + PlayerSpdMod, 1) #define PlayerStrFinal player.com.str #define PlayerDefFinal iif(player.com.def + PlayerDefMod > 0, player.com.def + PlayerDefMod, 1) #define NPCDone(i) (timer > npcs(i).dEnd) #define PickTilePtr(t, p) select case (t) : _ case 0 : (p) = Road : _ case 1 : (p) = Pavement : _ case 2 : (p) = RoadLineH : _ case 3 : (p) = RoadLineV : _ case 4 : (p) = StormDrain : _ case 50 : (p) = Blackness : _ case 51 : (p) = WallTop : _ case 52 : (p) = GreyWall : _ case 53 : (p) = GlassPane : _ case 54 : (p) = TrashCan : _ case 55 : (p) = TippedTrashCan : _ end select #define BlitMapScreen call DrawMap : _ call DrawEntities : _ call DrawPlayer( TileToPixelX(px), TileToPixelY(py) ) : _ call DrawInfo : _ screensync : _ screencopy : _ sleep 1 #define BlitTextBox call DrawMap : _ call DrawEntities : _ call DrawPlayer( TileToPixelX(px), TileToPixelY(py) ) : _ call DrawInfo : _ call DrawTextBox( tag, " " & line1, " " & line2, " " & line3 ) : _ screensync : _ screencopy : _ sleep 1 #define BlitPrompt call DrawMap : _ call DrawEntities : _ call DrawPlayer( TileToPixelX(px), TileToPixelY(py) ) : _ call DrawInfo : _ call DrawTextBox( tag, " " & line1, " " & line2, " " & line3 ) : _ call DrawYesNo( choice ) : _ screensync : _ screencopy : _ sleep 1 #define BlitMainMenu call DrawMap : _ call DrawEntities : _ call DrawPlayer( TileToPixelX(px), TileToPixelY(py) ) : _ call DrawInfo : _ call DrawMainMenu( menuPage, itemIndex ) : _ screensync : _ screencopy : _ sleep 1 option explicit defint a-z ' Subs and functions declare sub InitVars () declare sub LoadMaps () declare sub LoadGraphics () declare sub LoadTiles () declare sub LoadSprites () declare sub UnloadGraphics () declare sub UnloadTiles () declare sub UnloadSprites () declare sub DrawMap () declare sub DrawInfo () declare sub DrawEntities () declare sub DrawPlayer (x as integer, y as integer) declare sub DrawTextBox (line1 as string, line2 as string, line3 as string, line4 as string) declare sub DrawYesNo (choice as integer) declare sub DrawMeter (x as integer, y as integer, w as integer, h as integer, amnt as integer, max as integer, col as integer) declare function TileBlocked (tx as integer, ty as integer) as integer declare sub HandleMapInput () declare sub MovePlayer (direction as integer) declare sub TextBox (who as string, line1 as string, line2 as string, line3 as string) declare function PromptYesNo (who as string, line1 as string, line2 as string, line3 as string) as integer declare sub EquipWeapon (wpn as integer) declare sub EquipArmour (arm as integer) declare function GetWeapon () as integer declare function GetArmour () as integer declare sub CalcXPPenalty () declare sub MainMenu () declare sub DrawMainMenu (p as integer, itm as integer) declare sub DrawClock () declare sub DrawTab (x1 as integer, y1 as integer, x2 as integer, y2 as integer) declare sub DrawMMStats () declare sub DrawMMGun () declare sub DrawMMArm () declare sub DrawMMItem (itm as integer) declare sub DrawMMExit () declare function UseItem (itm as integer) as integer declare sub MenuUseItem (itm as integer) declare sub BattleUseItem (itm as integer) declare sub MoveNPC (idx as integer, dirn as integer) declare sub CheckInteract () declare function CheckChests () as integer declare function CheckNPCs () as integer declare sub ResetTalkCount () declare sub TalkToNPC (who as integer) ' Constants const FALSE = 0, TRUE = not FALSE const SCREEN_WIDTH = 320, SCREEN_HEIGHT = 240, SCREEN_DEPTH = 16, PAGES = 2 const TILE_WIDTH = 16, TILE_HEIGHT = 16 const MAP_COUNT = 1, MAP_WIDTH = 20, MAP_HEIGHT = 14 ' Main menu const MENU_STATS = 0, MENU_GUN = 1, MENU_ARM = 2, MENU_ITEM = 3, MENU_EXIT = 4 ' Items const ITEM_COUNT = 5 const ITEM_SALVE = 0, ITEM_TRAUMA = 1, ITEM_HPATCH = 2, ITEM_COFFEE = 3, ITEM_STIM = 4 ' NPCs const NPC_COUNT = 10 const NPC_JACK = 0, NPC_GEMMA = 1, NPC_XAVIER = 2, NPC_TOM = 3 const NPC_PASCAL = 4, NPC_VERITY = 5 const NPC_ZOMBIE1 = 6, NPC_ZOMBIE2 = 7, NPC_ZOMBIE3 = 8 const NPC_BREATHLESS_SERGEANT = 9 const ANIM_MOVE = 0, ANIM_FADE = 1 const MOVE_SPEED = 0.3, FADE_SPEED = 2 ' Weapons and armour const AMMO_STANDARD = 0, AMMO_ARMOURPIERCING = 1, AMMO_HOLLOWPOINT = 2 const WPN_REVOLVER = 0, WPN_GLOCK = 1, WPN_M14A1 = 2, WPN_XM8 = 3 const ARM_VEST = 0, ARM_PADDING = 1, ARM_KEVLAR = 2, ARM_BLAST = 3 ' Key codes const K_RIGHT = 77, K_UP = 72, K_LEFT = 75, K_DOWN = 80 const K_SPACEBAR = 57, K_ENTER = 28, K_ESC = 1 ' Game types type Weapon tag as string ' I'd use "name", but that's a keyword :( techLevel as integer ' Used to calculate xp penalties weight as integer ' Penalises accuracy, evasion, speed ammoType as integer rounds as integer clipSize as integer burst as integer ' Number of rounds fired per shot jammed as integer jamChance as single ' Chance of weapon jamming per round accMod as integer evaMod as integer spdMod as integer end type type Armour tag as string techLevel as integer ' Used to calculate xp penalties weight as integer ' Penalises accuracy, evasion, speed defMod as integer ' Defensive bonus evaMod as integer ' Evasion penalty spdMod as integer ' Speed penalty end type type Combatant tag as string ' I'd use "name", but that's a keyword :( boss as integer ' True for bosses level as integer xp as integer xpLimit as integer ' Rises by 100 for each level xpPenalty as single ' Multiplier to received xp hp as integer hpMax as integer sp as integer spMax as integer str as integer ' Physical strength def as integer ' Physical toughness acc as integer ' Accuracy of attacks eva as integer ' Evasion against attacks spd as integer ' Speed of actions end type type Hero tag as string ' I'd use "name", but that's a keyword :( com as Combatant gun as Weapon arm as Armour ' Ammo ammoStd as integer ' Amount of standard ammo that is being carried ammoStdMax as integer ' Maximum standard ammo that can be carried ammoAP as integer ' Armourpiercing (2x damage vs. hard) ammoAPMax as integer ' Armourpiercing maximum ammoHP as integer ' Hollowpoint (2x damage vs. soft) ammoHPMax as integer ' Hollowpoint maximum ' Inventory itemMax as integer ' Maximum multiple of items salveCount as integer ' Heals 30% HP traumaFixPillCount as integer ' Heals 50% HP hPatchCount as integer ' Heals 100% HP coffeeTabletCount as integer ' Recovers 50% SP stimPillCount as integer ' Recovers 100% SP end type type Map tag as string terrain as string tiles(0 to MAP_WIDTH - 1, 0 to MAP_HEIGHT - 1) as integer end type type NPC tag as string sprite1 as any ptr ' Image buffer POINTERS: sprite2 as any ptr ' Point to preallocated images ONLY visible as integer map as integer x as integer y as integer dx as integer dy as integer dStart as double dEnd as double animate as integer talkCount as integer end type type Chest contents as integer taken as integer map as integer x as integer y as integer end type ' Game variables dim shared quitGame as integer = FALSE dim shared playTimeStart as double dim shared playTimeOffset as double = 0 dim shared player as Hero dim shared enemy as Combatant dim shared encounter as integer dim shared npcs(NPC_COUNT - 1) as NPC dim shared as integer px, py ' Player tile position dim shared playerMap as integer dim shared safeDeath as integer dim shared mapData(MAP_COUNT - 1) as Map dim shared displayMap as integer ' Map tiles, 16 x 16 dim shared Road as any ptr ' 0 dim shared Pavement as any ptr ' 1 dim shared RoadLineH as any ptr ' 2 dim shared RoadLineV as any ptr ' 3 dim shared StormDrain as any ptr ' 4 dim shared Blackness as any ptr ' 50 dim shared WallTop as any ptr ' 51 dim shared GreyWall as any ptr ' 52 dim shared GlassPane as any ptr ' 53 dim shared TrashCan as any ptr ' 54 dim shared TippedTrashCan as any ptr' 55 ' Sprites dim shared Jack1 as any ptr dim shared Jack2 as any ptr ' ----==== MAIN PROGRAM ====---- windowtitle "After Dark " & GAME_VERSION print "After Dark "; GAME_VERSION print "Build date: "; __DATE__ print "Build time: "; __TIME__; " AEST +10h" print print "Press any key to continue" sleep #ifdef DEBUG_MODE screenres SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, PAGES #else screenres SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, PAGES, 1 #endif screenset 0, 1 call InitVars call LoadGraphics call LoadMaps ' Turn off cursor and mouse cursor locate , , 0 setmouse 0, 0, 0 ' Start the clock! playTimeStart = timer do call HandleMapInput BlitMapScreen loop until quitGame = TRUE call UnloadGraphics end 0 ' ----==== END MAIN ====---- sub InitVars () with player .tag = "Jack" .com.tag = .tag .com.level = 1 .com.xp = 0 .com.xpLimit = 20 .com.xpPenalty = 1 .com.hpMax = 20 .com.hp = .com.hpMax .com.spMax = 10 .com.sp = .com.spMax .com.str = 1 .com.def = 5 .com.acc = 5 .com.eva = 5 .com.spd = 5 .ammoStdMax = 30 .ammoStd = .ammoStdMax .ammoAPMax = 30 .ammoAP = 0 .ammoHPMax = 30 .ammoHP = 0 .itemMax = 9 .salveCount = 3 .traumaFixPillCount = 0 .hPatchCount = 0 .coffeeTabletCount = 3 .stimPillCount = 0 end with call EquipWeapon( WPN_REVOLVER ) call EquipArmour( ARM_VEST ) px = 8 py = 5 encounter = 0 safeDeath = TRUE playerMap = 0 displayMap = 0 end sub sub LoadMaps () dim as integer x, y, m for m = 0 to MAP_COUNT - 1 with mapData(m) read .tag read .terrain for y = 0 to MAP_HEIGHT - 1 for x = 0 to MAP_WIDTH - 1 read .tiles(x, y) next next end with next end sub sub LoadGraphics () call LoadSprites call LoadTiles end sub sub LoadSprites () dim i as integer Jack1 = imagecreate(TILE_WIDTH, TILE_HEIGHT) Jack2 = imagecreate(TILE_WIDTH, TILE_HEIGHT) bload "jack1.bmp", Jack1 bload "jack2.bmp", Jack2 npcs(NPC_JACK).sprite1 = Jack1 npcs(NPC_JACK).sprite2 = Jack2 for i = 0 to NPC_COUNT - 1 npcs(i).visible = TRUE next i end sub sub LoadTiles () Road = imagecreate(TILE_WIDTH, TILE_HEIGHT) Pavement = imagecreate(TILE_WIDTH, TILE_HEIGHT) RoadLineH = imagecreate(TILE_WIDTH, TILE_HEIGHT) RoadLineV = imagecreate(TILE_WIDTH, TILE_HEIGHT) StormDrain = imagecreate(TILE_WIDTH, TILE_HEIGHT) bload "road.bmp", Road bload "pavement.bmp", Pavement bload "roadlineh.bmp", RoadLineH bload "roadlinev.bmp", RoadLineV bload "stormdrain.bmp", StormDrain Blackness = imagecreate(TILE_WIDTH, TILE_HEIGHT, rgb(0, 0, 0)) WallTop = imagecreate(TILE_WIDTH, TILE_HEIGHT) GreyWall = imagecreate(TILE_WIDTH, TILE_HEIGHT) GlassPane = imagecreate(TILE_WIDTH, TILE_HEIGHT) TrashCan = imagecreate(TILE_WIDTH, TILE_HEIGHT) TippedTrashCan = imagecreate(TILE_WIDTH, TILE_HEIGHT) bload "walltop.bmp", WallTop bload "greywall.bmp", GreyWall bload "glasspane.bmp", GlassPane bload "trashcan.bmp", TrashCan bload "tippedtrashcan.bmp", TippedTrashCan end sub sub UnloadGraphics () call UnloadSprites call UnloadTiles end sub sub UnloadSprites () imagedestroy Jack1 imagedestroy Jack2 Jack1 = 0 Jack2 = 0 end sub sub UnloadTiles () imagedestroy Road imagedestroy Pavement imagedestroy RoadLineH imagedestroy RoadLineV imagedestroy StormDrain Road = 0 Pavement = 0 RoadLineH = 0 RoadLineV = 0 StormDrain = 0 imagedestroy Blackness imagedestroy WallTop imagedestroy GreyWall imagedestroy GlassPane imagedestroy TrashCan imagedestroy TippedTrashCan Blackness = 0 WallTop = 0 GreyWall = 0 GlassPane = 0 TrashCan = 0 TippedTrashCan = 0 end sub sub DrawMap () dim as integer x, y, tile dim tilePtr as any ptr = 0 for y = 0 to MAP_HEIGHT - 1 for x = 0 to MAP_WIDTH - 1 tile = mapData(displayMap).tiles(x, y) ' Draw the correct tile for the position PickTilePtr(tile, tilePtr) if tilePtr <> 0 then put (TileToPixelX(x), TileToPixelY(y)), tilePtr, PSET end if tilePtr = 0 next next end sub sub DrawInfo () dim ammoTypeStr as string dim ammoHeld as integer dim ammoMax as integer ' Clean the info area line (0, 0)-(319, 15), rgb(0, 0, 0), BF ' Draw HP info color rgb(255, 255, 255), rgb(0, 0, 0) locate 1, 1 : print using "HP ###"; player.com.hp call DrawMeter( 0 * 8, 1 * 8, 6 * 8, 1 * 8, player.com.hp, player.com.hpMax, rgb(255, 0, 0) ) ' Draw SP info locate 1, 8 : print using "SP ###"; player.com.sp call DrawMeter( 7 * 8, 1 * 8, 6 * 8, 1 * 8, player.com.sp, player.com.spMax, rgb(0, 128, 128) ) ' Draw ammo info select case player.gun.ammoType case AMMO_STANDARD ammoTypeStr = "St" ammoHeld = player.ammoStd ammoMax = player.ammoStdMax case AMMO_ARMOURPIERCING ammoTypeStr = "AP" ammoHeld = player.ammoAP ammoMax = player.ammoAPMax case AMMO_HOLLOWPOINT ammoTypeStr = "HP" ammoHeld = player.ammoHP ammoMax = player.ammoHPMax end select locate 1, 15 print "A:"; ammoTypeStr locate 1, 20 print using "##/###"; player.gun.rounds, ammoHeld call DrawMeter( 14 * 8, 1 * 8, 11 * 8, 4, player.gun.rounds, player.gun.clipSize, rgb(0, 128, 0) ) call DrawMeter( 14 * 8, 1 * 8 + 3, 11 * 8, 5, ammoHeld, ammoMax, rgb(192, 128, 0) ) ' Finally, draw location info color rgb(172, 172, 172), rgb(0, 0, 0) locate 1, 27 : print "Location" color rgb(255, 255, 255), rgb(0, 0, 0) locate 2, 40 - len(mapData(displayMap).tag) : print mapData(displayMap).tag end sub sub DrawEntities () dim as integer i, x, y dim state as double dim spriteImage as any ptr for i = 0 to NPC_COUNT - 1 with npcs(i) if .map = displayMap then if NPCDone(i) then x = TileToPixelX(.x) y = TileToPixelY(.y) else ' Animation state = (timer - .dStart) / (.dEnd - .dStart) select case .animate case ANIM_MOVE state = 1 - state ' Now runs from 0 to 1 if state > 1 then state = 1 x = TileToPixelX(.x) + cint(.dx * state) y = TileToPixelY(.y) + cint(.dy * state) end select end if if .visible = TRUE then if ((timer * 10) mod 10) < 5 then spriteImage = .sprite1 else spriteImage = .sprite2 end if if spriteImage <> 0 then put (x, y), spriteImage, TRANS end if end if end with next i end sub sub DrawPlayer (x as integer, y as integer) ' Calculate animation frame if playerMap = displayMap then if (timer * 10) mod 10 < 5 then put (x, y), Jack1, TRANS else put (x, y), Jack2, TRANS end if end if end sub function TileBlocked (tx as integer, ty as integer) as integer dim blocked as integer dim i as integer if tx >= 0 and ty >= 0 and tx < MAP_WIDTH and ty < MAP_HEIGHT then if mapData(displayMap).tiles(tx, ty) >= 50 then blocked = TRUE else blocked = FALSE for i = 0 to NPC_COUNT - 1 if npcs(i).x = tx and npcs(i).y = ty then blocked = TRUE exit for end if next i end if else blocked = TRUE end if return blocked end function sub HandleMapInput () dim k as string k = inkey$ if multikey(K_RIGHT) then if px < MAP_WIDTH then ' Move if TileBlocked(px + 1, py) = FALSE then call MovePlayer( K_RIGHT ) end if else ' Potential map warp end if elseif multikey(K_UP) then if py > 0 then ' Move if TileBlocked(px, py - 1) = FALSE then call MovePlayer( K_UP ) end if else ' Potential map warp '12345678901234567890123456789012345 call TextBox( "Jack", _ "There's nothing in this direction", _ "at the moment. I suppose I should", _ "come back later.") end if elseif multikey(K_LEFT) then if px > 0 then ' Move if TileBlocked(px - 1, py) = FALSE then call MovePlayer( K_LEFT ) end if else ' Potential map warp end if elseif multikey(K_DOWN) then if py < MAP_HEIGHT then ' Move if TileBlocked(px, py + 1) = FALSE then call MovePlayer( K_DOWN ) end if else ' Potential map warp end if end if ' Check conventional key buffer if k = chr(32) then ' Space bar ' Action! call CheckInteract elseif k = chr(13) then ' Enter ' Menu call MainMenu elseif k = chr(27) then ' Escape ' Quit the game quitGame = PromptYesNo("", "Are you sure you want to quit?", "", "") elseif k = "a" then ' TODO: Remove this when done experimenting ' Debug: Move NPC call MoveNPC( NPC_JACK, K_RIGHT ) call MoveNPC( NPC_JACK, K_RIGHT ) do : BlitMapScreen : loop until NPCDone(NPC_JACK) call MoveNPC( NPC_JACK, K_DOWN ) do : BlitMapScreen : loop until NPCDone(NPC_JACK) end if end sub sub MovePlayer (direction as integer) dim as integer dx, dy dim startTime as double dim state as double startTime = timer ' Note to self: TIMER is in seconds! dx = 0 dy = 0 select case direction case K_RIGHT px += 1 dx = -TILE_WIDTH case K_UP py -= 1 dy = TILE_HEIGHT case K_LEFT px -= 1 dx = TILE_WIDTH case K_DOWN py += 1 dy = -TILE_HEIGHT end select do state = (timer - startTime) / MOVE_SPEED state = 1 - state if state < 0 then state = 0 if state > 1 then state = 1 call DrawMap call DrawEntities call DrawPlayer( TileToPixelX(px) + cint(dx * state), TileToPixelY(py) + cint(dy * state) ) call DrawInfo screensync screencopy sleep 1 loop until timer > startTime + MOVE_SPEED end sub sub DrawTextBox (line1 as string,line2 as string, line3 as string, line4 as string) ' Lines should be 36 chars max line (1 * 8 + 3, 23 * 8 + 3)-(38 * 8 + 4, 28 * 8 + 4), rgb(0, 0, 128), BF line (1 * 8 + 3, 23 * 8 + 3)-(38 * 8 + 4, 28 * 8 + 4), rgb(255, 255, 255), B color rgb(255, 255, 255), rgb(0, 0, 128) locate 25, 3 : print line1 locate 26, 3 : print line2 locate 27, 3 : print line3 locate 28, 3 : print line4 color rgb(255, 255, 255), rgb(0, 0, 0) end sub sub TextBox (who as string, line1 as string, line2 as string, line3 as string) ' 35 chars per line max, for presentation ' 12345678901234567890123456789012345 dim tag as string = "" if not (strptr(who) = 0) then tag = who + ":" while inkey$ <> "" : wend do BlitTextBox loop until inkey$ = " " end sub sub DrawYesNo (choice as integer) ' Yes = TRUE, No = FALSE dim state as double state = (timer * 1000 mod 1000) / 1000 line (32 * 8 + 3, 19 * 8 + 3)-(38 * 8 + 4, 22 * 8 + 4), rgb(0, 0, 128), BF line (32 * 8 + 3, 19 * 8 + 3)-(38 * 8 + 4, 22 * 8 + 4), rgb(255, 255, 255), B color rgb(cint(sin(state * PI) * 255), 255, cint(sin(state * PI) * 255)), rgb(0, 0, 128) if choice = TRUE then locate 21, 34 : print ">" locate 21, 36 : print "Yes" color rgb(255, 255, 255) locate 22, 36 : print "No" elseif choice = FALSE then locate 22, 34 : print ">" locate 22, 36 : print "No" color rgb(255, 255, 255) locate 21, 36 : print "Yes" end if color rgb(255, 255, 255), rgb(0, 0, 0) end sub sub DrawMeter (x as integer, y as integer, w as integer, h as integer, amnt as integer, max as integer, col as integer) dim as integer x1, y1, x2, y2 dim state as double dim bar as integer dim bg as integer = rgb(192, 192, 192) x1 = x y1 = y x2 = x + w - 1 y2 = y + h - 1 state = amnt / max if state < 0 then state = 0 if state > 1 then state = 1 bar = int((w - 3) * state + 0.5) line (x1, y1)-(x2, y2), rgb(0, 0, 0), BF line (x1, y1)-(x2, y2), bg, B line (x1 + 1, y1 + 1)-(x1 + 1 + bar, y2 - 1), col, BF end sub function PromptYesNo (who as string, line1 as string, line2 as string, line3 as string) as integer ' Yes = TRUE, No = FALSE dim k as string dim tag as string = "" dim choice as integer = TRUE dim lastPress as double ' In seconds! if not (strptr(who) = 0) then tag = who & ":" while inkey$ <> "" : wend ' Input loop do k = inkey$ if k = chr(255) + chr(K_UP) then choice = TRUE if k = chr(255) + chr(K_DOWN) then choice = FALSE BlitPrompt loop until k = " " while inkey$ <> "" : wend return choice end function sub EquipWeapon (wpn as integer) ' WPN_REVOLVER = 0, WPN_GLOCK = 1, WPN_M14A1 = 2, WPN_XM8 = 3 with player.gun select case wpn case WPN_REVOLVER .tag = "Revolver" .techLevel = 1 .weight = 1 .ammoType = AMMO_STANDARD .rounds = 6 .clipSize = 6 .burst = 2 .jammed = FALSE .jamChance = 0 .accMod = 0 .evaMod = 0 .spdMod = -1 case WPN_GLOCK .tag = "Glock" .techLevel = 3 .weight = 2 .ammoType = AMMO_HOLLOWPOINT .rounds = 19 .clipSize = 19 .burst = 3 .jammed = FALSE .jamChance = 0.1 .accMod = 4 .evaMod = 0 .spdMod = -2 case WPN_M14A1 .tag = "M14A1 Rifle" .techLevel = 5 .weight = 1 .ammoType = AMMO_STANDARD .rounds = 30 .clipSize = 30 .burst = 5 .jammed = FALSE .jamChance = 0.2 .accMod = 5 .evaMod = -2 .spdMod = -3 case WPN_XM8 .tag = "XM8 Assault Rifle" .techLevel = 7 .weight = 1 .ammoType = AMMO_ARMOURPIERCING .rounds = 65 .clipSize = 65 .burst = 8 .jammed = FALSE .jamChance = 0.3 .accMod = 7 .evaMod = -3 .spdMod = -4 end select end with call CalcXPPenalty end sub sub EquipArmour (arm as integer) ' ARM_VEST = 0, ARM_PADDING = 1, ARM_KEVLAR = 2, ARM_BLAST = 3 with player.arm select case arm case ARM_VEST .tag = "Vest" .techLevel = 1 .weight = 1 .defMod = 1 .evaMod = -1 .spdMod = 0 case ARM_PADDING .tag = "Padding" .techLevel = 2 .weight = 2 .defMod = 3 .evaMod = -2 .spdMod = -2 case ARM_KEVLAR .tag = "Kevlar Vest" .techLevel = 4 .weight = 5 .defMod = 8 .evaMod = -5 .spdMod = -4 case ARM_BLAST .tag = "Blast Suit" .techLevel = 6 .weight = 10 .defMod = 15 .evaMod = -9 .spdMod = -7 end select end with call CalcXPPenalty end sub function GetWeapon () as integer dim wpn as integer select case player.gun.tag case "Revolver" : wpn = WPN_REVOLVER case "Glock" : wpn = WPN_GLOCK case "M14A1 Rifle" : wpn = WPN_M14A1 case "XM8 Assault Rifle" : wpn = WPN_XM8 end select return wpn end function function GetArmour () as integer dim arm as integer select case player.arm.tag case "Vest" : arm = ARM_VEST case "Padding" : arm = ARM_PADDING case "Kevlar Vest" : arm = ARM_KEVLAR case "Blast Suit" : arm = ARM_BLAST end select return arm end function sub CalcXPPenalty () player.com.xpPenalty = 1 - PlayerTechLevel / 10 if player.com.xpPenalty < 0.01 then player.com.xpPenalty = 0.01 end sub sub MainMenu () dim k as string dim menuDone as integer dim menuPage as integer dim itemIndex as integer ' There are five menu pages: ' Stats, Gun, Arm, Item and Exit menuDone = FALSE menuPage = 0 itemIndex = 0 do ' Use the conventional key buffer for key presses k = inkey$ select case k case chr(255) & chr(K_LEFT) menuPage -= 1 if menuPage < 0 then menuPage = 4 case chr(255) & chr(K_RIGHT) menuPage += 1 if menuPage > 4 then menuPage = 0 case chr(255) & chr(K_UP) if menuPage = MENU_ITEM then itemIndex -= 1 if itemIndex < 0 then itemIndex = ITEM_COUNT - 1 end if case chr(255) & chr(K_DOWN) if menuPage = MENU_ITEM then itemIndex += 1 if itemIndex >= ITEM_COUNT then itemIndex = 0 end if end if case " " ' Space bar confirms things if menuPage = MENU_ITEM then call MenuUseItem( itemIndex ) elseif menuPage = MENU_EXIT then menuDone = TRUE end if case chr(13) ' Enter is a shortcut to leave the menu menuDone = TRUE end select ' Draw it all BlitMainMenu loop until menuDone = TRUE end sub sub DrawMainMenu (p as integer, itm as integer) dim state as double ' Draw boxes color rgb(255, 255, 255), rgb(0, 0, 128) ' Menu page selector line (4 * 8 + 3, 3 * 8 + 3)-(35 * 8 + 4, 5 * 8 + 4), rgb(0, 0, 128), BF line (4 * 8 + 3, 3 * 8 + 3)-(35 * 8 + 4, 5 * 8 + 4), rgb(255, 255, 255), B ' Menu page line (4 * 8 + 3, 6 * 8 + 3)-(35 * 8 + 4, 26 * 8 + 4), rgb(0, 0, 128), BF line (4 * 8 + 3, 6 * 8 + 3)-(35 * 8 + 4, 26 * 8 + 4), rgb(255, 255, 255), B ' Menu page description line (4 * 8 + 3, 27 * 8 + 3)-(24 * 8 + 4, 29 * 8 + 4), rgb(0, 0, 128), BF line (4 * 8 + 3, 27 * 8 + 3)-(24 * 8 + 4, 29 * 8 + 4), rgb(255, 255, 255), B ' Game clock call DrawClock ' Draw main menu items locate 5, 6 : print " Stats Gun Arm Item Exit " state = ((timer * 1000) mod 1000) / 1000 color rgb(cint(sin(state * PI) * 255), 255, cint(sin(state * PI) * 255)) ' Draw the current menu page select case p case MENU_STATS call DrawTab( 4 * 8 + 3, 3 * 8 + 3, 12 * 8 + 4, 6 * 8 + 3 ) locate 5, 6 print "" call DrawMMStats case MENU_GUN call DrawTab( 11 * 8 + 3, 3 * 8 + 3, 17 * 8 + 4, 6 * 8 + 3 ) locate 5, 13 print "" call DrawMMGun case MENU_ARM call DrawTab( 16 * 8 + 3, 3 * 8 + 3, 22 * 8 + 4, 6 * 8 + 3 ) locate 5, 18 print "" call DrawMMArm case MENU_ITEM call DrawTab( 21 * 8 + 3, 3 * 8 + 3, 28 * 8 + 4, 6 * 8 + 3 ) locate 5, 23 print "" call DrawMMItem( itm ) case MENU_EXIT call DrawTab( 28 * 8 + 3, 3 * 8 + 3, 35 * 8 + 4, 6 * 8 + 3 ) locate 5, 30 print "" call DrawMMExit end select color rgb(255, 255, 255), rgb(0, 0, 0) end sub sub DrawClock () dim as integer hrs, min, sec dim as string hrsStr, minStr, secStr dim pt as double pt = timer - playTimeStart + playTimeOffset sec = cint(pt) mod 60 min = cint((pt - sec) / 60) mod 60 hrs = cint((pt - min * 60 - sec) / 3600) mod 1000 secStr = "" if sec < 10 then secStr = "0" secStr = secStr & sec minStr = "" if min < 10 then minStr = "0" minStr = minStr & min hrsStr = "" if hrs < 100 then hrsStr = "00" elseif hrs < 10 then hrsStr = "0" end if hrsStr = hrsStr & hrs line (25 * 8 + 3, 27 * 8 + 3)-(35 * 8 + 4, 29 * 8 + 4), rgb(0, 0, 128), BF line (25 * 8 + 3, 27 * 8 + 3)-(35 * 8 + 4, 29 * 8 + 4), rgb(255, 255, 255), B locate 29, 27 if ((timer * 10) mod 10) < 5 then print hrsStr; ":"; minStr; ":"; secStr else print hrsStr; " "; minStr; " "; secStr end if end sub sub DrawTab (x1 as integer, y1 as integer, x2 as integer, y2 as integer) line (x1, y1)-(x2, y2), rgb(255, 255, 255), B line (x1 + 1, y1 + 1)-(x2 - 1, y2), rgb(0, 0, 128), BF end sub sub DrawMMStats () dim hunterRank as string ' Jack's stats ' Figure out Jack's hunter rank if player.com.level > 0 then hunterRank = "Recruit" end if ' Little Jack portrait :) if (timer * 10) mod 10 < 5 then put (6 * 8, 8 * 8), Jack1, TRANS else put (6 * 8, 8 * 8), Jack2, TRANS end if color rgb(255, 255, 255), rgb(0, 0, 128) locate 8, 10 print "Jack" line (9 * 8, 8 * 8 + 3)-(34 * 8, 8 * 8 + 3), rgb(255, 255, 255) locate 10, 10 print "Hunter "; hunterRank locate 12, 10 print using "Level ##############"; player.com.level locate 13, 10 print using "Experience ######/######"; player.com.xp, player.com.xpLimit locate 14, 10 print using "Exp_. gain ###_%"; cint(player.com.xpPenalty * 100) locate 16, 10 print using "Hit points ###/###"; player.com.hp, player.com.hpMax locate 17, 10 print using "Skill points ###/###"; player.com.sp, player.com.spMax color rgb(128, 128, 128), rgb(0, 0, 128) locate 19, 10 print "STAT BASE MOD FINAL" color rgb(255, 255, 255), rgb(0, 0, 128) ' TODO: Replace with _real_ stats. locate 21, 10 print using "Accuracy ### ### ###"; player.com.acc, PlayerAccMod, PlayerAccFinal locate 22, 10 print using "Evasion ### ### ###"; player.com.eva, PlayerEvaMod, PlayerEvaFinal locate 23, 10 print using "Speed ### ### ###"; player.com.spd, PlayerSpdMod, PlayerSpdFinal locate 25, 10 print using "Strength ### ### ###"; player.com.str, PlayerStrMod, PlayerStrFinal locate 26, 10 print using "Defense ### ### ###"; player.com.def, PlayerDefMod, PlayerDefFinal locate 29, 6 print "Character status" color rgb(255, 255, 255), rgb(0, 0, 0) end sub sub DrawMMGun () dim as string ammoTypeStr, gunJammedStr dim as integer ammoHeld, ammoMax select case player.gun.ammoType case AMMO_STANDARD ammoTypeStr = "Standard" ammoHeld = player.ammoStd ammoMax = player.ammoStdMax case AMMO_HOLLOWPOINT ammoTypeStr = "Hollowpoint" ammoHeld = player.ammoHP ammoMax = player.ammoHPMax case AMMO_ARMOURPIERCING ammoTypeStr = "Armourpiercing" ammoHeld = player.ammoAP ammoMax = player.ammoAPMax end select if player.gun.jammed = TRUE then gunJammedStr = " (JAMMED)" else gunJammedStr = "" end if ' TODO: Draw the 24 * 16 image of the weapon here. color rgb(255, 255, 255), rgb(0, 0, 128) locate 8, 10 print player.gun.tag & gunJammedStr line (9 * 8, 8 * 8 + 3)-(34 * 8, 8 * 8 + 3), rgb(255, 255, 255) locate 10, 10 print using "Tech level ###"; player.gun.techLevel locate 11, 10 print using "Weight ###"; player.gun.weight locate 13, 10 : print "Ammunition" locate 13, 35 - len(ammoTypeStr) : print ammoTypeStr locate 14, 10 print using "Rounds per attack ###"; player.gun.burst locate 15, 10 print using "Loaded/clip size ###/###"; player.gun.rounds, player.gun.clipSize locate 16, 10 print using "Spare ammo ###/###"; ammoHeld, ammoMax locate 17, 10 print using "Jamming chance ###_%"; player.gun.jamChance color rgb(128, 128, 128), rgb(0, 0, 128) locate 19, 10 print "STAT BASE MOD" color rgb(255, 255, 255), rgb(0, 0, 128) locate 21, 10 print using "Accuracy ### ###"; player.gun.accMod, player.gun.accMod - iif(player.gun.weight > player.com.level, player.gun.weight - player.com.level, 0) locate 22, 10 print using "Evasion ### ###"; player.gun.evaMod, player.gun.evaMod - iif(player.gun.weight > player.com.level, player.gun.weight - player.com.level, 0) locate 23, 10 print using "Speed ### ###"; player.gun.spdMod, player.gun.spdMod - iif(player.gun.weight > player.com.level, player.gun.weight - player.com.level, 0) locate 25, 10 select case GetWeapon() case WPN_REVOLVER print "A reliable sidearm." case WPN_GLOCK print "A standard issue police" locate 26, 10 print "handgun." case WPN_M14A1 print "A military-grade carbine," locate 26, 10 print "for urban combat." case WPN_XM8 print "A powerful special-ops" locate 26, 10 print "automatic rifle." end select locate 29, 6 print "Weapon statistics" color rgb(255, 255, 255), rgb(0, 0, 0) end sub sub DrawMMArm () ' TODO: Draw the 24 * 16 armour image color rgb(255, 255, 255), rgb(0, 0, 128) locate 8, 10 print player.arm.tag line (9 * 8, 8 * 8 + 3)-(34 * 8, 8 * 8 + 3), rgb(255, 255, 255) locate 10, 10 print using "Tech level ###"; player.arm.techLevel locate 11, 10 print using "Weight ###"; player.arm.weight color rgb(128, 128, 128), rgb(0, 0, 128) locate 19, 10 print "STAT BASE MOD" color rgb(255, 255, 255), rgb(0, 0, 128) locate 21, 10 print using "Defense ### ###"; player.arm.defMod, player.arm.defMod locate 22, 10 print using "Evasion ### ###"; player.arm.evaMod, player.arm.evaMod - iif(player.arm.weight > player.com.level, player.arm.weight - player.com.level, 0) locate 23, 10 print using "Speed ### ###"; player.arm.spdMod, player.arm.spdMod - iif(player.arm.weight > player.com.level, player.arm.weight - player.com.level, 0) locate 25, 10 select case GetArmour() case ARM_VEST print "A vest reinforced with" locate 26, 10 print "armourweave fibres." case ARM_PADDING print "Armour with integrated" locate 26, 10 print "shock absorbers." case ARM_KEVLAR print "Military issue bullet-" locate 26, 10 print "proof body armour." case ARM_BLAST print "Special-ops blast-" locate 26, 10 print "resistant body armour." end select locate 29, 6 print "Armour statistics" color rgb(255, 255, 255), rgb(0, 0, 0) end sub sub DrawMMItem (itm as integer) dim state as double state = ((timer * 1000) mod 1000) / 1000 color rgb(255, 255, 255), rgb(0, 0, 128) locate 9, 7 print "Curatives" line (6 * 8, 9 * 8 + 3)-(34 * 8, 9 * 8 + 3), rgb(255, 255, 255) ' Handle salves if player.salveCount > 0 and player.com.hp < player.com.hpMax then if itm = ITEM_SALVE then ' Selected color rgb(cint(sin(state * PI) * 255), 255, cint(sin(state * PI) * 255)) else ' Active color rgb(255, 255, 255), rgb(0, 0, 128) end if else ' Inactive color rgb(172, 172, 172), rgb(0, 0, 128) end if if itm = ITEM_SALVE then locate 11, 6 print ">" end if locate 11, 8 print using "Salve x# 30_% HP"; player.salveCount ' Handle trauma fix pills if player.traumaFixPillCount > 0 and player.com.hp < player.com.hpMax then if itm = ITEM_TRAUMA then ' Selected color rgb(cint(sin(state * PI) * 255), 255, cint(sin(state * PI) * 255)) else ' Active color rgb(255, 255, 255), rgb(0, 0, 128) end if else ' Inactive color rgb(172, 172, 172), rgb(0, 0, 128) end if if itm = ITEM_TRAUMA then locate 12, 6 print ">" end if locate 12, 8 print using "Trauma Fix Pill x# 50_% HP"; player.traumaFixPillCount ' Handle H-Patches if player.hPatchCount > 0 and player.com.hp < player.com.hpMax then if itm = ITEM_HPATCH then ' Selected color rgb(cint(sin(state * PI) * 255), 255, cint(sin(state * PI) * 255)) else ' Active color rgb(255, 255, 255), rgb(0, 0, 128) end if else ' Inactive color rgb(172, 172, 172), rgb(0, 0, 128) end if if itm = ITEM_HPATCH then locate 13, 6 print ">" end if locate 13, 8 print using "H-Patch x# 100_% HP"; player.hPatchCount ' Handle coffee tablets if player.coffeeTabletCount > 0 and player.com.sp < player.com.spMax then if itm = ITEM_COFFEE then ' Selected color rgb(cint(sin(state * PI) * 255), 255, cint(sin(state * PI) * 255)) else ' Active color rgb(255, 255, 255), rgb(0, 0, 128) end if else ' Inactive color rgb(172, 172, 172), rgb(0, 0, 128) end if if itm = ITEM_COFFEE then locate 15, 6 print ">" end if locate 15, 8 print using "Coffee Tablet x# 50_% SP"; player.coffeeTabletCount ' Handle stim pills if player.stimPillCount > 0 and player.com.sp < player.com.spMax then if itm = ITEM_STIM then ' Selected color rgb(cint(sin(state * PI) * 255), 255, cint(sin(state * PI) * 255)) else ' Active color rgb(255, 255, 255), rgb(0, 0, 128) end if else ' Inactive color rgb(172, 172, 172), rgb(0, 0, 128) end if if itm = ITEM_STIM then locate 16, 6 print ">" end if locate 16, 8 print using "Stim Pill x# 100_% SP"; player.stimPillCount ' Now handle the ammunition listing color rgb(255, 255, 255), rgb(0, 0, 128) locate 20, 7 print "Ammunition" line (6 * 8, 20 * 8 + 3)-(34 * 8, 20 * 8 + 3), rgb(255, 255, 255) if player.gun.ammoType = AMMO_STANDARD then color rgb(255, 255, 255), rgb(0, 0, 128) else color rgb(172, 172, 172), rgb(0, 0, 128) end if locate 22, 8 print using "Standard ###/###"; player.ammoStd, player.ammoStdMax if player.gun.ammoType = AMMO_ARMOURPIERCING then color rgb(255, 255, 255), rgb(0, 0, 128) else color rgb(172, 172, 172), rgb(0, 0, 128) end if locate 23, 8 print using "Armourpiercing ###/###"; player.ammoAP, player.ammoAPMax if player.gun.ammoType = AMMO_HOLLOWPOINT then color rgb(255, 255, 255), rgb(0, 0, 128) else color rgb(172, 172, 172), rgb(0, 0, 128) end if locate 24, 8 print using "Hollowpoint ###/###"; player.ammoHP, player.ammoHPMax color rgb(255, 255, 255), rgb(0, 0, 128) locate 29, 6 print "Carried inventory" color rgb(255, 255, 255), rgb(0, 0, 0) end sub sub DrawMMExit () color rgb(255, 255, 255), rgb(0, 0, 128) locate 16, 12 print "Press to" locate 17, 12 print "resume the game." locate 29, 6 print "Return to the game" color rgb(255, 255, 255), rgb(0, 0, 0) end sub function UseItem (itm as integer) as integer ' Returns: ' 0) Item was used ' 1) Item not used; none in stock ' 2) Item not used; not required dim usage as integer = 1 select case itm case ITEM_SALVE ' +30% HP if player.salveCount > 0 then if player.com.hp < player.com.hpMax then player.com.hp += cint(player.com.hpMax * 0.3) player.salveCount -= 1 usage = 0 else usage = 2 end if else usage = 1 end if case ITEM_TRAUMA ' +50% HP if player.traumaFixPillCount > 0 then if player.com.hp < player.com.hpMax then player.com.hp += cint(player.com.hpMax * 0.5) player.traumaFixPillCount -= 1 usage = 0 else usage = 2 end if else usage = 1 end if case ITEM_HPATCH ' +100% HP if player.hPatchCount > 0 then if player.com.hp < player.com.hpMax then player.com.hp = player.com.hpMax player.hPatchCount -= 1 usage = 0 else usage = 2 end if else usage = 1 end if case ITEM_COFFEE ' +50% SP if player.coffeeTabletCount > 0 then if player.com.sp < player.com.spMax then player.com.sp += cint(player.com.spMax * 0.5) player.coffeeTabletCount -= 1 usage = 0 else usage = 2 end if else usage = 1 end if case ITEM_STIM ' +100% SP if player.stimPillCount > 0 then if player.com.sp < player.com.spMax then player.com.sp = player.com.spMax player.stimPillCount -= 1 usage = 0 else usage = 2 end if else usage = 1 end if end select if player.com.hp > player.com.hpMax then player.com.hp = player.com.hpMax if player.com.sp > player.com.spMax then player.com.sp = player.com.spMax return usage end function sub MenuUseItem (itm as integer) dim k as string dim as string itemName, heal dim usage as integer dim as string line1, line2 usage = UseItem(itm) select case itm case ITEM_SALVE itemName = "Salve" heal = str(player.com.hpMax * 0.3) + " HP" case ITEM_TRAUMA itemName = "Trauma Fix Pill" heal = str(player.com.hpMax * 0.5) + " HP" case ITEM_HPATCH itemName = "H-Patch" heal = "All HP" case ITEM_COFFEE itemName = "Coffee Pill" heal = str(player.com.spMax * 0.5) + " SP" case ITEM_STIM itemName = "Stim Pill" heal = "All SP" end select line1 = itemName & " used." line2 = heal & " recovered." if usage = 0 then do k = inkey$ call DrawMap call DrawEntities call DrawPlayer( TileToPixelX(px), TileToPixelY(py) ) call DrawInfo call DrawMainMenu( MENU_ITEM, itm ) ' Draw the box line (7 * 8 + 3, 14 * 8 + 3)-(32 * 8 + 4, 17 * 8 + 4), rgb(0, 0, 128), BF line (7 * 8 + 3, 14 * 8 + 3)-(32 * 8 + 4, 17 * 8 + 4), rgb(255, 255, 255), B ' Draw the message color rgb(255, 255, 255), rgb(0, 0, 128) locate 16, 9 : print line1 locate 17, 9 : print line2 color rgb(255, 255, 255), rgb(0, 0, 0) screensync screencopy sleep 25 loop until k = " " end if end sub sub BattleUseItem (itm as integer) ' TODO: Write this battle stub! end sub sub MoveNPC (idx as integer, dirn as integer) dim state as double with npcs(idx) .animate = ANIM_MOVE if NPCDone(idx) then .dStart = timer .dEnd = timer + MOVE_SPEED select case dirn case K_RIGHT .x += 1 .dx = -TILE_WIDTH .dy = 0 case K_UP .y -= 1 .dx = 0 .dy = TILE_HEIGHT case K_LEFT .x -= 1 .dx = TILE_WIDTH .dy = 0 case K_DOWN .y += 1 .dx = 0 .dy = -TILE_HEIGHT end select else state = (timer - .dStart) / (.dEnd - .dStart) state = 1 - state .dEnd += MOVE_SPEED .dStart = timer select case dirn case K_RIGHT .x += 1 .dx = cint(.dx * state) - TILE_WIDTH .dy = cint(.dy * state) case K_UP .y -= 1 .dx = cint(.dx * state) .dy = cint(.dy * state) + TILE_HEIGHT case K_LEFT .x -= 1 .dx = cint(.dx * state) + TILE_WIDTH .dy = cint(.dy * state) case K_DOWN .y += 1 .dx = cint(.dx * state) .dy = cint(.dy * state) - TILE_HEIGHT end select end if end with end sub sub CheckInteract () if CheckChests() = FALSE then if CheckNPCs() = FALSE then ' Nothing was found ' 12345678901234567890123456789012345 call TextBox ("Jack", _ "There's nothing here.", _ "", _ "") end if end if end sub function CheckChests () as integer ' Returns TRUE if a chest was found, FALSE if otherwise. ' TODO: Add "chest" code. return FALSE end function function CheckNPCs () as integer dim i as integer dim spoken as integer = FALSE for i = 0 to NPC_COUNT - 1 if npcs(i).visible = TRUE and npcs(i).map = playerMap then if px = npcs(i).x + 1 and py = npcs(i).y then ' Check the NPC's east spoken = TRUE elseif px = npcs(i).x and py = npcs(i).y - 1 then ' Check the NPC's north spoken = TRUE elseif px = npcs(i).x - 1 and py = npcs(i).y then ' Check the NPC's west spoken = TRUE elseif px = npcs(i).x and py = npcs(i).y + 1 then ' Check the NPC's south spoken = TRUE end if if spoken = TRUE then call TalkToNPC( i ) exit for end if end if next i return spoken end function sub ResetTalkCount () dim i as integer for i = 0 to NPC_COUNT - 1 npcs(i).talkCount = 0 next i end sub sub TalkToNPC (who as integer) select case who case NPC_JACK if npcs(NPC_JACK).talkCount < 1 then ' What the...?! ' 12345678901234567890123456789012345 call TextBox( "Jack", _ "This guy looks just like me.", _ "How... odd.", _ "" ) end if ' 12345678901234567890123456789012345 call TextBox( "Other Jack", _ "Hi.", _ "", _ "" ) npcs(NPC_JACK).talkCount += 1 case NPC_GEMMA npcs(NPC_GEMMA).talkCount += 1 case NPC_XAVIER npcs(NPC_XAVIER).talkCount += 1 case NPC_TOM npcs(NPC_TOM).talkCount += 1 case NPC_PASCAL npcs(NPC_PASCAL).talkCount += 1 case NPC_VERITY npcs(NPC_VERITY).talkCount += 1 case else ' 12345678901234567890123456789012345 call TextBox( "Jack", _ "There's nobody here.", _ "", _ "" ) end select end sub ' ----==== MAP DATA ====---- ' All maps are 20 x 14 tiles ' 0) Test map! data "Streets"," open urban " data 51,51,51,51,51,51,1,0,0,3,0,0,1,51,50,50,50,50,50,50 data 52,52,52,52,52,52,1,0,0,0,0,0,1,51,50,50,50,50,50,50 data 0,55,0,0,0,0,1,0,0,3,0,0,1,51,51,51,51,50,50,50 data 55,0,55,55,0,0,3,0,0,0,0,0,1,52,53,53,51,50,50,50 data 51,51,51,51,51,51,1,0,0,3,0,0,1,0,1,54,51,51,51,51 data 50,50,50,50,50,51,1,2,2,2,2,2,1,1,0,1,52,53,53,53 data 50,50,50,50,50,51,1,0,0,0,0,0,3,0,0,0,0,0,0,55 data 50,50,50,50,51,51,1,0,0,0,0,0,3,0,0,0,0,0,0,0 data 50,50,50,51,51,52,1,2,2,2,2,2,1,51,51,51,51,51,51,51 data 50,50,50,51,52,0,1,0,0,3,0,0,1,51,50,50,50,50,50,50 data 50,50,50,51,55,0,1,4,0,0,0,0,1,51,50,50,50,50,50,50 data 50,50,50,51,51,51,1,0,0,3,0,0,1,51,50,50,50,50,50,50 data 50,50,50,50,50,51,54,0,0,0,0,0,1,51,50,50,50,50,50,50 data 50,50,50,50,50,51,1,0,0,3,0,0,1,51,50,50,50,50,50,50