Welcome, Guest
You have to register before you can post on our site.

Username/Email:
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 390
» Latest member: ahenry3068
» Forum threads: 2,330
» Forum posts: 22,885

Full Statistics

Latest Threads
Alphabetical sort of char...
Forum: Help Me!
Last Post: bplus
Less than 1 minute ago
» Replies: 46
» Views: 439
InForm-PE
Forum: a740g
Last Post: bplus
26 minutes ago
» Replies: 69
» Views: 4,102
Posting Error message is ...
Forum: Site Suggestions
Last Post: bplus
31 minutes ago
» Replies: 3
» Views: 42
GnomeSort
Forum: Utilities
Last Post: James D Jarvis
1 hour ago
» Replies: 2
» Views: 42
Space Explorer
Forum: Games
Last Post: johannhowitzer
3 hours ago
» Replies: 0
» Views: 21
print file
Forum: Utilities
Last Post: eoredson
10 hours ago
» Replies: 11
» Views: 255
How to reorder string var...
Forum: Help Me!
Last Post: PhilOfPerth
11 hours ago
» Replies: 13
» Views: 146
Program Containing All In...
Forum: Utilities
Last Post: TDarcos
11 hours ago
» Replies: 0
» Views: 15
String Addition (Optimiza...
Forum: Learning Resources and Archives
Last Post: bplus
Yesterday, 06:29 PM
» Replies: 8
» Views: 104
Another Mouse Issue?
Forum: Help Me!
Last Post: NakedApe
Yesterday, 06:19 AM
» Replies: 12
» Views: 131

 
  Space Explorer
Posted by: johannhowitzer - 3 hours ago - Forum: Games - No Replies

       

When I was a kid, we had a book called "Beyond Competition."  It contained a handful of cooperative games, the one I remember most fondly is "Space Explorer."  To play, compile the code and make sure the following resource file is in the same folder:


.mfi   resource.mfi (Size: 918.14 KB / Downloads: 3)

Code: (Select All)
$noprefix

const true = -1
const false = 0

type coordinate_dec
  x as double
  y as double
end type
type coordinate_int
  x as integer
  y as integer
end type
type coordinate_byte
  x as byte
  y as byte
end type

' ----- Settings -----

dim shared option_sound      as byte ' True is on, false is off
dim shared option_window_size as byte ' 1=640x360, [2=1280x720], 3=1920x1080
option_sound      = true
option_window_size = 2
load_settings

do: loop until screenexists = true
title "Space Explorer"

' ----- Images and screen -----

const screenw = 640
const screenh = 360
dim shared full_screen as unsigned long
full_screen = newimage(screenw, screenh, 32)
screen full_screen

dim shared background_image    as unsigned long
dim shared grid_image          as unsigned long
dim shared sprite_image        as unsigned long
dim shared icon_image          as unsigned long
dim shared how_to_play_image(4) as unsigned long
dim shared landing_image(9)    as unsigned long
dim shared gameover_image      as unsigned long
dim shared reference_image      as unsigned long

dim shared store_screen as unsigned long ' Anytime screen state should be stored

dim shared scaled_screen(3) as unsigned long
scaled_screen(1) = newimage( 640,  360, 32)
scaled_screen(2) = newimage(1280,  720, 32)
scaled_screen(3) = newimage(1920, 1080, 32)
screen scaled_screen(option_window_size)

displayorder hardware

source full_screen ' Prevent handles from ever being null
dest  full_screen

dim shared camera_x as double
dim shared camera_y as double

' ----- Sprite constants -----

' Cards, numbers are found via animation frame

const spr_card_large      = 1
const spr_card_small      = 2
const spr_deck            = 3
const spr_cursor          = 4
const spr_cursor_trail    = 5
const spr_fuel            = 6

' Path components

const spr_path            = 11 ' 6 rotations
const spr_ship            = 21 ' 6 rotations

' Planets, take off and landing

const spr_planet          = 31
const spr_sun            = 41
const spr_asteroid        = 42 ' 4 variations
const spr_reticle        = 43

' Hex menu icons, inactive and highlighted versions

const spr_iconx_move      = 71 ' 6 rotations
const spr_icono_move      = 72 ' 6 rotations
const spr_iconx_turnsoftl = 73 ' 6 rotations
const spr_icono_turnsoftl = 74 ' 6 rotations
const spr_iconx_turnsoftr = 75 ' 6 rotations
const spr_icono_turnsoftr = 76 ' 6 rotations
const spr_iconx_turnhardl = 77 ' 6 rotations
const spr_icono_turnhardl = 78 ' 6 rotations
const spr_iconx_turnhardr = 79 ' 6 rotations
const spr_icono_turnhardr = 80 ' 6 rotations
const spr_iconx_depart    = 81 ' 6 rotations
const spr_icono_depart    = 82 ' 6 rotations
const spr_iconx_discard  = 83 ' 6 copies, but none are rotated
const spr_icono_discard  = 84 ' 6 copies, but none are rotated

const sprite_total        = 100
dim shared sprite_ref(sprite_total) as integer

' --- Sound effects ---

const sfx_menu_move    = 1 ' Move menu cursor
const sfx_menu_confirm = 2 ' Confirm menu selection

const sfx_card        = 3 ' One card flip
const sfx_shuffle      = 4 ' Deck shuffle

const sfx_rocket      = 5 ' Moving forward
const sfx_thruster    = 6 ' Turning
const sfx_landing      = 7 ' Landing on planet
const sfx_takeoff      = 8 ' Launching from planet

const sfx_total        = 8
dim shared sfx(sfx_total, 100) as unsigned long

' ----- Resource file -----

dim shared mfi_s(255) as long ' Size
dim shared mfi_o(255) as long ' Offset
dim shared mfi_count  as unsigned byte
dim shared mfi_index  as unsigned byte
mfi_loader "resource.mfi"

type sprite_structure
  pos      as coordinate_int ' position in sprite sheet
  size      as coordinate_int ' size of sprite in sheet
  size_draw as coordinate_int ' size of sprite when displayed - equal to size.xy if no stretch
  frames    as integer        ' sprite's frames of animation
  fpf      as byte          ' Frame counter ticks per animation frame (0 defaults to 1)
  hb_offset as coordinate_int ' display position relative to hitbox position
  hb_size  as coordinate_int ' size of hitbox, to be copied to entity_spec().size.xy after parse
  image    as unsigned long  ' Handle of sprite sheet
end type
dim shared sprite_count        as integer
dim shared sprite(1000) as sprite_structure

parse_sprites sprite_image
parse_sprites icon_image
set_sprite_ref

' ----- Fonts -----

const fonts = 3
' Glass Fonts - custom pixel font processing and drawing

type font_structure
  image as unsigned long
  pos  as coordinate_int
  h    as integer
  w    as integer
end type

' Alignment in font calls
const left_align  = 0
const right_align  = 1
const center_align = 2

dim shared g_font(fonts, 255) as font_structure ' Number of fonts comes from main program header

' Current font options in use
dim shared font_using as byte          ' Index of current font being used
dim shared font_align as byte          ' Alignment
dim shared font_dest  as unsigned long  ' Destination image surface
dim shared font_x    as integer        ' Rolling font position, set by each glass_fonts call
dim shared font_y    as integer

' Font references
const f_loxica    = 1 ' Height 16 inclusive
const f_gaia_blue = 2 ' Height 20 inclusive
const f_gaia_red  = 3

' ----- Sort and shuffle -----

type sort_structure
  s_index as integer ' Reference to array being sorted
  s_value as single  ' Value being used for sorting
end type

const card_limit = 24
dim shared sorting(card_limit)  as sort_structure ' Before sort
dim shared sorting_count        as integer
dim shared sorted(2, card_limit) as sort_structure ' After sort
dim shared sorted_count(2)      as integer

' ----- Directional data -----

' Grid is along two axes, x increases to the northeast, y increases to the south
' Valid moves can be four cardinals, as well as NW (-1, -1) and SE (+1, +1) diagonals

dim shared move_delta(6) as coordinate_byte
move_delta(1).x =  0: move_delta(1).y = -1
move_delta(2).x =  1: move_delta(2).y =  0
move_delta(3).x =  1: move_delta(3).y =  1
move_delta(4).x =  0: move_delta(4).y =  1
move_delta(5).x = -1: move_delta(5).y =  0
move_delta(6).x = -1: move_delta(6).y = -1

const up    = 1
const right = 2
const down  = 3
const left  = 4
dim shared arrow(4) as string * 2
arrow(up)    = chr$(0) + chr$(72)
arrow(right) = chr$(0) + chr$(77)
arrow(down)  = chr$(0) + chr$(80)
arrow(left)  = chr$(0) + chr$(75)

const boardw = 28
const boardh = 31 ' Actual size is 27x30, one wide border is added to simplify checking for valid moves

' ----- Game state data -----

dim shared valid_cell(boardw, boardh) as byte
dim shared dir_used(boardw, boardh, 6) ' Set to true when that direction leaving/entering a cell has been used

dim shared player_count  as byte
player_count = 4
dim shared turn          as byte ' Player currently taking turn
dim shared asteroid_seed as byte ' Determined at game start, used to select asteroid appearances

const state_moved  = 1 ' Last action was a forward move to an empty cell
const state_turned = 2 ' Last action was a turn or planet departure
const state_landed = 3 ' Last action was a forward move to a planet
dim shared ship_state  as byte
dim shared ship_pos    as coordinate_byte ' Ship position
dim shared travel      as byte ' Direction currently traveling
dim shared next_planet as byte ' Next planet to be visited
dim shared fuel_tanks  as byte ' Fuel remaining, starting value affected by player_count

dim shared actions_taken(4)  as byte    ' Non-discard actions taken by each player
dim shared distance_traveled as integer ' Total distance traveled in hexes

dim shared planet_name$(10)
dim shared planet_preset(10, 6) as coordinate_byte
dim shared planet_at(boardw, boardh) as byte ' Index of planet located here, false if none, true if unused preset
dim shared planet_pos(10) as coordinate_byte ' Position of each planet on board

for x = 0 to boardw
  for y = 0 to boardh
      planet_at(x, y) = false
      valid_cell(x, y) = true
      if x = 0 or x = boardw or y = 0 or y = boardh then valid_cell(x, y) = false

      for d = 1 to 6: dir_used(x, y, d) = false: next d
  next y

  ' Top edge
  if x <> 4 then valid_cell(x, 1) = false
  if x < 4 or x > 6 then valid_cell(x, 2) = false
  if x = 2 or x = 3 or x > 8 then valid_cell(x, 3) = false
  if x > 10 then valid_cell(x, 4)  = false
  if x > 12 then valid_cell(x, 5)  = false
  if x > 14 then valid_cell(x, 6)  = false
  if x > 16 then valid_cell(x, 7)  = false
  if x > 18 then valid_cell(x, 8)  = false
  if x > 20 then valid_cell(x, 9)  = false
  if x > 22 then valid_cell(x, 10) = false
  if x > 24 then valid_cell(x, 11) = false
  if x > 24 then valid_cell(x, 12) = false
  if x > 25 then valid_cell(x, 13) = false
  if x > 26 then valid_cell(x, 14) = false

  ' Bottom edge
  if x < 3  then valid_cell(x, 18) = false
  if x < 5  then valid_cell(x, 19) = false
  if x < 7  then valid_cell(x, 20) = false
  if x < 9  then valid_cell(x, 21) = false
  if x < 10 then valid_cell(x, 22) = false
  if x < 11 then valid_cell(x, 23) = false
  if x < 12 then valid_cell(x, 24) = false
  if x < 14 then valid_cell(x, 25) = false
  if x < 16 then valid_cell(x, 26) = false
  if x < 18 then valid_cell(x, 27) = false
  if x < 20 then valid_cell(x, 28) = false
  if x < 24 then valid_cell(x, 29) = false
  if x < 26 then valid_cell(x, 30) = false
next x

'                        board xx,yy    1      2      3      4      5      6
const mercury = 1: set_preset mercury,  14,14,  15,15,  15,16,  14,16,  13,15,  13,14,  "Mercury"
const venus  = 2: set_preset venus,    14,12,  17,15,  17,18,  14,18,  11,15,  11,12,  "Venus"
const mars    = 3: set_preset mars,    15,10,  20,16,  19,21,  13,20,  8,14,  9, 9,  "Mars"
const jupiter = 4: set_preset jupiter,  19,13,  21,20,  16,22,  9,17,  7,10,  12, 8,  "Jupiter"
const saturn  = 5: set_preset saturn,  17, 9,  23,18,  20,24,  11,21,  5,12,  8, 6,  "Saturn"
const uranus  = 6: set_preset uranus,  21,12,  24,22,  17,25,  7,18,  4, 8,  11, 5,  "Uranus"
const neptune = 7: set_preset neptune,  25,14,  26,21,  23,27,  4,17,  2,12,  5, 3,  "Neptune"
const pluto  = 8: set_preset pluto,    23,11,  27,19,  27,26,  20,28,  1, 9,  1, 4,  "Pluto"
const earth  = 9: set_preset earth,    16,13,  18,17,  16,19,  12,17,  10,13,  12,11,  "Earth"
valid_cell(14, 15) = false ' Sun

dim shared deck(card_limit) as byte ' Contents of the main deck
dim shared deck_size        as byte ' Size of the main deck
dim shared hand(4, 3)      as byte ' Contents of each player's hand
dim shared hand_size(4)    as byte ' Size of each player's hand

' ----- Hand display dimensions -----

const x_offset = 20 ' x pixel change when moving horizontally on board
const y_offset = 26 ' y pixel change when moving vertically on board

dim shared hand_ox(4, 2)    as integer ' Player hand display top-left corner, second index is card size toggle
dim shared hand_oy(4, 2)    as integer
dim shared hand_offset(2)  as integer ' Pixel spacing between cards in hand
for s = spr_card_large to spr_card_small: hand_offset(s) = int((size_x(sprite_ref(s)) + 1) * 0.7): next s

margin = 2
x1 = margin                                                              ' Left column large and small cards
y1 = margin                                                              ' Top row large and small cards

s = spr_card_large
x2 = screenw - 1 - size_x(sprite_ref(s)) - (hand_offset(s) * 2) - margin ' Right column large cards
y2 = screenh - 1 - size_y(sprite_ref(s)) - margin                        ' Bottom row large cards
hand_ox(1, s) = x1: hand_oy(1, s) = y1 ' Large cards
hand_ox(2, s) = x2: hand_oy(2, s) = y1
hand_ox(3, s) = x1: hand_oy(3, s) = y2
hand_ox(4, s) = x2: hand_oy(4, s) = y2

s = spr_card_small
x3 = screenw - 1 - size_x(sprite_ref(s)) - (hand_offset(s) * 2) - margin ' Right column small cards
y3 = screenh - 1 - size_y(sprite_ref(s)) - margin                        ' Bottom row small cards
hand_ox(1, s) = x1: hand_oy(1, s) = y1 ' Small cards
hand_ox(2, s) = x3: hand_oy(2, s) = y1
hand_ox(3, s) = x1: hand_oy(3, s) = y3
hand_ox(4, s) = x3: hand_oy(4, s) = y3

' Floating cursor

const trail_length = 3
dim shared cursor_pos(trail_length) as coordinate_int ' Display position of cursor (nonzero indices are trail)
dim shared cursor_goal as coordinate_int ' Destination of cursor
cursor_goal.x = 0
cursor_goal.y = 0

dim shared reticle_flash as byte
dim shared ship_frame    as byte





' Title screen

dim menu_text$(6)
menu_start  = 1
menu_how    = 2
menu_sound  = 3
menu_window = 4
menu_quit  = 5

cy = 1
do
  putimage(0, 0), background_image, full_screen, (inthalf(width(background_image) - screenw),_
  inthalf(height(background_image) - screenh))-step(screenw - 1, screenh - 1)

  menu_text$(menu_start)  = "Start game - < " + trim$(str$(player_count)) + " Player >"
  menu_text$(menu_how)    = "How to play"
  if option_sound = true then menu_text$(menu_sound) = "Sound: < ON >" else menu_text$(menu_sound) = "Sound: < OFF >"
  menu_text$(menu_window) = "Window size: < x" + trim$(str$(option_window_size)) + " >"
  menu_text$(menu_quit)  = "Quit"

  set_font f_gaia_blue, center_align, full_screen
  font_pos inthalf(screenw), 110
  glass_fonts_at "- SPACE EXPLORER -"
  glass_fonts_at ""
  for m = menu_start to menu_quit
      set_font f_gaia_blue, center_align, full_screen
      t$ = menu_text$(m)
      if cy = m then font_using = f_gaia_red else t$ = text_replace$(text_replace$(t$, "< ", ""), " >", "")
      glass_fonts_at t$
  next m

  do
      limit 60
      display_screen
      k$ = inkey$
  loop while k$ = ""

  if k$ = arrow(up)  then play_sound sfx_menu_move: cy = wrap(cy - 1, menu_start, menu_quit)
  if k$ = arrow(down) then play_sound sfx_menu_move: cy = wrap(cy + 1, menu_start, menu_quit)

  dx = 0
  if k$ = arrow(right) or k$ = chr$(13) or k$ = " " then dx = 1
  if k$ = arrow(left) then dx = -1

  select case cy
      case menu_start
        if k$ <> chr$(13) and k$ <> " " then play_sound sfx_menu_move: player_count = wrap(player_count + dx, 2, 4)
      case menu_sound
        option_sound = wrap(option_sound + dx, true, false)
        if dx <> 0 then play_sound sfx_menu_move
      case menu_window
        option_window_size = wrap(option_window_size + dx, 1, 3)
        if dx <> 0 then play_sound sfx_menu_move: screen scaled_screen(option_window_size): dest full_screen
  end select

  if k$ = chr$(27) then play_sound sfx_menu_move: cy = menu_quit

  if k$ <> chr$(13) and k$ <> " " then continue
  if cy = menu_quit then system

  play_sound sfx_menu_confirm

  if cy = menu_how then
      h_page = 1
      do
        putimage(0, 0), background_image, full_screen, (inthalf(width(background_image) - screenw),_
        inthalf(height(background_image) - screenh))-step(screenw - 1, screenh - 1)

        ' Instructional splash image
        putimage(0, 0), how_to_play_image(h_page), full_screen

        ' Text
        set_font f_loxica, left_align, full_screen
        select case h_page
            case 1
              glass_fonts "Your mission is to visit each planet in the solar system,", 70, 27
              glass_fonts "then return to Earth.", 70, 42

              glass_fonts "You must visit the planets in order moving outward from the Sun,", 202, 171
              glass_fonts "so Mercury first, Pluto last.", 202, 186

              glass_fonts "Be careful, you have a limited supply of fuel!", 55, 256
              glass_fonts "One unit of fuel is spent each time the deck runs out of cards.", 55, 271
              glass_fonts "If you run out of fuel and cards, you'll be stranded in space!", 55, 286

            case 2
              glass_fonts "Play any card to move forward that number of spaces.", 164, 8
              glass_fonts "Asteroids must be avoided, you can't move through them.", 164, 23
              glass_fonts "You also cannot move along a path you previously used.", 164, 38

              glass_fonts "You can make a shallow turn left or right by playing a 5 or 6.", 129, 180
              glass_fonts "Sharp turns can be made with a 3, 4, or 6.", 129, 195
              glass_fonts "Once you've made a turn, you must move forward before turning again.", 129, 210

            case 3
              glass_fonts "To land on a planet, you need to move exactly the right distance.", 45, 102
              glass_fonts "You cannot move through planets normally.", 45, 117

              glass_fonts "After landing, you must choose a launch direction.", 193, 194
              glass_fonts "Playing 1 will launch you to the north, 2 launches northeast,", 193, 209
              glass_fonts "and so on clockwise, so 6 launches northwest.", 193, 224

              glass_fonts "Turning and launch angles are displayed during the game for reference.", 213, 282

            case 4
              glass_fonts "Each turn, you can play any number of cards.", 63, 101
              glass_fonts "If you play nothing, then discard two cards to pass your turn.", 63, 116
              glass_fonts "To do this, choose the card you'll keep, then choose 'discard.'", 63, 131

              glass_fonts "Each player has a hand of three cards, and everyone can see all hands.", 121, 249
              glass_fonts "Work together and plan ahead to complete your mission!", 121, 264
        end select

        glass_fonts "Page " + trim$(str$(h_page)) + "/4", 10, screenh - 10 - g_font(font_using, 0).h

        do
            limit 60
            display_screen
            k$ = inkey$
        loop while k$ = ""

        if k$ = arrow(left) then
            if h_page > 1 then play_sound sfx_menu_move
            h_page = max(h_page - 1, 1)
        end if
        if k$ = arrow(right) or k$ = chr$(13) or k$ = " " then
            if h_page < 4 then play_sound sfx_menu_move
            if h_page => 4 and k$ <> arrow(right) then exit do
            h_page = min(h_page + 1, 4)
        end if
        if k$ = chr$(27) then play_sound sfx_menu_move: exit do
      loop
  end if

  if cy <> menu_start then continue

  ' Start game

  asteroid_seed = timer
  randomize timer

  select case player_count
      case 2: fuel_tanks = 7
      case 3: fuel_tanks = 8
      case 4: fuel_tanks = 10
  end select
  for n = 1 to 4: actions_taken(n) = 0: next n
  distance_traveled = 0
  for n = 1 to card_limit: sorting(n).s_index = ((n - 1) mod 6) + 1: next n
  sorting_count = card_limit
  shuffle_deck
  for p = 1 to player_count: fill_hand(p): next p
  turn = 1
  for x = 0 to boardw: for y = 0 to boardh: for d = 1 to 6
      dir_used(x, y, d) = false
  next d: next y: next x

  ' Planet positions

  for p = 1 to 9
      for r = 1 to 6
        planet_at( planet_preset(p, r).x, planet_preset(p, r).y) = true
        valid_cell(planet_preset(p, r).x, planet_preset(p, r).y) = false
      next r
      set_planet p, rand(6)
  next p

  ship_pos.x = planet_pos(earth).x
  ship_pos.y = planet_pos(earth).y
  travel = rand(6) ' Departure from Earth
  ship_state = state_turned
  next_planet = mercury

  ' Initial camera and floating cursor
  camera_x = half(hex_center_x(ship_pos.x, ship_pos.y) + hex_center_x(planet_pos(next_planet).x, planet_pos(next_planet).y))
  camera_y = half(hex_center_y(ship_pos.x, ship_pos.y) + hex_center_y(planet_pos(next_planet).x, planet_pos(next_planet).y))
  cursor_pos(0).x = true ' Setting to true means next update, it will be set to goal instead of approaching goal
  cursor_pos(0).y = true

  play_game

  cy = 1
loop





' ===== Routine index =====

'--- Game mechanics ---
'play_game            ' Main game loop
'shuffle_deck        ' Shuffle a new deck with all cards not present in a player's hand
'fill_hand            ' Fill a player's hand, shuffling when necessary
'end_turn            ' Fill the current hand, then advance the turn counter
'f legal_move        ' Determine whether moving a given direction from a given position is allowed
'set_preset          ' Set the six preset locations for each planet
'set_planet          ' Set the position of a planet to one of its six presets

'--- Graphics ---
'draw_board          ' Draw all board and UI elements
'draw_cursor          ' Draw the red arrow cursor and trail
'draw_sprite          ' Draw a specified animation frame of a sprite at a given position on screen
'display_screen      ' Display the main screen in hardware mode, accounting for window size option
'capture_screen      ' Copy the contents of the screen for later use
'restore_screen      ' Put the stored screen contents back on the screen
'clear_image          ' Fill an image surface with a given color
'play_sound          ' Play a sound effect by name

'--- Shorthand and conversion ---
'f compass$          ' Convert a numerical direction to compass direction text
'f text_replace$      ' Search a string for instances of a given piece, and replace all with another piece
'f hex_center_x      ' Take board coordinates and return display coordinates of center of hex cell,
'f hex_center_y      '    relative to board center at 14, 15
'f size_x            ' Return the visual dimensions of a sprite
'f size_y

'--- Files and data handling ---
'mfi_loader          ' Load the archived resource file, containing images and sounds
'f load_gfx&          ' Retrieve an image from the loaded resource file and return its handle
'f load_sfx&          ' Retrieve a sound from the loaded resource file and return its handle
'load_settings        ' Load any existing settings file, otherwise create one from defaults
'save_settings        ' Save settings to a file
'parse_sprites        ' Scan a sprite sheet for sprite positions and dimensions, using detection pixels
'set_sprite_ref      ' Set references to sprites found in sheets in sequence, using named constants





' ------------------------------------
' ========== Game mechanics ==========
' ------------------------------------

sub play_game

cx = 1
do
  ' Game over check
  if fuel_tanks <= 0 and deck_size <= 0 then
      ' Iterate through each player's hand, if any possible action is found, it's not a game over
      game_over = true
      for p = 1 to player_count
        for c = 1 to hand_size(p)
            v = hand(p, c)
            a_move    = true
            a_shall_l = true
            a_shall_r = true
            a_sharp_l = true
            a_sharp_r = true
            a_depart  = true

            if ship_state = state_landed then a_move = false
            for n = 1 to v
              dx = ship_pos.x + (move_delta(travel).x * n)
              dy = ship_pos.y + (move_delta(travel).y * n)
              if legal_move(dx, dy, travel) = false        then a_move = false: exit for
              if n < v and planet_at(dx, dy) = next_planet then a_move = false: exit for
            next n

            d = wrap(travel - 1, 1, 6): a_shall_l = legal_move(ship_pos.x + move_delta(d).x, ship_pos.y + move_delta(d).y, d)
            d = wrap(travel + 1, 1, 6): a_shall_r = legal_move(ship_pos.x + move_delta(d).x, ship_pos.y + move_delta(d).y, d)
            d = wrap(travel - 2, 1, 6): a_sharp_l = legal_move(ship_pos.x + move_delta(d).x, ship_pos.y + move_delta(d).y, d)
            d = wrap(travel + 2, 1, 6): a_sharp_r = legal_move(ship_pos.x + move_delta(d).x, ship_pos.y + move_delta(d).y, d)
            if ship_state <> state_moved then a_shall_l = false: a_shall_r = false: a_sharp_l = false: a_sharp_r = false
            if v < 5 then a_shall_l = false: a_shall_r = false
            if v < 3 or v = 5 then a_sharp_l = false: a_sharp_r = false

            if ship_state <> state_landed then a_depart = false
            if dir_used(ship_pos.x, ship_pos.y, v) = true then a_depart = false ' Departing in the same direction landed

            if a_move + a_shall_l + a_shall_r + a_sharp_l + a_sharp_r + a_depart <> false then game_over = false: exit for
        next c
        if game_over = false then exit for
      next p

      if game_over = true then
        topx = -screenw: botx = screenw: xstep = 16: h = inthalf(screenh)
        for frame = 1 to 130
            limit 60
            draw_board cx
            line(0, 0)-(screenw, screenh), rgba32(0, 0, 0, (frame / 130) * 255), bf
            if frame <= 40 then topx = topx + xstep
            if frame > 40 and frame <= 80 then botx = botx - xstep
            putimage(topx, 0)-step(screenw - 1, h - 1), gameover_image, full_screen, (0, 0)-step(screenw - 1, h - 1)
            putimage(botx, h)-step(screenw - 1, h - 1), gameover_image, full_screen, (0, h)-step(screenw - 1, h - 1)
            display_screen
        next frame

        do
            limit 60
            display_screen
            k$ = inkey$
        loop until k$ = ""
        do
            limit 60
            display_screen
            k$ = inkey$
        loop while k$ = ""

        exit sub
      end if
  end if

  s = sprite_ref(spr_card_large)
  cursor_goal.x = hand_ox(turn, spr_card_large) + inthalf(size_x(s)) + (hand_offset(spr_card_large) * (cx - 1))
  cursor_goal.y = hand_oy(turn, spr_card_large) + size_y(s) - inthalf(size_y(sprite_ref(spr_cursor))) + (int(size_y(s) * 0.2) * -sgn(turn - 2.5))

  do
      limit 60
      draw_board cx
      draw_cursor
      display_screen
      k$ = inkey$
  loop while k$ = ""

  menu_end = hand_size(turn) + 1
  if hand_size(turn) => 3 then l = hand_size(turn) else l = menu_end
  if k$ = arrow(left)  then play_sound sfx_card: cx = wrap(cx - 1, 1, l)
  if k$ = arrow(right) then play_sound sfx_card: cx = wrap(cx + 1, 1, l)

  if k$ = chr$(27) then
      play_sound sfx_menu_move
      ' Quit confirmation
      t$ = "END GAME IN PROGRESS? (Y/N)"
      w = inthalf(text_width(t$, f_gaia_red))
      h = inthalf(g_font(f_gaia_red, 0).h)
      margin = 10
      do
        limit 60
        draw_board cx
        set_font f_gaia_red, center_align, full_screen
        line(inthalf(screenw) - w - margin, inthalf(screenh) - h - margin)-(inthalf(screenw) + w + margin, inthalf(screenh) + h + margin), rgba32( 0,  0,  0, 255), bf
        line(inthalf(screenw) - w - margin, inthalf(screenh) - h - margin)-(inthalf(screenw) + w + margin, inthalf(screenh) + h + margin), rgba32(11, 148, 217, 255), b
        glass_fonts t$, inthalf(screenw), inthalf(screenh) - h
        display_screen
        k$ = lcase$(inkey$)
      loop while k$ = ""
      play_sound sfx_menu_confirm
      if k$ = "y" then exit sub else continue
  end if

  if k$ <> chr$(13) and k$ <> " " then continue

  ' Selection confirmed

  if cx = menu_end then end_turn: cx = 1: continue

  play_sound sfx_menu_confirm

  ' Prepare action menu

  v = hand(turn, cx)

  a_move    = true
  a_shall_l = true
  a_shall_r = true
  a_sharp_l = true
  a_sharp_r = true
  a_depart  = true
  a_discard = true

  ' Action conditions

  if ship_state = state_landed then a_move = false
  for n = 1 to v
      dx = ship_pos.x + (move_delta(travel).x * n)
      dy = ship_pos.y + (move_delta(travel).y * n)
      if legal_move(dx, dy, travel) = false        then a_move = false: exit for
      if n < v and planet_at(dx, dy) = next_planet then a_move = false: exit for
  next n

  d = wrap(travel - 1, 1, 6): a_shall_l = legal_move(ship_pos.x + move_delta(d).x, ship_pos.y + move_delta(d).y, d)
  d = wrap(travel + 1, 1, 6): a_shall_r = legal_move(ship_pos.x + move_delta(d).x, ship_pos.y + move_delta(d).y, d)
  d = wrap(travel - 2, 1, 6): a_sharp_l = legal_move(ship_pos.x + move_delta(d).x, ship_pos.y + move_delta(d).y, d)
  d = wrap(travel + 2, 1, 6): a_sharp_r = legal_move(ship_pos.x + move_delta(d).x, ship_pos.y + move_delta(d).y, d)
  if ship_state <> state_moved then a_shall_l = false: a_shall_r = false: a_sharp_l = false: a_sharp_r = false
  if v < 5 then a_shall_l = false: a_shall_r = false
  if v < 3 or v = 5 then a_sharp_l = false: a_sharp_r = false

  if ship_state <> state_landed then a_depart = false
  if dir_used(ship_pos.x, ship_pos.y, v) = true then a_depart = false ' Departing in the same direction landed

  if hand_size(turn) < 3 then a_discard = false

  ' Menu positions

  total_a = 0
  if a_move    = true then total_a = total_a + 1: a_move    = total_a
  if a_shall_l = true then total_a = total_a + 1: a_shall_l = total_a
  if a_shall_r = true then total_a = total_a + 1: a_shall_r = total_a
  if a_sharp_l = true then total_a = total_a + 1: a_sharp_l = total_a
  if a_sharp_r = true then total_a = total_a + 1: a_sharp_r = total_a
  if a_depart  = true then total_a = total_a + 1: a_depart  = total_a
  if a_discard = true then total_a = total_a + 1: a_discard = total_a
  if total_a = 0 then continue

  a_ox = 60: a_oy = 2
  cx2 = 1

  do
      do
        limit 60
        draw_board cx

        x = 2
        if turn mod 2 = 0 then x = screenw - (x_offset * (total_a + 1)) - (y_offset - x_offset) - 2
        y = hand_oy(1, spr_card_large) + size_y(sprite_ref(spr_card_large)) + 3
        if turn > 2 then y = hand_oy(3, spr_card_large) - y_offset - inthalf(y_offset) - 2

        y1 = 0
        for n = 1 to total_a
            select case n
              case a_move:    s = sprite_ref(spr_iconx_move):      m = travel
              case a_shall_l: s = sprite_ref(spr_iconx_turnsoftl): m = travel
              case a_shall_r: s = sprite_ref(spr_iconx_turnsoftr): m = travel
              case a_sharp_l: s = sprite_ref(spr_iconx_turnhardl): m = travel
              case a_sharp_r: s = sprite_ref(spr_iconx_turnhardr): m = travel
              case a_depart:  s = sprite_ref(spr_iconx_depart):    m = v
              case a_discard: s = sprite_ref(spr_iconx_discard):  m = 1
            end select
            if n = cx2 then s = s + 1
            draw_sprite s, m, x, y + y1

            ' Cursor
            if n = cx2 then cursor_goal.x = x + inthalf(y_offset): cursor_goal.y = y + y1 + 28

            x = x + x_offset + 1
            y1 = toggle(y1, 0, inthalf(y_offset)) ' Stagger hexes up and down
        next n

        select case cx2
            case a_move:    t$ = "Move forward"
            case a_shall_l: t$ = "Shallow left turn"
            case a_shall_r: t$ = "Shallow right turn"
            case a_sharp_l: t$ = "Sharp left turn"
            case a_sharp_r: t$ = "Sharp right turn"
            case a_depart:  t$ = "Launch"
            case a_discard: t$ = "Discard other cards"
        end select
        set_font f_loxica, center_align, full_screen
        w = inthalf(text_width(t$, f_loxica))
        margin = 5
        line(inthalf(screenw) - w - margin, margin)-(inthalf(screenw) + w + margin, (margin * 3) + g_font(font_using, 0).h), rgba32( 0,  0,  0, 255), bf
        line(inthalf(screenw) - w - margin, margin)-(inthalf(screenw) + w + margin, (margin * 3) + g_font(font_using, 0).h), rgba32(11, 148, 217, 255), b
        glass_fonts t$, inthalf(screenw), margin * 2

        draw_cursor

        display_screen
        k$ = inkey$
      loop while k$ = ""

      if k$ = arrow(left)  then play_sound sfx_menu_move: cx2 = wrap(cx2 - 1, 1, total_a)
      if k$ = arrow(right) then play_sound sfx_menu_move: cx2 = wrap(cx2 + 1, 1, total_a)
      if k$ = chr$(27) then play_sound sfx_menu_move: exit do

      if k$ <> chr$(13) and k$ <> " " then continue

      ' Selection confirmed

      if cx2 <> a_discard then actions_taken(turn) = actions_taken(turn) + 1

      select case cx2
        case a_shall_l
            play_sound sfx_thruster
            travel = wrap(travel - 1, 1, 6)
        case a_shall_r
            play_sound sfx_thruster
            travel = wrap(travel + 1, 1, 6)
        case a_sharp_l
            play_sound sfx_thruster
            travel = wrap(travel - 2, 1, 6)
        case a_sharp_r
            play_sound sfx_thruster
            travel = wrap(travel + 2, 1, 6)

        case a_depart
            play_sound sfx_takeoff
            travel = v

        case a_discard
            hand(turn, 1) = v
            hand_size(turn) = 1
            cx = 1
            end_turn

        case a_move
            distance_traveled = distance_traveled + v
            for n = 1 to v
              dir_used(ship_pos.x, ship_pos.y, travel) = true
              ship_pos.x = ship_pos.x + move_delta(travel).x
              ship_pos.y = ship_pos.y + move_delta(travel).y
              dir_used(ship_pos.x, ship_pos.y, wrap(travel + 3, 1, 6)) = true
            next n
            ship_state = state_moved
            if planet_at(ship_pos.x, ship_pos.y) = next_planet then
              play_sound sfx_landing
              cursor_pos(0).x = true: cursor_pos(0).y = true

              ' Landing Successful overlay animation
              topx = -screenw: botx = screenw: xstep = 16: h = inthalf(screenh)
              for frame = 1 to 210
                  limit 60
                  draw_board cx
                  if frame <= 40 then topx = topx + xstep
                  if frame > 40 and frame <= 80 then botx = botx - xstep
                  if frame > 170 then topx = topx + xstep: botx = botx - xstep
                  if next_planet = earth and frame => 80 then exit for
                  putimage(topx, 0)-step(screenw - 1, h - 1), landing_image(next_planet), full_screen, (0, 0)-step(screenw - 1, h - 1)
                  putimage(botx, h)-step(screenw - 1, h - 1), landing_image(next_planet), full_screen, (0, h)-step(screenw - 1, h - 1)
                  display_screen
              next frame

              ' Victory animation continues
              if next_planet = earth then
                  draw_board cx
                  capture_screen
                  y = 0
                  for frame = 1 to 130
                    limit 60
                    if frame > 40 and frame <= 85 then y = y - 2
                    restore_screen
                    line(0, 0)-(screenw, screenh), rgba32(0, 0, 0, (frame / 130) * 255), bf
                    putimage(0, y), landing_image(earth), full_screen
                    display_screen
                  next frame
                  cls , rgba32(0, 0, 0, 255)
                  putimage(0, y), landing_image(earth), full_screen
                  display_screen

                  font_using = f_gaia_blue
                  w = inthalf(text_width("DISTANCE TRAVELED:" + str$(distance_traveled), font_using))
                  h = g_font(font_using, 0).h
                  y = inthalf(screenh) + h

                  for frame = 1 to 60: limit 60: display_screen: next frame
                  set_font f_gaia_blue, left_align, full_screen
                  glass_fonts "FUEL REMAINING:", inthalf(screenw) - w, y
                  set_font f_gaia_red, right_align, full_screen
                  glass_fonts str$(fuel_tanks), inthalf(screenw) + w, y
                  y = y + h

                  for frame = 1 to 60: limit 60: display_screen: next frame
                  set_font f_gaia_blue, left_align, full_screen
                  glass_fonts "DISTANCE TRAVELED:", inthalf(screenw) - w, y
                  set_font f_gaia_red, right_align, full_screen
                  glass_fonts str$(distance_traveled), inthalf(screenw) + w, y
                  y = y + h

                  for frame = 1 to 60: limit 60: display_screen: next frame
                  set_font f_gaia_blue, left_align, full_screen
                  glass_fonts "TOTAL MOVES:", inthalf(screenw) - w, y
                  set_font f_gaia_red, right_align, full_screen
                  glass_fonts str$(actions_taken(1) + actions_taken(2) + actions_taken(3) + actions_taken(4)), inthalf(screenw) + w, y

                  do
                    limit 60
                    display_screen
                    k$ = inkey$
                  loop until k$ = ""
                  do
                    limit 60
                    display_screen
                    k$ = inkey$
                  loop while k$ = ""
                  exit sub
              end if

              next_planet = next_planet + 1
              ship_state = state_landed
            else
              play_sound sfx_rocket ' No planet landing, just normal move forward
            end if
      end select

      if cx2 <> a_move and cx2 <> a_discard then ship_state = state_turned

      if cx2 <> a_discard then
        hand_size(turn) = hand_size(turn) - 1
        for n = cx to hand_size(turn)
            hand(turn, n) = hand(turn, n + 1)
        next n
      end if

      exit do
  loop

  cx = min(cx, hand_size(turn))
  if hand_size(turn) <= 0 then cx = 1: end_turn
loop

end sub


sub shuffle_deck

dim card_count(6) as byte
for p = 1 to player_count: for c = 1 to hand_size(p)
  card_count(hand(p, c)) = card_count(hand(p, c)) + 1
next c: next p

sorting_count = 0
for n = 1 to 6: for c = card_count(n) + 1 to 4
  sorting_count = sorting_count + 1
  sorting(sorting_count).s_index = n
next c: next n
shuffle
for n = 1 to sorted_count(1): deck(n) = sorted(1, n).s_index: next n
deck_size = sorted_count(1)

fuel_tanks = fuel_tanks - 1

end sub


sub fill_hand(p)
do while hand_size(p) < 3
  if deck_size <= 0 and fuel_tanks > 0 then shuffle_deck
  if deck_size <= 0 and fuel_tanks <= 0 then exit sub
  hand_size(p) = hand_size(p) + 1
  hand(p, hand_size(p)) = deck(deck_size)
  deck_size = deck_size - 1
loop
end sub


sub end_turn
if 3 - hand_size(turn) >  deck_size and hand_size(turn) > 0 then play_sound sfx_shuffle
if 3 - hand_size(turn) <= deck_size and hand_size(turn) > 0 then play_sound sfx_card
fill_hand(turn)
turn = wrap(turn + 1, 1, player_count)
end sub


function legal_move(x, y, d)
legal_move = true
if valid_cell(x, y) = false then legal_move = false
if dir_used(x, y, wrap(d + 3, 1, 6)) = true then legal_move = false
p = planet_at(x, y)
if p <> false and p <> next_planet then legal_move = false
end function


sub set_preset(i, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6, n$)
planet_name$(i) = n$
planet_preset(i, 1).x = x1: planet_preset(i, 1).y = y1
planet_preset(i, 2).x = x2: planet_preset(i, 2).y = y2
planet_preset(i, 3).x = x3: planet_preset(i, 3).y = y3
planet_preset(i, 4).x = x4: planet_preset(i, 4).y = y4
planet_preset(i, 5).x = x5: planet_preset(i, 5).y = y5
planet_preset(i, 6).x = x6: planet_preset(i, 6).y = y6
end sub


sub set_planet(p, v)
planet_at( planet_preset(p, v).x, planet_preset(p, v).y) = p
valid_cell(planet_preset(p, v).x, planet_preset(p, v).y) = true
planet_pos(p).x = planet_preset(p, v).x
planet_pos(p).y = planet_preset(p, v).y
end sub





' ------------------------------
' ========== Graphics ==========
' ------------------------------

sub draw_board(cx)

boundw = 366 ' Size of camera bounding box
boundh = 320 ' (This can be made to auto-adjust later if desired)

nextx = hex_center_x(planet_pos(next_planet).x, planet_pos(next_planet).y)
nexty = hex_center_y(planet_pos(next_planet).x, planet_pos(next_planet).y)
shipx = hex_center_x(ship_pos.x, ship_pos.y)
shipy = hex_center_y(ship_pos.x, ship_pos.y)

' Find camera destination

camx = half(shipx + nextx) ' Start between ship and next planet
camy = half(shipy + nexty)
camx = min(max(camx, shipx - half(boundw)), shipx + half(boundw)) ' Move camera if ship is outside bounding box
camy = min(max(camy, shipy - half(boundh)), shipy + half(boundh)) '  (Don't need to do this for next planet)

' Camera's actual position approaches destination

if abs(camx - camera_x) <= 0.6 then camera_x = camx ' Prevent very delayed last pixel of camera movement
if abs(camy - camera_y) <= 0.6 then camera_y = camy
camera_x = camera_x + ((camx - camera_x) * 0.2)
camera_y = camera_y + ((camy - camera_y) * 0.2)

' --- Background ---

putimage(0, 0), background_image, full_screen, (inthalf(width(background_image) - screenw) - (camera_x * 0.2),_
inthalf(height(background_image) - screenh) - (camera_y * 0.2))-step(screenw - 1, screenh - 1)

' --- Board ---

' Sun
s = sprite_ref(spr_sun)
x = inthalf(screenw) + hex_center_x(14, 15) - inthalf(size_x(s)) - camera_x
y = inthalf(screenh) + hex_center_y(14, 15) - inthalf(size_y(s)) - camera_y
draw_sprite s, 1, x, y

' Asteroids
randomize using asteroid_seed ' Fixed seed for consistent asteroid variations
for x1 = 0 to boardw: for y1 = 0 to boardh
  if planet_at(x1, y1) <> true then continue
  s = sprite_ref(spr_asteroid) + rand(4) - 1
  x = inthalf(screenw) + hex_center_x(x1, y1) - inthalf(size_x(s)) - camera_x
  y = inthalf(screenh) + hex_center_y(x1, y1) - inthalf(size_y(s)) - camera_y
  draw_sprite s, 1, x, y
next y1: next x1

' Planets
for p = 1 to 9
  s = sprite_ref(spr_planet) + p - 1
  x = inthalf(screenw) + hex_center_x(planet_pos(p).x, planet_pos(p).y) - inthalf(size_x(s)) - camera_x
  y = inthalf(screenh) + hex_center_y(planet_pos(p).x, planet_pos(p).y) - inthalf(size_y(s)) - camera_y
  draw_sprite s, 1, x, y
next p

' Hex grid
putimage(inthalf(screenw) + hex_center_x(1, -1) - inthalf(y_offset) - camera_x,_
inthalf(screenh) + hex_center_y(1, -1) - camera_y), grid_image, full_screen

' Path segments
for x = 0 to boardw: for y = 0 to boardh: for d = 1 to 6
  if dir_used(x, y, d) = false then continue
  s = sprite_ref(spr_path)
  x1 = inthalf(screenw) + hex_center_x(x, y) - inthalf(size_x(s)) - camera_x
  y1 = inthalf(screenh) + hex_center_y(x, y) - inthalf(size_y(s)) - camera_y
  draw_sprite s, d, x1, y1
next d: next y: next x

' Next planet reticle
f = 6
reticle_flash = wrap(reticle_flash + 1, 0, (f * 2) - 1)
s = sprite_ref(spr_reticle)
p = next_planet
x = inthalf(screenw) + hex_center_x(planet_pos(p).x, planet_pos(p).y) - inthalf(size_x(s)) - camera_x
y = inthalf(screenh) + hex_center_y(planet_pos(p).x, planet_pos(p).y) - inthalf(size_y(s)) - camera_y
draw_sprite s, int(reticle_flash / f) + 1, x, y

' Ship
f = 4
ship_frame = wrap(ship_frame + 1, 0, (f * 6) - 1)
s = sprite_ref(spr_ship)
x = inthalf(screenw) + hex_center_x(ship_pos.x, ship_pos.y) - inthalf(size_x(s)) - camera_x
y = inthalf(screenh) + hex_center_y(ship_pos.x, ship_pos.y) - inthalf(size_y(s)) - camera_y
if ship_state <> state_landed then draw_sprite s + travel - 1, int(ship_frame / f) + 1, x, y

' --- UI ---

' Navigation guides
putimage(screenw - 86, inthalf(screenh) - 70), reference_image, full_screen

' Deck
x = 10: y = hand_oy(3, spr_card_large) - 10 - size_y(sprite_ref(spr_deck))
for c = 1 to deck_size: draw_sprite sprite_ref(spr_deck), 1, x + c, y - inthalf(c): next c

' Fuel label
y = y - 30
font_pos x, y
if fuel_tanks > 0 then
  set_font f_gaia_blue, left_align, full_screen
  glass_fonts_at "FUEL"
elseif fuel_tanks <= 0 and int(timer mod 2) = 0 then
  set_font f_gaia_red, left_align, full_screen
  glass_fonts_at "FUEL"
end if

' Fuel gauge
y = y - 10
s = sprite_ref(spr_fuel)
for n = 1 to fuel_tanks
  draw_sprite s, 1, x, y
  y = y - size_y(s) - 1
next n

' Player hands
for p = 1 to player_count
  if p = turn then s = spr_card_large else s = spr_card_small
  temp_size = hand_size(p)
  if p = turn and temp_size < 3 then temp_size = temp_size + 1
  for c = 1 to temp_size
      y = hand_oy(p, s)
      if p = turn and c = cx then y = y + (int(size_y(sprite_ref(s)) * 0.2) * -sgn(turn - 2.5))
      m = hand(p, c)
      if c > hand_size(p) then m = 7
      draw_sprite sprite_ref(s), m, hand_ox(p, s) + ((c - 1) * hand_offset(s)), y
  next c
next p

end sub


sub draw_cursor

' Update cursor trail
for n = trail_length to 1 step -1
  cursor_pos(n).x = cursor_pos(n - 1).x
  cursor_pos(n).y = cursor_pos(n - 1).y
next n

' Cursor
dx = cursor_goal.x - cursor_pos(0).x
dy = cursor_goal.y - cursor_pos(0).y
if cursor_pos(0).x = true or abs(dx) < 0.5 then cursor_pos(0).x = cursor_goal.x
if cursor_pos(0).y = true or abs(dy) < 0.5 then cursor_pos(0).y = cursor_goal.y
cursor_pos(0).x = cursor_pos(0).x + ((cursor_goal.x - cursor_pos(0).x) * 0.3)
cursor_pos(0).y = cursor_pos(0).y + ((cursor_goal.y - cursor_pos(0).y) * 0.3)

for n = trail_length to 0 step -1
  s = sprite_ref(spr_cursor_trail)
  if n = 0 then s = sprite_ref(spr_cursor)
  draw_sprite s, 1, cursor_pos(n).x - inthalf(size_x(s)), cursor_pos(n).y - inthalf(size_y(s))
next n

end sub


sub draw_sprite(s, f, x, y)
x1 = sprite(s).pos.x + ((f - 1) * (size_x(s) + 2)) ' Animation frame
putimage(x, y), sprite(s).image, full_screen, (x1, sprite(s).pos.y)-step(size_x(s), size_y(s))
end sub


sub display_screen

'preserve& = dest
'dest scaled_screen(option_window_size)

hardware_image = copyimage(full_screen, 33)
putimage(0, 0)-((screenw * option_window_size) - 1, (screenh * option_window_size) - 1), hardware_image
display
freeimage hardware_image

'dest preserve&

end sub


sub capture_screen
clear_image store_screen, rgba32(0, 0, 0, 255)
putimage(0, 0)-(screenw - 1, screenh - 1), full_screen, store_screen, (0, 0)-(screenw - 1, screenh - 1)
end sub


sub restore_screen
clear_image full_screen, rgba32(0, 0, 0, 255)
putimage(0, 0)-(screenw - 1, screenh - 1), store_screen, full_screen, (0, 0)-(screenw - 1, screenh - 1)
end sub


sub clear_image(d&, h~&)
preserve& = dest
dest d&
cls , h~&
dest preserve&
end sub


sub play_sound(s)

if s = false or option_sound = false or sfx(s, 1) = false then exit sub

' Count valid sounds at this index and select one randomly
c = 1
do until sfx(s, c + 1) = false: c = c + 1: loop
r = rand(c)
if sfx(s, r) <> false then sndplay sfx(s, r)

end sub





' ----------------------------------------------
' ========== Shorthand and conversion ==========
' ----------------------------------------------

function compass$(d)
select case d
  case 1: c$ = "north"
  case 2: c$ = "northeast"
  case 3: c$ = "southeast"
  case 4: c$ = "south"
  case 5: c$ = "southwest"
  case 6: c$ = "northwest"
end select
compass$ = c$
end function


function text_replace$(t1$, r1$, r2$)
' Search t$ for instances of r1$ and replace them with r2$
t$ = t1$
do while instr(t$, r1$) <> false
  t$ = left$(t$, instr(t$, r1$) - 1) + r2$ + right$(t$, len(t$) - (instr(t$, r1$) + len(r1$) - 1))
loop
text_replace$ = t$
end function


function hex_center_x(x, y)
' Take board coordinates and return display x of center of hex cell, relative to board center at 14, 15
z = y ' y parameter is to give these two functions the same syntax, avoid forgetting to omit y for this one
hex_center_x = (x - inthalf(boardw)) * x_offset
end function


function hex_center_y(x, y)
' Take board coordinates and return display y of center of hex cell, relative to board center at 14, 15
hex_center_y = ((y - inthalf(boardh)) * y_offset) - ((x - inthalf(boardw)) * inthalf(y_offset))
end function


function size_x(s)
size_x = sprite(s).size.x
end function


function size_y(s)
size_y = sprite(s).size.y
end function





' ---------------------------------------------
' ========== Files and data handling ==========
' ---------------------------------------------

sub mfi_loader(f$)

mfi = freefile

open f$ for binary as #mfi
get #mfi, , mfi_count
for i = 1 to mfi_count
  get #mfi, , mfi_o(i)
  get #mfi, , mfi_s(i)
  mfi_o(i) = mfi_o(i) + 1
next i

mfi_index = 1

' ----- Images -----

background_image = load_gfx(mfi)
grid_image      = load_gfx(mfi)
sprite_image    = load_gfx(mfi)
icon_image      = load_gfx(mfi)

g_font(f_loxica,    0).image = load_gfx(mfi)
g_font(f_gaia_blue, 0).image = load_gfx(mfi)
g_font(f_gaia_red,  0).image = load_gfx(mfi)
for n = 1 to fonts: initialize_font n: next

for n = 1 to 4: how_to_play_image(n) = load_gfx(mfi): next n
for n = 1 to 9: landing_image(n) = load_gfx(mfi): next n
gameover_image  = load_gfx(mfi)
reference_image  = load_gfx(mfi)

' ----- Sound effects -----

sfx(sfx_menu_move,    1) = load_sfx(mfi)
sfx(sfx_menu_confirm, 1) = load_sfx(mfi)
sfx(sfx_card,        1) = load_sfx(mfi)
sfx(sfx_shuffle,      1) = load_sfx(mfi)
sfx(sfx_rocket,      1) = load_sfx(mfi)
sfx(sfx_thruster,    1) = load_sfx(mfi)
sfx(sfx_landing,      1) = load_sfx(mfi)
sfx(sfx_takeoff,      1) = load_sfx(mfi)

if fileexists("mfi_temp.dat") then kill "mfi_temp.dat"

end sub


function load_gfx&(mfi)

if fileexists("mfi_temp.dat") then kill "mfi_temp.dat"
mfidata = freefile

open "mfi_temp.dat" for binary as #mfidata
dat$ = space$(mfi_s(mfi_index))
get #mfi, mfi_o(mfi_index), dat$
put #mfidata, , dat$

close #mfidata
load_gfx& = loadimage("mfi_temp.dat", 32)

mfi_index = mfi_index + 1

end function


function load_sfx&(mfi)

if fileexists("mfi_temp.dat") then kill "mfi_temp.dat"
mfidata = freefile

open "mfi_temp.dat" for binary as #mfidata
dat$ = space$(mfi_s(mfi_index))
get #mfi, mfi_o(mfi_index), dat$
put #mfidata, , dat$

close #mfidata
load_sfx& = sndopen("mfi_temp.dat")

mfi_index = mfi_index + 1

end function


sub load_settings

if fileexists("settings.ini") = false then save_settings: exit sub

open "settings.ini" for binary as #1
get #1, 1, option_sound
get #1, , option_window_size
close #1

' Reset invalid option states to default
if option_sound <> false then option_sound = true
if option_window_size < 1 or option_window_size > 3 then option_window_size = 2

end sub


sub save_settings

open "settings.ini" for binary as #1
put #1, 1, option_sound
put #1, , option_window_size
close #1

end sub


sub parse_sprites(i&)

preserve& = source
source i&

d~& = point(0, 0) ' Detection color
s = sprite_count + 1
x1 = 1 ' Top left of first sprite
y1 = 2

do
  sprite(s).image = i&

  ' Source position
  sprite(s).pos.x = x1
  sprite(s).pos.y = y1

  ' Sprite size
  x2 = scan_right(x1, y1, i&, d~&)
  y2 =  scan_down(x1, y1, i&, d~&)
  sprite(s).size.x = x2 - x1 - 1
  sprite(s).size.y = y2 - y1 - 1

  ' Animation frame count
  x2 = scan_right(x2, y1, i&, d~&)
  sprite(s).frames = int( ((x2 + 1) - x1) / (sprite(s).size.x + 2) )
  if sprite(s).frames < 1 then sprite(s).frames = 1

  ' Frame counter ticks per animation frame
  sprite(s).fpf = scan_right(x2, y1 - 1, i&, d~&) - x2
  if sprite(s).fpf < 1 then sprite(s).fpf = 1
  x2 = x2 + 1

  ' Sprite display position - relative to entity hitbox position
  x_hb = scan_right(x2 - 1, y1, i&, d~&)
  y_hb =  scan_down(x2, y1 - 1, i&, d~&)
  sprite(s).hb_offset.x = x2 - x_hb
  sprite(s).hb_offset.y = y1 - y_hb

  ' Hitbox size
  sprite(s).hb_size.x = scan_right(x_hb, y1, i&, d~&) - x_hb
  sprite(s).hb_size.y =  scan_down(x2, y_hb, i&, d~&) - y_hb

  y1 = y2 + 1
  if point(x1 - 1, y1) = d~& then ' End of column
      if point(x1, 0) = d~& then exit do ' No more columns
      y1 = 2
      x1 = scan_right(x1, 0, i&, d~&) + 1 ' Find new column
  end if

  s = s + 1
loop

sprite_count = s

source preserve&

end sub


sub set_sprite_ref

' ----- Set sprite references - must be in order found in image files -----

s = 1
sprite_ref(spr_card_large)      = s: s = s + 1
sprite_ref(spr_card_small)      = s: s = s + 1
sprite_ref(spr_deck)            = s: s = s + 1
sprite_ref(spr_cursor)          = s: s = s + 1
sprite_ref(spr_cursor_trail)    = s: s = s + 1

sprite_ref(spr_path)            = s: s = s + 1
sprite_ref(spr_ship)            = s: s = s + 6

sprite_ref(spr_planet)          = s: s = s + 9
sprite_ref(spr_sun)            = s: s = s + 1
sprite_ref(spr_asteroid)        = s: s = s + 4

sprite_ref(spr_fuel)            = s: s = s + 1
sprite_ref(spr_reticle)        = s: s = s + 1

sprite_ref(spr_iconx_move)      = s: s = s + 1
sprite_ref(spr_icono_move)      = s: s = s + 1
sprite_ref(spr_iconx_turnsoftl) = s: s = s + 1
sprite_ref(spr_icono_turnsoftl) = s: s = s + 1
sprite_ref(spr_iconx_turnsoftr) = s: s = s + 1
sprite_ref(spr_icono_turnsoftr) = s: s = s + 1
sprite_ref(spr_iconx_turnhardl) = s: s = s + 1
sprite_ref(spr_icono_turnhardl) = s: s = s + 1
sprite_ref(spr_iconx_turnhardr) = s: s = s + 1
sprite_ref(spr_icono_turnhardr) = s: s = s + 1
sprite_ref(spr_iconx_depart)    = s: s = s + 1
sprite_ref(spr_icono_depart)    = s: s = s + 1
sprite_ref(spr_iconx_discard)  = s: s = s + 1
sprite_ref(spr_icono_discard)  = s: s = s + 1

end sub


' Math and logic routines

' No data structure or dependencies


function plus_limit(n, p, l) ' p is added to n, but can't go past l in the direction of travel
q = n + p
if sgn(q - l) = sgn(p) then q = l
plus_limit = q
end function


function half(n) ' less expensive than n / 2, less parentheses than n * 0.5
half = n * 0.5
end function
function inthalf(n) ' same, but with int() around it
inthalf = int(n * 0.5)
end function


function sq(n) ' less expensive and less parentheses than n ^ 2
' For code clarity
sq = n * n
end function


function atn1(n) ' shortcut for getting radians of eight cardinals and diagonals
' For code clarity - n represents multiple of 45 degrees, or quarter-pi radians
atn1 = n * atn(1)
end function


function degrees(d) ' pass in degrees, returns radians
degrees = atn1(d / 45)
end function


function hypo(a, b) ' pass in triangle legs, returns hypotenuse (Pythagoras)
hypo = sqr(sq(a) + sq(b)) ' squares are always positive, so no danger of imaginary component
end function


function arctan(y, x) ' atn() with safety checks, and sensitive to negative axes
arctan = 0
if x = 0 and y = 0 then exit function
a = atn1(2)
if x <> 0 then ' prevent division by zero
  a = abs(atn(y / x))
  if x < 0 then a = atn1(4) - a
end if
if y < 0 then a = flip_y(a)
arctan = a
end function


function flip_x(a) ' flips angle left/right
flip_x = wrap_a( (atn1(8) - wrap_a(a + atn1(2))) - atn1(2) )
end function
function flip_y(a) ' flips angle up/down
flip_y = atn1(8) - a
end function


function frames(s) ' pass a decimal as seconds.frames, returns integer frames
f = int(s) * 60
frames = int(f + ((s - int(s)) * 100))
end function


function frames_dec(s) ' like frames(), but takes seconds.decimal instead of seconds.frames,
f = int(s) * 60        ' so 0.50 will return 30 frames, not 50 frames
frames_dec = int(f + ((s - int(s)) * 60))
end function


function wrap(n, l1, h1) ' n is adjusted back within lower(l) and upper(h) bounds similar to mod operator
l = l1: h = h1 ' make sure h is never less than l, this also prevents division by zero
if h1 < l1 then
  l = h1: h = l1
end if
x = (l - n) / ((h - l) + 1)
if x <> int(x) then x = x + 1
wrap = n + (int(x) * ((h - l) + 1))
end function


function wrap_a(a) ' angle a is adjusted back within 0 and 2pi, noninclusive of 2pi
x = -a / atn1(8)
if x <> int(x) then x = x + 1
wrap_a = a + (int(x) * atn1(8))
end function


function toggle(v, p, q)
if v = p then toggle = q
if v = q then toggle = p
end function


function rounding(n) ' rounds to closer integer
p = int(n)
if mod_dec(n, 1) => 0.5 then p = p + 1
rounding = p
end function


function min(n1, n2)
if n2 < n1 then min = n2 else min = n1
end function


function max(n1, n2)
if n2 > n1 then max = n2 else max = n1
end function


function pyr(n) ' produce pyramid number on n (1 + 2 + 3 ... n)
pyr = n * (n + 1) * 0.5
end function


function rand(n) ' produce random whole number from 1 to n
rand = int(rnd * n) + 1
end function


function mod_dec(n, d) ' mod operator that preserves decimal
mod_dec = n
if d = 0 then exit function ' Division by zero protection
mod_dec = ((n / d) - int(n / d)) * d
end function


function hexcolor~&(h$)
hexcolor~& = rgba32(0, 0, 0, 255)
if len(h$) <> 6 then exit function
hexcolor~& = rgba32(val("&H" + mid$(h$, 1, 2)), val("&H" + mid$(h$, 3, 2)), val("&H" + mid$(h$, 5, 2)), 255)
end function


function before$(t$, c$)
p = instr(t$, c$)
if p = false then p = len(t$) + 1
before$ = left$(t$, p - 1)
end function


function after$(t$, c$)
after$ = right$(t$, len(t$) - instr(t$, c$) - (len(c$) - 1))
end function


function between$(t$, c1$, c2$)
between$ = before$(after$(t$, c1$), c2$)
end function


function vector_x(a, v) ' convert polar vector to x component
vector_x = 0
if a = aim_n or a = aim_s then exit function ' Protect against undefined cos()
vector_x = v * cos(a)
end function
function vector_y(a, v) ' convert polar vector to y component
vector_y = 0
if a = aim_w or a = aim_e then exit function ' Protect against undefined sin()
vector_y = v * sin(a)
end function


function ellipse_focus_x(axis_x, axis_y)
ellipse_focus_x = 0
if axis_x > axis_y then ellipse_focus_x = sqr(sq(axis_x) - sq(axis_y))
end function
function ellipse_focus_y(axis_x, axis_y)
ellipse_focus_y = 0
if axis_x < axis_y then ellipse_focus_y = sqr(sq(axis_y) - sq(axis_x))
end function


function x_on_ellipse(ax, ay, angle)

select case angle
  case atn1(0): ex = ax
  case atn1(4): ex = ax
  case atn1(2): ex = 0
  case atn1(6): ex = 0
  case else: ex = (ax * ay) / sqr(sq(ay) + sq(ax * tan(angle)))
end select

if angle > atn1(2) and angle < atn1(6) then ex = -ex
x_on_ellipse = ex

end function


function y_on_ellipse(ax, ay, angle)

select case angle
  case atn1(0): ey = 0
  case atn1(4): ey = 0
  case atn1(2): ey = ay
  case atn1(6): ey = ay
  case else: ey = (ax * ay) / sqr(sq(ax) + sq(ay / tan(angle)))
end select

if angle > atn1(4) then ey = -ey
y_on_ellipse = ey

end function


function ellipse_tangent(ax, ay, angle)

' ax and ay are axis lengths from center of ellipse
' angle is from center of ellipse
' Returns tangent angle, facing in clockwise direction

' Point angle intersects ellipse
ix = x_on_ellipse(ax, ay, angle)
iy = y_on_ellipse(ax, ay, angle)

' Focus distance from center
fx = ellipse_focus_x(ax, ay)
fy = ellipse_focus_y(ax, ay)

' Angles from foci to intersection point
a1 = arctan(iy + fy, ix + fx)
a2 = arctan(iy - fy, ix - fx)

' Average, then right angle to get tangent angle
ellipse_tangent = wrap_a(half(a1 + a2) + atn1(2))

end function


function line_and_ellipse(x1, y1, x2, y2, axis_x, axis_y, ix, iy)

' Given a line between points (x1, y1) and (x2, y2) relative to an ellipse's center,
' find the x coordinate of the intersection between the line and the ellipse,
' closer to (x1, y1), and put output in (ix, iy).

ix = 0 ' Default to center of ellipse
iy = 0
line_and_ellipse = true ' Becomes false later if the quadratic's radical is negative

if axis_x = 0 and axis_y = 0 then exit function

fx = ellipse_focus_x(axis_x, axis_y)
fy = ellipse_focus_y(axis_x, axis_y)

dx = sgn(x2 - x1)
dy = sgn(y2 - y1)

' Handle pure vertical and horizontal
if dx = 0 or dy = 0 then
  ix = x1
  iy = y1
  if dx = 0 and dy <> 0 and axis_x > 0 then
      iy = -dy * sqr((sq(axis_y) * abs(sq(axis_x) - sq(x1))) / sq(axis_x))
  end if
  if dy = 0 and dx <> 0 and axis_y > 0 then
      ix = -dx * sqr((sq(axis_x) * abs(sq(axis_y) - sq(y1))) / sq(axis_y))
  end if

' Otherwise, run quadratic solution of line and ellipse
else
  slope = (y2 - y1) / (x2 - x1)
  elevation = y1 - (slope * x1)

  ' Quadratic coefficients
  a = sq(axis_x * slope) + sq(axis_y)
  b = 2 * sq(axis_x) * slope * elevation
  c = sq(axis_x) * (sq(elevation) - sq(axis_y))

  if sq(b) - (4 * a * c) < 0 then
      line_and_ellipse = false ' Negative will fail the quadratic radical,
      exit function            ' calling routine must be alerted
  end if

  ' Use x coordinate closer to (x1, y1)
  ix1 = quadratic(a, b, c,  1)
  ix2 = quadratic(a, b, c, -1)
  if abs(x1 - ix1) < abs(x1 - ix2) then ix = ix1 else ix = ix2

  iy = (slope * ix) + elevation
end if

end function


function quadratic(a, b, c, pm)
' pm is 1 or -1, to represent the +/- in the quadratic formula
if a = 0 then
  print "Quadratic denominator was zero!"
  display: sleep
  exit function
end if
quadratic = (-b + (pm * sqr(sq(b) - (4 * a * c)))) / (2 * a)
end function


' Insertion sort and sequence shuffle

' No dependencies



sub sort(s, d)

' Before calling, put key values in sorting().s_index, .s_value, and sorting_count
' Takes s_index and s_value in sorting(), sorts them into sorted(s, ) by s_value, in direction of sgn(d)

' So if d = 1, values will go up as sorted() index goes up, -1 is reverse

c = 1
sorted(s, 1).s_index = sorting(1).s_index
sorted(s, 1).s_value = sorting(1).s_value

for n1 = 2 to sorting_count ' sorting() index being inserted
  for n2 = 1 to c + 1 ' position in sorted(s, ) being checked

      if n2 > c or sgn(sorted(s, n2).s_value - sorting(n1).s_value) = sgn(d) then
        for n3 = c to n2 step -1 ' make space for insertion
            sorted(s, n3 + 1).s_index = sorted(s, n3).s_index
            sorted(s, n3 + 1).s_value = sorted(s, n3).s_value
        next n3

        sorted(s, n2).s_index = sorting(n1).s_index
        sorted(s, n2).s_value = sorting(n1).s_value
        c = c + 1
        exit for
      end if

  next n2
next n1
sorted_count(s) = c

end sub


sub shuffle

randomize timer
sorted_count(1) = 0
c = sorting_count

for n = 1 to c
  s = int(rnd * sorting_count) + 1
  sorted_count(1) = sorted_count(1) + 1
  sorted(1, sorted_count(1)).s_index = sorting(s).s_index

  sorting_count = sorting_count - 1
  for n1 = s to sorting_count
      sorting(n1).s_index = sorting(n1 + 1).s_index
  next n1
next n

end sub


' Glass Fonts - custom pixel font processing and drawing

' NOTE: Number of fonts, image handle assignment, and initialize_font calls must be done in main program.
'      Set fonts constant, then $include, then set image handles, then call initialize_font for each.



sub glass_fonts(t1$, x1, y1)
' Text, font, destination image surface, position, alignment

t$ = t1$
carriage = true
if right$(t$, 1) = ";" then
  carriage = false
  t$ = left$(t$, len(t$) - 1)
end if

x = x1: y = y1
f = font_using

if font_align <> left_align then
  ' Adjust starting point based on line width, for center or right align
  w = text_width(t$, f)
  if font_align = center_align then w = int(w * 0.5)
  x = x - w
end if

for n = 1 to len(t$)
  c = asc(mid$(t$, n, 1))
  w = g_font(f, c).w
  putimage(x, y)-step(w, g_font(f, 0).h), g_font(f, 0).image, font_dest, (g_font(f, c).pos.x, g_font(f, c).pos.y)-step(w, g_font(f, 0).h)
  x = x + w + 1
next n

font_x = x1
font_y = y1
if carriage = false then font_x = x
if carriage = true  then font_y = y1 + g_font(f, 0).h

end sub


sub glass_fonts_at(t$)
glass_fonts t$, font_x, font_y
end sub


sub set_font(f, a, d&)

font_using = f
font_align = a
font_dest  = d&

end sub


sub font_pos(x, y)

font_x = x
font_y = y

end sub


sub initialize_font(f)

preserve& = source

source g_font(f, 0).image
clearcolor point(0, 0), g_font(f, 0).image
i& = g_font(f, 0).image
d~& = point(1, 0) ' Detection color

' Height
g_font(f, 0).h = scan_down(1, 2, i&, d~&) - 3

y = 0
for cy = 0 to 15
  y = scan_down(1, y, i&, d~&) + 1
  x = 1
  for cx = 0 to 15
      n = (cy * 16) + cx
      g_font(f, n).pos.x = x ' Source position
      g_font(f, n).pos.y = y
      x = scan_right(x, y, i&, d~&) + 1
      g_font(f, n).w = x - g_font(f, n).pos.x - 2 ' Variable width
  next cx
next cy

source preserve&

end sub


function font_height
font_height = g_font(font_using, 0).h
end function


function text_width(t$, f)
w = 0
for n = 1 to len(t$)
  w = w + g_font(f, asc(mid$(t$, n, 1))).w + 1
next n
text_width = w - 1
end function


function scan_right(x1, y, i&, d~&) ' Starting position (noninclusive), image, detection color
x = x1
preserve& = source
source i&
w = width(i&)
do
  x = x + 1
  if x > w then call scan_error(x, y, "right")
loop until point(x, y) = d~& or x > w
scan_right = x
source preserve&
end function


function scan_down(x, y1, i&, d~&)
y = y1
preserve& = source
source i&
h = height(i&)
do
  y = y + 1
  if y > h then call scan_error(x, y, "down")
loop until point(x, y) = d~& or y > h
scan_down = y
source preserve&
end function


sub scan_error(x, y, t$)
t1$ = "Moved " + t$ + " beyond image at" + str$(x) + "," + str$(y)
set_font f_kharon, left_align, full_screen
glass_fonts t1$, 0, 0
display: sleep
end sub

You fly a rocket ship around a hex grid of the solar system, starting from Earth, and visiting each planet before returning home.  To navigate, you play cards numbered one to six.  Each time you have to reshuffle the deck, you use up some fuel, and if you run out of fuel, you'll be stranded in space.

The controls are just menu navigation, so just arrow keys, enter/spacebar, and escape.  The game's rules are available from the title menu under "how to play," they're pretty simple.  You can read them in the images under this post before downloading, if you want.

Planet locations are chosen randomly at the start of the game, so each game is unique.  Sometimes the mission will be easy, other times you may struggle to conserve fuel.  I am fairly sure that getting an unwinnable game is mathematically possible, but it hasn't happened to me yet.

I've recreated the game faithfully as it was in the book, but I'd be open to mixing it up a bit, adding features, making the gameplay more complex.  Feel free to offer suggestions!

   

   

Print this item

  Posting Error message is unreadable
Posted by: PhilOfPerth - 10 hours ago - Forum: Site Suggestions - Replies (3)

Maybe it's my setup or something, but when I submit a post, if it's not accepted by the system, 
the error message returned is not legible. It's in black on dark red background. Is there a setting I can change for this?    Huh
(I don't know what my error was when I discovered this, as I couldn't read it).

Print this item

  Program Containing All Inkey$ function codes and all other codes
Posted by: TDarcos - 11 hours ago - Forum: Utilities - No Replies

You're probably aware that the 12 function keys can generate 48 functions (FKey, Shift FKey, Ctrl FKey, Alt Fkey). You might be aware that there are 12 more function keys by using ALT and any of 0-9 , - , and -. You're probably not aware of some functions, like ALT-Pg Down , Shift Pg Down, beyond the usual Pg Down and Ctrl Pg Down. But did you know about ALT-Comma, and Alt-Open Brace (Actually it's available as ALT-[ and as ALT-{.)

I have created a file containing the definition for essentially every key combination recognized by Inkey$ a set of named constants. It's intended to go by most used to least used:

  • All F-Keys
  • ALT numbers
  • ALT punctuation
  • Regular upper case (Capitals)
  • Regular lower case
  • Digits
  • Punctuation
  • Control Characters

I was trying to find a file containing definitions for all key combinations that generate a 2-character Inkey$ string, and not finding one, made one myself. The program at the end will display key combinations, which is how I generated the results, as the reference in the Wiki (which I pasted in as comments at the beginning) does not show all of them.

I've attached the program so it may be downloaded.

This is what it looks like:
Code: (Select All)

'                                ASCII Keyboard Codes
'
'  Esc  F1  F2  F3  F4  F5  F6  F7  F8  F9  F10  F11  F12  Sys ScL Pause
'  27 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68  +133 +134  -  -    -
'  `~  1!  2@  3#  4$  5%  6^  7&  8*  9(  0) -_ =+ BkSp  Ins Hme PUp  NumL  /  *    -
'  126 33  64  35  36  37  94  38  42  40  41 95 43  8    +82 +71 +73    -    47  42  45
'  96 49  50  51  52  53  54  55  56  57  48 45 61
'  Tab Q  W  E  R  T  Y  U  I  O  P  [{  ]}  \|  Del End PDn  7Hme 8/?  9PU  +
'  9  81  87  69  82  84  89  85  73  79  80 123 125 124  +83 +79 +81  +71  +72  +73  43
'    113 119 101 114 116 121 117 105 111 112  91  93  92                55  56  57
'  CapL  A  S  D  F  G  H  J  K  L  ;:  '" Enter                4/?-  5  6/-?
'    -  65  83  68  70  71  72  74  75  76  58  34  13                  +75  +76  +77  E
'        97 115 100 102 103 104 106 107 108  59  39                      52  53  54  n
'  Shift  Z  X  C  V  B  N  M  ,<  .>  /?    Shift      ?        1End 2/?  3PD  t
'    *    90  88  67  86  66  78  77  60  62  63      *        +72      +79  +80  +81  e
'        122 120  99 118  98 110 109  44  46  47                          49  50  51  r
'  Ctrl Win Alt      Spacebar          Alt Win Menu Ctrl  ?-  ?  -?  0Ins    .Del
'  *    -  *          32              *  -  -    *    +75 +80 +77  +82      +83  13
'                                                                        48        46
'
'    Italics = LCase/NumLock On  * = 2 byte combo only,  + = 2 Byte: CHR$(0) + CHR$(code)
'



' Alt #
Const KeyAlt0 = Chr$(0) + Chr$(129)
Const KeyAlt1 = Chr$(0) + Chr$(120)
Const KeyAlt2 = Chr$(0) + Chr$(121)
Const KeyAlt3 = Chr$(0) + Chr$(122)
Const KeyAlt4 = Chr$(0) + Chr$(123)
Const KeyAlt5 = Chr$(0) + Chr$(124)
Const KeyAlt6 = Chr$(0) + Chr$(125)
Const KeyAlt7 = Chr$(0) + Chr$(126)
Const KeyAlt8 = Chr$(0) + Chr$(127)
Const KeyAlt9 = Chr$(0) + Chr$(128)
Const KeyAltMinus = Chr$(0) + Chr$(130)
Const KeyAltPlus = Chr$(0) + Chr$(131)

' Alt + Letter
Const KeyAltA = Chr$(0) + Chr$(30)
Const KeyAltB = Chr$(0) + Chr$(48)
Const KeyAltC = Chr$(0) + Chr$(46)
Const KeyAltD = Chr$(0) + Chr$(32)
Const KeyAltE = Chr$(0) + Chr$(18)
Const KeyAltF = Chr$(0) + Chr$(33)
Const KeyAltG = Chr$(0) + Chr$(34)
Const KeyAltH = Chr$(0) + Chr$(35)
Const KeyAltI = Chr$(0) + Chr$(23)
Const KeyAltJ = Chr$(0) + Chr$(36)
Const KeyAltK = Chr$(0) + Chr$(37)
Const KeyAltL = Chr$(0) + Chr$(38)
Const KeyAltM = Chr$(0) + Chr$(50)
Const KeyAltN = Chr$(0) + Chr$(49)
Const KeyAltO = Chr$(0) + Chr$(24)
Const KeyAltP = Chr$(0) + Chr$(25)
Const KeyAltQ = Chr$(0) + Chr$(16)
Const KeyAltR = Chr$(0) + Chr$(19)
Const KeyAltS = Chr$(0) + Chr$(31)
Const KeyAltT = Chr$(0) + Chr$(20)
Const KeyAltU = Chr$(0) + Chr$(22)
Const KeyAltV = Chr$(0) + Chr$(47)
Const KeyAltW = Chr$(0) + Chr$(17)
Const KeyAltX = Chr$(0) + Chr$(45)
Const KeyAltY = Chr$(0) + Chr$(21)
Const KeyAltZ = Chr$(0) + Chr$(44)

' Function Keys
Const KeyF1 = Chr$(0) + Chr$(59)
Const KeyF2 = Chr$(0) + Chr$(60)
Const KeyF3 = Chr$(0) + Chr$(61)
Const KeyF4 = Chr$(0) + Chr$(62)
Const KeyF5 = Chr$(0) + Chr$(63)
Const KeyF6 = Chr$(0) + Chr$(64)
Const KeyF7 = Chr$(0) + Chr$(65)
Const KeyF8 = Chr$(0) + Chr$(66)
Const KeyF9 = Chr$(0) + Chr$(67)
Const KeyF10 = Chr$(0) + Chr$(68)
Const KeyF11 = Chr$(0) + Chr$(133)
Const KeyF12 = Chr$(0) + Chr$(134)

' Function Keys - Alt
Const KeyAltF1 = Chr$(0) + Chr$(104)
Const KeyAltF2 = Chr$(0) + Chr$(105)
Const KeyAltF3 = Chr$(0) + Chr$(106)
Const KeyAltF4 = Chr$(0) + Chr$(107) ' Closes Program
Const KeyAltF5 = Chr$(0) + Chr$(108)
Const KeyAltF6 = Chr$(0) + Chr$(109)
Const KeyAltF7 = Chr$(0) + Chr$(110)
Const KeyAltF8 = Chr$(0) + Chr$(111)
Const KeyAltF9 = Chr$(0) + Chr$(112)
Const KeyAltF10 = Chr$(0) + Chr$(113)
Const KeyAltF11 = Chr$(0) + Chr$(139)
Const KeyAltF12 = Chr$(0) + Chr$(140)

' Function Keys - Ctrl
Const KeyCtrlF1 = Chr$(0) + Chr$(94)
Const KeyCtrlF2 = Chr$(0) + Chr$(95)
Const KeyCtrlF3 = Chr$(0) + Chr$(96)
Const KeyCtrlF4 = Chr$(0) + Chr$(97)
Const KeyCtrlF5 = Chr$(0) + Chr$(98)
Const KeyCtrlF6 = Chr$(0) + Chr$(99)
Const KeyCtrlF7 = Chr$(0) + Chr$(100)
Const KeyCtrlF8 = Chr$(0) + Chr$(101)
Const KeyCtrlF9 = Chr$(0) + Chr$(102)
Const KeyCtrlF10 = Chr$(0) + Chr$(103)
Const KeyCtrlF11 = Chr$(0) + Chr$(137)
Const KeyCtrlF12 = Chr$(0) + Chr$(138)

' Function Keys - Shift
Const KeyShiftF1 = Chr$(0) + Chr$(84)
Const KeyShiftF2 = Chr$(0) + Chr$(85)
Const KeyShiftF3 = Chr$(0) + Chr$(86)
Const KeyShiftF4 = Chr$(0) + Chr$(87)
Const KeyShiftF5 = Chr$(0) + Chr$(88)
Const KeyShiftF6 = Chr$(0) + Chr$(89)
Const KeyShiftF7 = Chr$(0) + Chr$(90)
Const KeyShiftF8 = Chr$(0) + Chr$(91)
Const KeyShiftF9 = Chr$(0) + Chr$(92)
Const KeyShiftF10 = Chr$(0) + Chr$(93)
Const KeyShiftF11 = Chr$(0) + Chr$(133)
Const KeyShiftF12 = Chr$(0) + Chr$(134)


' Cursor keys -
Const KeyDel = Chr$(0) + Chr$(83)
Const KeyDown = Chr$(0) + Chr$(80)
Const KeyEnd = Chr$(0) + Chr$(79)
Const KeyIns = Chr$(0) + Chr$(82)
Const KeyLeft = Chr$(0) + Chr$(75)
Const KeyPgDown = Chr$(0) + Chr$(81)
Const KeyPgUp = Chr$(0) + Chr$(73)
Const KeyRight = Chr$(0) + Chr$(77)
Const KeyUp = Chr$(0) + Chr$(72)

' Cursor keys - Alt
Const KeyAltDel = Chr$(0) + Chr$(163)
Const KeyAltDown = Chr$(0) + Chr$(160)
Const KeyAltEnd = Chr$(0) + Chr$(159)
Const KeyAltIns = Chr$(0) + Chr$(162)
Const KeyAltLeft = Chr$(0) + Chr$(157)
Const KeyAltPgDown = Chr$(0) + Chr$(161)
Const KeyAltPgUp = Chr$(0) + Chr$(153)
Const KeyAltRight = Chr$(0) + Chr$(155)
Const KeyAltUp = Chr$(0) + Chr$(152)

' Cursor keys - Ctrl
Const KeyCtrlDel = Chr$(0) + Chr$(147)
Const KeyCtrlDown = Chr$(0) + Chr$(145)
Const KeyCtrlEnd = Chr$(0) + Chr$(117)
Const KeyCtrlIns = Chr$(0) + Chr$(146)
Const KeyCtrlLeft = Chr$(0) + Chr$(115)
Const KeyCtrlPgDown = Chr$(0) + Chr$(118)
Const KeyCtrlPgUp = Chr$(0) + Chr$(132)
Const KeyCtrlRight = Chr$(0) + Chr$(116)
Const KeyCtrlUp = Chr$(0) + Chr$(141)

' Cursor keys - Shift
Const KeyShiftDel = Chr$(0) + Chr$(83)
Const KeyShiftDown = Chr$(0) + Chr$(80)
Const KeyShiftEnd = Chr$(0) + Chr$(79)
Const KeyShiftIns = Chr$(0) + Chr$(82)
Const KeyShiftLeft = Chr$(0) + Chr$(75)
Const KeyShiftPgDown = Chr$(0) + Chr$(81)
Const KeyShiftPgUp = Chr$(0) + Chr$(73)
Const KeyShiftRight = Chr$(0) + Chr$(77)
Const KeyShiftUp = Chr$(0) + Chr$(72)

'Other
Const KeyAltComma = Chr$(0) + Chr$(51)
Const KeyAltPeriod = Chr$(0) + Chr$(52)
Const KeyAltSlash = Chr$(0) + Chr$(53)
Const KeyAltSemiColon = Chr$(0) + Chr$(39)
Const KeyAltQuote = Chr$(0) + Chr$(40)
Const KeyAltOpenBracket = Chr$(0) + Chr$(26) '  [
Const KeyAltCloseBracket = Chr$(0) + Chr$(27) ' ]
Const KeyAltBackSlash = Chr$(0) + Chr$(43) '    \
Const KeyAltNumericPlus = Chr$(0) + Chr$(131) ' + on the number pad
Const KeyAltBackspace = Chr$(0) + Chr$(14)
Const KeyAltTilde = Chr$(0) + Chr$(41)

Const KeyCtrlBackspace = Chr$(0) + Chr$(147)

' Capital Letters
Const KeyCapitalA = "A"
Const KeyCapitalB = "B"
Const KeyCapitalC = "C"
Const KeyCapitalD = "D"
Const KeyCapitalE = "E"
Const KeyCapitalF = "F"
Const KeyCapitalG = "G"
Const KeyCapitalH = "H"
Const KeyCapitalI = "I"
Const KeyCapitalJ = "J"
Const KeyCapitalK = "K"
Const KeyCapitalL = "L"
Const KeyCapitalM = "M"
Const KeyCapitalN = "N"
Const KeyCapitalO = "O"
Const KeyCapitalP = "P"
Const KeyCapitalQ = "Q"
Const KeyCapitalR = "R"
Const KeyCapitalS = "S"
Const KeyCapitalT = "T"
Const KeyCapitalU = "U"
Const KeyCapitalV = "V"
Const KeyCapitalW = "W"
Const KeyCapitalX = "X"
Const KeyCapitalY = "Y"
Const KeyCapitalZ = "Z"

' Lower Case
Const KeyLowerCaseA = "a"
Const KeyLowerCaseB = "b"
Const KeyLowerCaseC = "c"
Const KeyLowerCaseD = "d"
Const KeyLowerCaseE = "e"
Const KeyLowerCaseF = "f"
Const KeyLowerCaseG = "g"
Const KeyLowerCaseH = "h"
Const KeyLowerCaseI = "i"
Const KeyLowerCaseJ = "j"
Const KeyLowerCaseK = "k"
Const KeyLowerCaseL = "l"
Const KeyLowerCaseM = "m"
Const KeyLowerCaseN = "n"
Const KeyLowerCaseO = "o"
Const KeyLowerCaseP = "p"
Const KeyLowerCaseQ = "q"
Const KeyLowerCaseR = "r"
Const KeyLowerCaseS = "s"
Const KeyLowerCaseT = "t"
Const KeyLowerCaseU = "u"
Const KeyLowerCaseV = "v"
Const KeyLowerCaseW = "w"
Const KeyLowerCaseX = "x"
Const KeyLowerCaseY = "y"
Const KeyLowerCaseZ = "z"

' Digits
Const KeyDigit0 = "0"
Const KeyDigit1 = "1"
Const KeyDigit2 = "2"
Const KeyDigit3 = "3"
Const KeyDigit4 = "4"
Const KeyDigit5 = "5"
Const KeyDigit6 = "6"
Const KeyDigit7 = "7"
Const KeyDigit8 = "8"
Const KeyDigit9 = "9"

' Punctuation
Const Dquote = Chr$(34) ' "
Const Squote = "''" '    '

Const KeyAmpersand = "&"
Const KeyAsterisk = "*"
Const KeyAt = "@"
Const KeyBackslash = "\"
Const KeyCaret = "^"
Const KeyCloseBracket = "]"
Const KeyCloseCurl = "}"
Const KeyCloseParen = ")"
Const KeyColon = ":"
Const KeyComma = ","
Const KeyDollar = "$"
Const KeyEqual = "="
Const KeyExclamation = "!"
Const KeyGreaterThan = ">"
Const KeyLessThan = "<"
Const KeyMinus = "-"
Const KeyOpenBracket = "["
Const KeyOpenCurl = "{"
Const KeyOpenParen = "("
Const KeyPercent = "%"
Const KeyPeriod = "."
Const KeyPipe = "|"
Const KeyPlus = "+"
Const KeyPound = "#"
Const KeyQuestion = "?"
Const KeySemiColon = ";"
Const KeyTick = "`"
Const KeyTilde = "~"
Const KeyUnderscore = "_"

' Control Codes
Const KeyCtrlA = Chr$(1)
Const KeyCtrlB = Chr$(2)
Const KeyCtrlC = Chr$(3)
Const KeyCtrlD = Chr$(4)
Const KeyCtrlE = Chr$(5)
Const KeyCtrlF = Chr$(6)
Const KeyCtrlG = Chr$(7)
Const KeyCtrlH = Chr$(8)
Const KeyCtrlI = Chr$(9)
Const KeyCtrlJ = Chr$(10)
Const KeyCtrlK = Chr$(11)
Const KeyCtrlL = Chr$(12)
Const KeyCtrlM = Chr$(13)
Const KeyCtrlN = Chr$(14)
Const KeyCtrlO = Chr$(15)
Const KeyCtrlP = Chr$(16)
Const KeyCtrlQ = Chr$(17)
Const KeyCtrlR = Chr$(18)
Const KeyCtrlS = Chr$(19)
Const KeyCtrlT = Chr$(20)
Const KeyCtrlU = Chr$(21)
Const KeyCtrlV = Chr$(22)
Const KeyCtrlW = Chr$(23)
Const KeyCtrlX = Chr$(24)
Const KeyCtrlY = Chr$(25)
Const KeyCtrlZ = Chr$(26)
Const KeyEscape = Chr$(27)
Const KeyFS = Chr$(28) ' File Separator
Const KeyGS = Chr$(29) ' Group Separator
Const KeyRS = Chr$(30) ' Record Separator
Const KeyUS = Chr$(31) ' Unit Separator
Const KeySpace = " "





Do
    R$ = InKey$
    If R$ <> "" Then
        Print Asc(R$, 1);
        If Len(R$) = 2 Then Print Asc(R$, 2)
    End If
Loop









Attached Files
.bas   KeyCodes.bas (Size: 10.3 KB / Downloads: 5)
Print this item

  GnomeSort
Posted by: James D Jarvis - Yesterday, 07:52 PM - Forum: Utilities - Replies (2)

Rosetta code didn't have a QB64 version of a Gnome Sort so I made one.

Code: (Select All)
'GnomeSort.bas
'a sorting algorithm that will sort a one dimensional array of any size from lowest to greatest value
'https://en.wikipedia.org/wiki/Gnome_sort
'initialize two different one dimensional arrays to demonstrate the subroutine
Randomize Timer
Dim A(1 To 6)
Dim B(-5 To 5)
For I = LBound(A) To UBound(A)
    A(I) = (Rnd(1) * 100)
Next I
For I = LBound(B) To UBound(B)
    B(I) = Int(Rnd(1) * 100) + 1
Next I

'display the arrays before and after the gnomesort
Print "unsorted array: ";: printarray A(): Print
gnomesort A()
Print "  sorted array: ";: printarray A(): Print

Print "unsorted array: ";: printarray B(): Print
gnomesort B()
Print "  sorted array: ";: printarray B(): Print
End

Sub printarray (array())
    'print all the elements in a 1 dimensional array  of any range
    For I = LBound(array) To UBound(array)
        Print array(I);
    Next I
End Sub

Sub gnomesort (array())
    'sort a one dimensional array of any size using gnomesort
    'https://en.wikipedia.org/wiki/Gnome_sort
    I = LBound(array) + 1 'find the lowest element in the array and add 1 for the sorting routine
    J = I + 1
    While I <= UBound(array)
        If array(I - 1) <= array(I) Then
            I = J
            J = J + 1
        Else If array(I - 1) > array(I) Then
                Swap array(I - 1), array(I)
                I = I - 1
                If I = LBound(array) Then
                    I = J
                    J = J + 1
                End If
            End If
        End If
    Wend
End Sub

Print this item

  String Addition (Optimization)
Posted by: SMcNeill - Yesterday, 12:48 AM - Forum: Learning Resources and Archives - Replies (8)

Code: (Select All)
Const limit = 200000
Dim Shared NumStr(limit) As String

MakeNumsStrings
t# = Timer(0.001)
o$ = AddStrings 'time how long it takes to add those strings together
t1# = Timer(0.001)
o1$ = MidStrings(Len(o$)) 'and time how long it takes to just mid$ those strings, if you know the size
t2# = Timer(0.001)

Print "Results:"
Print "First 50: "; Left$(o$, 50)
Print "First 50: "; Left$(o1$, 50)
Print "Last  50: "; Right$(o$, 50)
Print "Last  50: "; Right$(o$, 50)
Print
Print
Print Using "It took ###.### seconds to AddStrings"; t1# - t#
Print Using "It took ###.### seconds to MidStrings"; t2# - t1#

Sub MakeNumsStrings
    For i = 1 To limit
        NumStr(i) = _Trim$(Str$(i))
    Next
End Sub

Function AddStrings$
    For i = 1 To limit
        temp$ = temp$ + NumStr(i)
    Next
    AddStrings = temp$
End Function

Function MidStrings$ (size)
    temp$ = Space$(size)
    p = 1 'position in full string
    For i = 1 To limit
        Mid$(temp$, p) = NumStr(i)
        p = p + Len(NumStr(i))
    Next
    MidStrings = temp$
End Function

I think the code above helps showcase one of QB64's and QB64PE's greatest flaws -- the time it takes to do anything substantial with strings!

The above simply makes a list of strings, by using the numbers from 1 to whatever LIMIT we set, and then it adds those strings all into one massive string.   Basicially "1" + "2" + "3" +... = "123..." -- a simple process, but all that is needed to showcase how slow this process can become.  Wink

In the above, I've made use of two different methods for speed comparison, for folks.  

The first method is what we see a lot in our programs:  temp$ = temp$ + num$.  It simply adds the strings together over and over until it's finished.

The second method is much more efficient:  mid%(temp$, p) = num$.  This has to pre-allocate the proper size of the string, create the string, and then it simply uses mid$ to swap out the proper portion of that string with num$ as it goes along.

I won't post my times on this, as I'd prefer for folks to run this code at least once themselves and see what the difference in speed might be on their own system, with whatever compiler flags/optimizations they might be using.  Let's just say that I'm certain folks should be able to see a noticeable difference here.

NOTE:  And one important thing to note here -- the larger the strings involved, the greater the difference becomes.  The difference here isn't a static, "it takes 0.1 seconds to perform X additions to the string".  Change that limit and you can see for yourself.  A limit of 100000 takes X seconds.  A limit of 110000 takes 2 * x seconds.  A limit of 120000 takes 4 * x seconds.  Exponential time increases as string length increases!!  (Though not quite as bad as the * 2 modifier I just tossed out as an example to the left there.  Big Grin )


Take away from all this??

If you're going to be doing a lot of string addition, you'd probably be better served by running it through two loops, instead of just adding the strings together in one.

Loop 1:   Count the total size of the string
FOR i = 1 TO limit
    totalSize = totalSize + len(num$(i))
NEXT

Allocate the output string first:   
temp$ = SPACE$(totalSize)

Loop 2: Mid$ the string together instead of adding it
p = 1
FOR i = 1 TO limit
    mid$(temp$, p) = num(i)
    p = p + len(num(i))
NEXT


It's thinking outside the box, and it's not the way that most folks tend to do things, but I'd think the above showcases WHY this might be an important concept to keep under your hat, if you're ever doing any serious string work in your projects.

(And feel free to post your own times below.  I'd love to see how large a difference such a simple approach makes for most people on their own systems.  I just don't want to spoil the surprise by posting my own times here, and you guys might not want to read below this post until you run the code for yourself once, just for the "pop factor" of the figures. Big Grin )

Print this item

  no link for the matacommands on main page
Posted by: Jack - 04-25-2024, 10:23 PM - Forum: Wiki Discussion - Replies (2)

I couldn't find any link for the meta commands on main page, had to click on $ASSERTS which then gave me a link for the meta commands https://qb64phoenix.com/qb64wiki/index.php/Metacommand

Print this item

  AI does a good job of analyzing code
Posted by: SpriggsySpriggs - 04-25-2024, 03:26 PM - Forum: General Discussion - Replies (6)

I asked Perplexity AI what it thought my pipecom code did by asking it to read that page of the forum.

My prompt was

Quote:Analyze the code in the code block and give a best guess as to what it is used for

The response:
Quote:The code you provided appears to be an implementation of a pipe command in QB64, a BASIC programming language. The purpose of this code is to allow executing external commands and capturing their output and error streams[1].

Here's a breakdown of what the code does:

1. It defines a function called `pipecom` that takes a command string, an output string variable, and an error string variable as parameters.

2. The function creates two pipes using `CreatePipe` - one for standard output and one for standard error. It also sets up the necessary security attributes and startup information for the child process.

3. It then creates a child process using `CreateProcess` or `CreateProcessW` (depending on whether UNICODE is defined) to execute the specified command.

4. The function reads the output from the child process's standard output and error pipes using `ReadFile` and stores them in the provided output and error string variables.

5. Finally, it waits for the child process to exit, retrieves its exit code, and returns it.

There is also a helper function called `pipecom_lite` that simplifies the usage of `pipecom` by returning either the standard output or standard error stream as a string, depending on which one is not empty.

This code allows running external commands and capturing their output and error streams within a QB64 program, which can be useful for tasks such as executing system commands, parsing command output, or handling errors from external processes.

Citations:
[1] https://qb64phoenix.com/forum/showthread...20has%20co

Here is the link to the actual AI thread

Print this item

  Another Mouse Issue?
Posted by: NakedApe - 04-25-2024, 12:54 AM - Forum: Help Me! - Replies (12)

I'm working on a game, see, and I don't want the player to be able to hold down the fire-button indefinitely (that's cheating!). So I tried setting up a timer that kills the left mouse button after a second and a half. All is cool if the mouse is stationary, but the minute you move the mouse the button resets itself - without the user letting the button up - not cool. Is this a Mac mouse issue, a QB64PE mouse issue or a dumb NakedApe issue?
Is there a better way to do this?     Huh  

Thanks in advance for any insights, Ted

DIM AS _BYTE leftClick, started
DIM startTime AS LONG
SCREEN _NEWIMAGE(800, 600, 32)

DO
    WHILE _MOUSEINPUT
        leftClick = _MOUSEBUTTON(1) '
        mouseX = _MOUSEX
        mouseY = _MOUSEY
    WEND

    IF leftClick THEN

        IF NOT started THEN startTime = TIMER: started = -1

        IF TIMER - startTime > 1.5 THEN '    no holding the button down forever!
            leftClick = 0 '                              kill left click
            started = 0 '                                reset timer
            SOUND 1000, .7 '                         pip
        END IF

        _PRINTSTRING (380, 280), "Button Down"
        _PRINTSTRING (380, 320), STR$(TIMER - startTime)
    END IF

    IF NOT leftClick THEN '                            if buttonUP then reset timer and erase
        CLS
        started = 0
    END IF

LOOP UNTIL _KEYDOWN(27)
SYSTEM

Print this item

  Alphabetical sort of characters within a string.
Posted by: Circlotron - 04-24-2024, 12:25 PM - Forum: Help Me! - Replies (46)

I want to alphabetically sort the characters of a single word string. The only way i can think of so far is to get each character individually and make each one a single character variable, check the ASC value and bubble sort them with a SWAP function. Is there a better way?

Print this item

  How to reorder string variable x factorial different ways?
Posted by: Circlotron - 04-24-2024, 11:14 AM - Forum: Help Me! - Replies (13)

Say I have a string variable abcd$. The letters in the variable can be arranged 4 factorial or 4x3x2x1 different ways. How can I produce every combination? Find Len(abcd$) then a for/next loop Len factorial times, but what inside the loop? I'm at a loss here. Huh

Print this item