//
// This is a simple combat simulator
//
// Many of the different structure,
// address, an pointer operations are
// demonstrated. A few of the many
// flow control constructs are shown,
// including loops, tests, and function
// calls.
//
// A note about in-line strings. When a
// string is encountered in-line, space
// is allocated on the fly for the string
// in memory. PLASMA doesn't have garbage
// collection, so that memory adds up
// until the function exits (or the
// proram ends in the main function).
// If you use strings inside a loop, you
// may overflow memory. Try moving the
// string outside the loop, or into
// initialized memory.
//
const rndnum = $4E // ZP location of RND
const rndl   = $4E
const rndh   = $4F

struc t_player
  byte name[32]
  word morality
  byte health
  byte stamina
  byte strength
  byte skill
end

byte[32] player = "Player"
word            = 0   // morality
byte            = 0   // health
byte            = 10  // stamina
byte            = 50  // strength
byte            = 20  // skill

struc t_actor
  byte kind
  byte life
  byte power
  word ethics
  word next_actor
end

byte preacher = "Preacher", 200
byte zombie   = "Zombie",   0
byte cowboy   = "Cowboy",   129
byte clerk    = "Clerk",    128
byte merchant = "Merchant", 192
byte rustler  = "Rustler",  60
byte traveler = "Traveler", 132
byte rogue    = "Rogue",    30

//
// Notice how the array is initialized
// with the addresses of prior records.
//
word actors = @preacher, @zombie, @cowboy
word        = @clerk, @merchant, @rustler
word        = @traveler, @rogue, 0

byte fightstr = "F)ight or R)un?"
byte whostr   = "Whom do you want to fight (0=quit)?"
byte numactors
word choice

def rnd
  *rndnum = (*rndnum << 1) + *rndnum + 251
  return *rndnum & $7FFF
end

//
// Apple //e and //c computers can input
// lower-case, so convert all input into
// upper-case for easier testing.
//
def toupper(c)
  if c >= 'a' and c <= 'z'
    c = c - ('a' - 'A')
  fin
  return c
end

def putstats(other)
  home()
  gotoxy(0, 0)
  puts(@player.name)
  if player.health == 0
    puts(" Died!")
  fin
  gotoxy(1, 1)
  puts("Morality:"); puti(player:morality)
  gotoxy(1, 2)
  puts("Skill   :"); puti(player.skill)
  gotoxy(1, 3)
  puts("Stamina :"); puti(player.stamina)
  gotoxy(1, 4)
  puts("Strength:"); puti(player.strength)
  gotoxy(1, 5)
  puts("Health  :"); puti(player.health)

  gotoxy(20, 0)
  puts(actors[other->kind])
  if other->life == 0
    puts("Died!")
  fin
  gotoxy(21, 1)
  puts("Ethics  :"); puti(other=>ethics)
  gotoxy(21, 2)
  puts("Power   :"); puti(other->power)
  gotoxy(21, 3)
  puts("Life    :");  puti(other->life)
end

def fight(who)
  byte[t_actor] enemy
  byte quit
  word p_atck, e_atck

  enemy.kind   = who
  enemy:ethics = ^(actors[who] + ^(actors[who]) + 1) - 128
  enemy.power  = 64  + (rnd & 191)
  enemy.life   = 128 + (rnd & 127)

  quit = 0
  repeat
    putstats(@enemy)
    gotoxy(12, 8); puts(@fightstr)
    if toupper(getc()) == 'F'
      p_atck = player.skill * player.strength / enemy.power
      p_atck = p_atck + (rnd() & 15)
      if enemy.life > p_atck
        enemy.life = enemy.life - p_atck
      else
        player:morality = player:morality - enemy:ethics
        enemy.life = 0
        p_atck     = player.skill + enemy.power / 10
        if p_atck > 255 // Limit skill
          p_atck = 255
        fin
        player.skill = p_atck
        quit         = 1
      fin
      e_atck = enemy.power / player.stamina
      e_atck = e_atck + (rnd() & 15)
      if player.health > e_atck
        player.health = player.health - e_atck
      else
        player.health = 0
        quit          = 1
      fin
    else
      quit = 1
    fin
  until quit
  putstats(@enemy)
end

//
// This is the main loop. Know when to
// walk away, know when to run.
//
home()
repeat
  player.health = 192 + (rnd & 63)
  numactors = 0
  repeat
    gotoxy(10, 10 + numactors)
    puti(numactors + 1); putc(' ')
    puts(actors[numactors])
    numactors = numactors + 1
  until not actors[numactors]
  gotoxy(2, 11 + numactors)
  puts(@whostr)
  choice = getc() - '0'
  if choice > 0 and choice <= numactors
    fight(choice - 1)
  elsif choice == 0
    player.health = 0
  fin
until player.health == 0
gotoxy(0, 21); puts("That's all, folks!")
done
