#---
#Fighting fantasy library
#---
#Release 1
#---


constant skill 1 ;The current skill of a creature.
constant stamina 3 ;The current stamina of a creature.
constant istamina 4 ;The initial stamina of a creature.
constant luck 5 ;The current luck of a creature.
constant iluck 6 ;The initial luck of a creature.
constant attackstrength 7 ;The attack strength of a creature in combat.
constant damage 8 ;The effectiveness in combat.
constant dice1 9 ;Four dice, mainly used by the random number generator.
constant dice2 10
constant dice3 11
constant dice4 12
constant iskill 13 ;The initial skill of a creature.

#Combat bonuses
constant DoubleBonus 1 ;The player has two equal dice
constant FirstHitBonus 2 ;The player manages to hit his/her opponent for the first time

attribute CantChoose ;A location tagged with this attribute will have no numbered menu to choose a direction from.

integer InCombat false ;When combat begins, this variable should be changed to true.
integer VictoryPage 0 ;After a successful test, the player will be moved to this location.
integer FailedPage 0 ;After a failed test, the player will be moved to this location.
integer turncount 0 ;A variable to keep track of the turns in combat.
integer turnslimit 0 ;A variable to limit the player's turns in combat

integer_array CombatBonus 2 0 ;The array of combat bonuses (up to two items)
integer MAX_OPTION
integer_array OPTIONS 10 0
integer OPTION_COUNT 0
integer temp 0
integer MONSTERS 10 0
integer MONSTER_COUNT
integer FIRST_FIGHTING_OPTION
integer multipleTests false

#The text which is printed when the player types 'eq'
string before_eq "Looking into your backpack you see:"

grammar $integer >number

grammar blankjacl >blankjacl

grammar eq >display_eq

grammar stats >PrintStats

integer status_window 3

integer INDEX

string status_text "null"

{+update_status_window
style reverse
padstring status_text " " status_width
write status_text
cursor 0 1
write status_text
cursor 0 2
write status_text

execute "+print_right<game_title<0"

cursor 1 0
write "SKILL:   (" player(iskill) ") " player(skill)
cursor 1 1
write "STAMINA: (" player(istamina) ") " player(stamina)
cursor 1 2
write "LUCK:    (" player(iluck) ") " player(luck)

setstring status_text "Section " here{The}
execute "+print_right<status_text<2"

style normal
}

integer OFFSET

{+print_right
set OFFSET = status_width
length INDEX string_arg[0]
set OFFSET - INDEX - 1
cursor OFFSET arg[1]
write string_arg[0]
}

{+GetInitialStats
write "Your initial stats are:^"

set player(dice1) = +rnd<6
set player(iskill) = player(dice1) + 6
set player(skill) = player(iskill)
write "Skill: " player(skill) " (" player(dice1) " + 6)^"

set player(dice1) = +rnd<6
set player(dice2) = +rnd<6
set player(istamina) = player(dice1) + player(dice2) + 12
set player(stamina) = player(istamina)
write "Stamina: " player(stamina) " (" player(dice1) " + " player(dice2) " + 12)^"

set player(dice1) = +rnd<6
set player(iluck) = player(dice1) + 6
set player(luck) = player(iluck)
write "Luck: " player(luck) " (" player(dice1) " + 6)^"
}

{+rnd
set max_rand = arg[0]
return random
}

{+TestYourLuck
write "Testing your luck:^"
set player(dice1) = +rnd<6
set player(dice2) = +rnd<6
set temp = player(dice1) + player(dice2)
if arg[0] = 0
write "You roll a " player(dice1) " and a " player(dice2) ", which "
write "equals " temp ". Comparing this to your current luck (" player(luck) ") "
else
set temp + arg[0]
write "You roll a " player(dice1) " and a " player(dice2) ". "
if arg[0] < 0
write "Subtracting "
else
write "Adding "
endif
write arg[0] " "
if arg[0] > 1 : arg[0] < -1
write "modifier points "
else
write "modifier point "
endif
write "to the result, it equals " temp ". Comparing this to your current luck (" player(luck) ") "
endif
if temp <= player(luck)
write "you are lucky.^"
execute +DecreaseLuck<1
move player to VictoryPage
set VictoryPage = 0
set FailedPage = 0
look
return
else
write "you are unlucky.^"
execute +DecreaseLuck<1
set VictoryPage = 0
move player to FailedPage
set FailedPage = 0
look
return
endif
}

{+TestYourSkill
write "Testing your skill:^"
set player(dice1) = +rnd<6
set player(dice2) = +rnd<6
set temp = player(dice1) + player(dice2)
if arg[0] = 0
write "You roll a " player(dice1) " and a " player(dice2) ", which "
write "equals " temp ". Comparing this to your current skill (" player(skill) ") "
else
set temp + arg[0]
write "You roll a " player(dice1) " and a " player(dice2) ". "
if arg[0] < 0
write "Subtracting "
else
write "Adding "
endif
write arg[0] " "
if arg[0] > 1 : arg[0] < -1
write "modifier points "
else
write "modifier point "
endif
write "to the result, it equals " temp ". "
write "Comparing this to your current skill (" player(skill) ") "
endif
if temp <= player(skill)
write "you are skillful.^"
move player to VictoryPage
set VictoryPage = 0
set FailedPage = 0
look
return
else
write "you are unskillful.^"
move player to FailedPage
set VictoryPage = 0
set FailedPage = 0
look
return
endif
}

{+TestYourStamina
write "Testing your stamina:^"
set player(dice1) = +rnd<6
set player(dice2) = +rnd<6
set player(dice3) = +rnd<6
set player(dice4) = +rnd<6
set temp = player(dice1) + player(dice2) + player(dice3) + player(dice4)
if arg[0] = 0
write "You roll a " player(dice1) ", a " player(dice2) ", a "
write player(dice3) " and a " player(dice4) ", which "
write "equals " temp ". Comparing this to your current stamina (" player(stamina) ") "
else
set temp + arg[0]
write "You roll a " player(dice1) ", a " player(dice2) ", a "
write player(dice3) " and a " player(dice4) ". "
if arg[0] < 0
write "Subtracting "
else
write "Adding "
endif
write arg[0] " "
if arg[0] > 1 : arg[0] < -1
write "modifier points "
else
write "modifier point "
endif
write "to the result, it equals " temp ". "
write "Comparing this to your current stamina (" player(stamina) ") "
endif
if temp <= player(stamina)
write "you are strong.^"
move player to VictoryPage
set VictoryPage = 0
set FailedPage = 0
look
return
else
write "you are weak.^"
move player to FailedPage
set VictoryPage = 0
set FailedPage = 0
look
return
endif
}

{+DecreaseLuck
if player(luck) > 1
set player(luck) - arg[0]
write "You lose " arg[0] " luck.^"
if player(luck) < 1
set player(luck) = 1
endif
write "Your luck is now " player(luck) .^
endif
}

{+IncreaseLuck
if player(luck) < player(iluck)
set player(luck) + arg[0]
write "You gain " arg[0] " luck.^"
if player(luck) > player(iluck)
set player(luck) = player(iluck)
endif
write "Your luck is now " player(luck) .^
endif
}

{+DecreaseStamina
set player(stamina) - arg[0]
if player(stamina) < 1
execute +game_over
else
write "You lose " arg[0] " stamina.^"
write "Your stamina is now " player(stamina) .^
endif
}

{+IncreaseStamina
if player(stamina) < player(istamina)
set player(stamina) + arg[0]
write "You gain " arg[0] " stamina.^"
if player(stamina) > player(istamina)
set player(stamina) = player(istamina)
endif
write "Your stamina is now " player(stamina) .^
endif
}

{+DecreaseSkill
if player(skill) > 1
set player(skill) - arg[0]
write "You lose " arg[0] " skill.^"
if player(skill) < 1
set player(skill) = 1
endif
write "Your skill is now " player(skill) .^
endif
}

{+IncreaseSkill
if player(skill) < player(iskill)
set player(skill) + arg[0]
write "You gain " arg[0] " skill.^"
if player(skill) > player(iskill)
set player(skill) = player(iskill)
endif
write "Your skill is now " player(skill) .^
endif
}

 
{+blankjacl
write "Invalid command^"
}

{+number
if $integer < 1 : $integer > OPTION_COUNT
   if OPTION_COUNT = 1
      write "The only available choice is 1.^"
      return true
   else
      write "Please choose a number between 1 and " OPTION_COUNT .^
      return true
   endif
endif
ifall here = combat : $integer => FIRST_FIGHTING_OPTION
   # THE OPTIONS TO DO WITH FIGHTING ARE HANDLED DIFFERENTLY TO NORMAL OPTION
   execute "+combat_action<OPTIONS[$integer]"
   ifall InCombat = false : VictoryPage > 0
      move player to VictoryPage
      look
   set VictoryPage = 0
   return
   endif
else
   execute here.OPTIONS[$integer]
endif
}

{+clear_options
set OPTION_COUNT = 0;
set FIRST_FIGHTING_OPTION = 0;
}

{+add_option
if OPTION_COUNT = 10
   # NO MORE ROOM
   return false
endif
set OPTION_COUNT + 1
write OPTION_COUNT ". " string_arg[1] ^
set OPTIONS[OPTION_COUNT] = arg[0]
return true
}

{+add_fighting_option
if OPTION_COUNT = 10
   # NO MORE ROOM
   return false
endif
set OPTION_COUNT + 1
write OPTION_COUNT ". Fight " current_monster{the} ^
set OPTIONS[OPTION_COUNT] = arg[0]
if FIRST_FIGHTING_OPTION = 0
   # NOTE THE INDEX OF THE FIRST FIGHTING OPTION BECAUSE THEY ARE HANDLED 
   # DIFFERENTLY
   set FIRST_FIGHTING_OPTION = OPTION_COUNT
endif
return true
}

{+footer
if here hasnt CantChoose
   execute here.choices
endif
}

location combat : Combat
short name "Combat"

integer current_monster
integer MONSTER_COUNT

{look
write "Your stamina: " player(stamina) ^
write "Your skill: " player(skill) ^

# LOOP THROUGH ALL THE OBJECTS IN THE GAME
loop current_monster
   ifall current_monster(parent) = combat : current_monster != player
      # IF IT IS IN THIS LOCATION AND NOT THE PLAYER, IT MUST BE A MONSTER
      write current_monster{The} "'s stamina: " current_monster(stamina) ^
   write current_monster{The} "'s skill: " current_monster(skill) ^
   endif
endloop
}

{choices
execute "+clear_options"
# ADD COMBAT-ONLY ANY NORMAL OPTIONS HERE
#execute "+add_option<1<Cower in the corner.
#execute "+add_option<2<Try to negotiate peace.

# OUTPUT THE FIGHTING OPTIONS BY PASSING TRUE TO build_monster_list
execute "+build_monster_list<true"
}

{+build_monster_list
set MONSTER_COUNT = 0;
loop current_monster
   ifall current_monster(parent) = combat : current_monster != player
      # IF IT IS IN THIS LOCATION AND NOT THE PLAYER, IT MUST BE A MONSTER
      # STORE THE MONSTER IN THE MONSTERS ARRAY. NOTE THE MONSTER COUNT STARTS 
      # AT ZERO WHERE THE OPTION COUNT STARTS AT ONE
      set MONSTERS[MONSTER_COUNT] = current_monster
      set MONSTER_COUNT + 1

      # TEST IF WE NEED TO ALSO ADD THE OPTION SO WE CAN USE THIS FUNCTION
      # TO SILENTLY REBUILD THE LIST OF REMAINING MONSTERS LATER
      if arg[0] = true
         execute +add_fighting_option<current_monster
      endif
   endif
endloop
}

integer opponent

{+combat_action
# FIGURE OUT WHICH MONSTER THE PLAYER IS ATTACKING
set opponent = arg[0]

write "You attack " opponent{the} ".^"

set player(dice1) = +rnd<6
set player(dice2) = +rnd<6
set player(attackstrength) = 0
set player(attackstrength) + player(dice1) + player(dice2) + player(skill)
write "Your attack strength: " player(attackstrength) " (" player(dice1) " + " 
write player(dice2) " + " player(skill) ").^"

#rolling for all the enemies

set INDEX = 0

while INDEX < MONSTER_COUNT
   set current_monster = MONSTERS[INDEX]
   set current_monster(dice1) = +rnd<6
   set current_monster(dice2) = +rnd<6
   set current_monster(attackstrength) = 0
   set current_monster(attackstrength) + current_monster(dice1) + current_monster(dice2) + current_monster(skill)
   set INDEX + 1
endwhile

#checking for bonuses
if +bonuses = false
   # NO BONUSES, SO LETS COMPARE attackstrength
   write opponent{The} "'s attack strength: " opponent(attackstrength) " (" opponent(dice1) 
   write " + " opponent(dice2) " + " opponent(skill) ").^"
   execute "+attack_compare<opponent"
endif

if MONSTER_COUNT = 0
   # THE LAST MONSTER HAS NOW BEEN KILLED. VICTORY!
   execute +ResetCombat
   return true
endif

set INDEX = 0
# NOW THE OTHER MONSTERS GET TO FIGHT BACK.
while INDEX < MONSTER_COUNT
   set current_monster = MONSTERS[INDEX]
   if current_monster != opponent # DON'T FIGHT THE SAME GUY TWICE
      set player(dice1) = +rnd<6
set player(dice2) = +rnd<6
set player(attackstrength) = 0
set player(attackstrength) + player(dice1) + player(dice2) + player(skill)
write "Your attack strength: " player(attackstrength) " (" player(dice1) " + " 
write player(dice2) " + " player(skill) ").^"
      write current_monster{The} "'s attack strength: " current_monster(attackstrength) " (" 
      write current_monster(dice1) " + " current_monster(dice2) " + " current_monster(skill) ").^"
      execute "+being_attacked<current_monster"
   endif 
   set INDEX + 1
endwhile

if turnslimit > 0
set turncount + 1
if turncount >= turnslimit
loop
if noun3(parent) = combat
move noun3 to limbo
endif
endloop
move player to FailedPage
set VictoryPage = 0
set FailedPage = 0
look
endif
endif
}

{+bonuses
if CombatBonus[0] = DoubleBonus : CombatBonus[1] = DoubleBonus
   if player(dice1) = player(dice2)
      # IN THIS CASE YOU HAVE ONLY KILLED YOUR OPPONENT
	  write "You kill " opponent{the} ".^"
      move opponent to limbo
      # REBUILD THE LIST AS THERE IS NOW ONE LESS MONSTER
      execute "+build_monster_list<false"
      return true
   endif
endif
if CombatBonus[0] = FirstHitBonus : CombatBonus[1] = FirstHitBonus
if player(attackstrength) > opponent(attackstrength)
	  # Caught the first hit of the player
   execute "+attack_compare<opponent"
loop
if noun3(parent) = combat
move noun3 to limbo
endif
endloop
move player to VictoryPage
execute +ResetCombat
look
set VictoryPage = 0
return true
else
#The player was not able to damage his/her opponent, continuing normally...
return false
endif
endif
return false
}

{+being_attacked
if player(attackstrength) < arg[0](attackstrength)
   write arg[0]{The} " hits you!^"
   set player(stamina) - arg[0](damage)
      if player(stamina) < 1
      write "*** You have died ***^"
      execute +game_over
return
else
write "Your stamina is " player(stamina) ^
   return
   endif
else
   write arg[0]{The} " misses you!^"
endif
}

{+attack_compare
# THIS FUNCTION COMPARES THE ATTACK STRENGTH OF THE PLAYER AGAINST A MONSTER
# AND SUBTRACTS THE DAMAGE OF THE WINNER FROM THE STAMINUM OF THE LOOSER. 
if player(attackstrength) > arg[0](attackstrength)
   write "You hit " arg[0]{the} "!^"
   set arg[0](stamina) - player(damage)
      if arg[0](stamina) < 1
      write "You kill " arg[0]{the} ".^"
      move arg[0] to limbo
            # REBUILD THE LIST TO SEE HOW MANY ARE LEFT
      execute "+build_monster_list<false"
   return
   else
      write arg[0]{The} "'s stamina is " arg[0](stamina) ^
      return
   endif
endif
if player(attackstrength) < arg[0](attackstrength)
   write arg[0]{The} " hits you!^"
   set player(stamina) - arg[0](damage)
      if player(stamina) < 1
      write "*** You have died ***^"
      execute +game_over
return
else
write "Your stamina is " player(stamina) ^
return
   endif
   endif
write "You draw with " arg[0]{the} ".^"
}

location limbo


{+ResetCombat
set CombatBonus[0] = 0
set CombatBonus[1] = 0
set turnslimit = 0
set turncount = 0
set InCombat = false
}


{+take_eq
set arg[0](parent) = player
}

{+drop_eq
set arg[0](parent) = limbo
}

integer FirstItem
integer ItemCounter

{+display_eq
set FirstItem = true

write before_eq ^

loop
if noun3(parent) = player
set ItemCounter + 1
endif
endloop

if ItemCounter = 0
write "Nothing.^"
return
else
loop
if noun3(parent) = player
if FirstItem = true
write noun3{List}
set FirstItem = false
set ItemCounter - 1
execute +ListItemSeparator
else
write noun3{list}
set ItemCounter - 1
execute +ListItemSeparator
endif
endif
endloop
endif
}

{+ListItemSeparator
if ItemCounter > 1
write ", "
else
if ItemCounter = 1
write " and "
else
write .^
endif
endif
}

{+PrintStats
write "Your stats are:^"
write "Skill: " player(skill) " out of " player(iskill) ".^"
write "Stamina: " player(stamina) " out of " player(istamina) ".^"
write "Luck: " player(luck) " out of " player(iluck) ".^"
}

{+game_over
   write "---[Your adventure ends here.]---^"
   endgame
}

{+title
style subheader
write here{the} ^
style normal
}

{+look_around
ensure here hasnt VISITED
execute "+display_location"
set time = false
}

{+display_location
if here has DARKNESS
   execute "+dark_description"
   return
endif
call "+title"
if display_mode = true
   ensure here hasnt VISITED
endif
execute "here.look"
ensure here has KNOWN
ensure here has VISITED
ensure here has MAPPED
execute "+object_descriptions"
}

{+object_descriptions
loop
   ifall noun3(parent) = here : noun3(mass) < scenery : noun3 hasnt LOCATION
      write ^ noun3{long}
   endif
endloop
}
