!
! CASTING.SCR - Spell Casting script
!
! This script implements spell casting for wizards and elves.
!
! (c) DC Software, 1992
!
! Pending Enhancements
!
! - This script has no voices.  For an example of voices, look at
!   MERCHANT.SCR and HEALER.SCR.  Also, look at the OBJECT.SCR for
!   the sounds that are used for type 1 magic (heal,cure,resurect,
!   etc).  The same kind of sound applies here.
!
! - This entire set of code is currently duplicated in the OBJECT.SCR
!   file, since type 2 magic can be invoked by both a magic user (casting
!   a spell) or by using an object (Scrolls and Staffs).  I need a 
!   method for writing the script once and including it in two other
!   places.
!

:@CAST

if player.hp = 0 then 
  writeln( player.name, " is dead!" );
  STOP;
endif;

if player.class <> WIZARD and player.class <> ELF then
  writeln( player.name, " does not have magical abilities." );
  STOP;
endif;

if player.pwr <= 0 then
  writeln( player.name, " has no power left.." );
  STOP;
endif;

if fighting then
  L0 = select( "Kill", 20, "Confuse", 1, "Scare", 2, "Damage", 5, "Paralyze", 5 );
  on L0 goto X_KILL, X_CONFUSE, X_SCARE, X_DAMAGE, X_PARALYZE;
else
  L0 = select( "Destroy",       5,
               "Duplicate",    40,
               "Leave",         5,
               "Resurrect",    50,
               "Inform",        5,
               "Locate Doors", 10,
               "Recharge",     25,
               "Float",        10,
               "Analyze",      10,
               "View",         10 );
  on L0 goto X_DESTROY, X_DUPLICATE, X_LEAVE, X_RESURRECT, X_INFORM,
             X_LOCATE, X_RECHARGE,  X_FLOAT, X_ANALYZE,   X_ZOOM;
endif;

writeln( "Ok." );
STOP;

:X_DESTROY  
  L0 = DESTROY;   L1 = 5;  L2 = 10;
  gosub X_TARGET; goto X_DOIT;

:X_DUPLICATE
  L0 = DUPLICATE; L1 = 40; L2 = 1;
  gosub X_TARGET; goto X_DOIT;

:X_LEAVE  
  L0 = LEAVE; L1 = 5;
  goto X_DOIT;

:X_RESURRECT
  L0 = RESURRECT; L1 = 50;
  goto X_DOIT;

:X_INFORM  
  L0 = INFORM; L1 = 5;
  goto X_DOIT;

:X_LOCATE 
  L0 = DOORS; L1 = 10;
  goto X_DOIT;

:X_KILL  
  L0 = KILL;    L1 = 20; L2 = 6;
  gosub X_TARGET; goto X_DOIT;

:X_CONFUSE  
  L0 = CONFUSE; L1 =  1;
  goto X_DOIT;

:X_SCARE  
  L0 = SCARE;   L1 =  2;
  goto X_DOIT;

:X_DAMAGE  
  L0 = DAMAGE;  L1 =  5;
  goto X_DOIT;

:X_PARALYZE
  L0 = PARALYZE; L1 = 5;
  goto X_DOIT;

:X_RECHARGE
  L0 = RECHARGE; L1 = 25; L2 = 1;
  gosub X_TARGET; goto X_DOIT;

:X_FLOAT  
  L0 = FLOAT; L1 = 10; L2 = 1;
  gosub X_TARGET; goto X_DOIT;

:X_ANALYZE  
  L0 = ANALYZE; L1 = 10; L2 = 1; 
  gosub X_TARGET; goto X_DOIT;

:X_ZOOM  
  L0 = ZOOM; L1= 10;
  goto X_DOIT;

:X_DOIT
  if player.pwr < L1 then
    writeln( player.name, " doesn't have enough power.." );
    STOP;
  endif;

  dec( player.pwr, L1 );

  if L0 = DAMAGE or L0 = CONFUSE or L0 = SCARE or L0 = PARALYZE then
    !
    ! These spells operate on EVERY monster
    !
    ! L5 will contain the TOTAL experience points gained when done..
    ! L6 is the maximum damage that will be done to a single monster..
    ! L8 is the maximum total damage that can be done to a group of monsters..
    ! L9 is the number of monsters affected..
    !
    L5 = 0;
    L6 = player.level + adjustments(player.pwr) / 2 + 1;
    if L6 <= 0 then
      writeln( "The spell failed.." );
      STOP;
    endif;
    L8 = player.iq;
    L9 = 0;
  endif;

  on L0 goto 
    M2_NONE,     M2_DESTROY,  M2_DUPLICATE, M2_LEAVE,
    M2_RESURRECT,M2_INFORM,   M2_LOCATE,    M2_KILL, 
    M2_CONFUSE,  M2_SCARE,    M2_DAMAGE,    M2_PARALYZE,
    M2_RECHARGE, M2_FLOAT,    M2_ANALYZE,   M2_ZOOM;

:M2_NONE      ! No spell
  writeln( "Nothing happens.." );
  STOP;

:M2_DESTROY   ! Destroy an object
  writeln( "The ", object.type, " is destroyed.." );
  vanish( object );
  STOP;

:M2_DUPLICATE ! Duplicates an object
  writeln( "The ", object.type, " has been duplicated.. " );
  inc( object.count, 1 ); ! Creates an identical copy ! 
  STOP;

:M2_LEAVE     ! Exit through the 'exit' door from anywhere...  
  if world.type <> DUNGEON then
    writeln( "This spell only work's in dungeons.." );
    STOP;
  endif;
  enter( world.edgedoor );
  writeln( "You leave this level of the dungeon.." );
  STOP;

:M2_RESURRECT ! Revive a DEAD person                   
  write( "Resurrect: " );
  L3 = select( group );
  if player.hp > 0 then
    writeln( player.name, " is not dead!  The spell fails." );
  else
    writeln( player.name );
    player.hp = 2;
    writeln( player.name, " is alive, but weak.." );
  endif;
  STOP;

:M2_INFORM    ! Displays some text                     
  loadhint;
  writeln( "The wind seems to carry a random phrase to your ears.." );
  writeln( s0 );
  STOP;

:M2_LOCATE    ! Locate doors                           
  for L5 = 0 to 15 do
    if world.doorx(L5) > 0 and world.doory(L5) > 0 then
      frame( world.doorx(L5), world.doory(L5), SYS_FRAME );
    endif;
  endfor;
  STOP;

:M2_KILL      ! Kill 1 enemy during battle             
  writeln( npc.name, " killed. +", npc.hp, " exp." );
  inc( player.exp, npc.hp );
  npc.hp = 0;
  STOP;

:M2_DAMAGE    ! Causes damage to monsters              
  S0 = "hit";
  foreach npc do
    L7 = min( npc.hp, random(L6) );  ! How much damage to this one monster?
    if L7 > 0 then
      frame(npc.x, npc.y, SYS_SPLAT); wait(1); frame(npc.x, npc.y, SYS_SPLAT);
      write( npc.name );
      if L7 < npc.hp then
        write( " hit." );
        dec( npc.hp, L7 );           ! Hit the monster..
      else
        write( " killed!" );
        npc.hp = 0;
      endif;
      writeln( " +", L7, " exp." );
      inc(L9);                       ! Count of affected npcs
      inc( L5, L7 );                 ! Accumulate experience..
      if L5 > L8 goto DCSPEXIT;      ! Stop when total of L8 points used
    endif;
  endfor;  
  goto DCSPEXIT;

:M2_CONFUSE   ! Makes monsters shoot at other monsters 
  S0 = "confused";
  foreach npc do
    L7 = min( npc.hp, random(L6) );  ! How much confusion to this one monster?
    if L7 > 0 and npc.confused = 0 then
      frame(npc.x, npc.y, SYS_SPLAT); wait(1); frame(npc.x, npc.y, SYS_SPLAT);
      inc(L9);                       ! Count of affected npcs
      npc.confused = L7;             ! Confuse for 'n' units
      inc( L5, L7 );                 ! Accumulate experience..
      if L5 > L8 goto DCSPEXIT;      ! Stop when total of L8 points used
    endif;
  endfor;  
  goto DCSPEXIT;

:M2_SCARE     ! Scares monsters                        
  S0 = "scared";
  foreach npc do
    L7 = min( npc.hp, random(L6) );  ! How much 'fright' to this one monster?
    if L7 > 0 and npc.scared = 0 then
      frame(npc.x, npc.y, SYS_SPLAT); wait(1); frame(npc.x, npc.y, SYS_SPLAT);
      inc(L9);
      npc.scared = L7;               ! Frighten for 'n' units
      inc( L5, L7 );                 ! Accumulate experience..
      if L5 > L8 goto DCSPEXIT;      ! Stop when total of L8 points used
    endif;
  endfor;  
  goto DCSPEXIT;

:M2_PARALYZE  ! Monster can't move                     
  S0 = "paralyzed";
  foreach npc do
    L7 = min( npc.hp, random(L6) );  ! How much paralysis to this one monster?
    if L7 > 0 and npc.paralyzed = 0 then
      frame(npc.x, npc.y, SYS_SPLAT); wait(1); frame(npc.x, npc.y, SYS_SPLAT);
      inc(L9);
      npc.paralyzed = L7;            ! Paralyze for 'n' units
      inc( L5, L7 );                 ! Accumulate experience..
      if L5 > L8 goto DCSPEXIT;      ! Stop when total of L8 points used
    endif;
  endfor;  
  goto DCSPEXIT;

:M2_RECHARGE  ! Recharge an ITEM                       pwr = 25, rng=1
  if object.type = RING or object.type = AMULET or object.type = STAFF then
    inc( object.charges, random(player.level)+1 );
    writeln( "The ", object.type, " now has ", object.charges, " charges." );
  else
    writeln( "The smell of rotten eggs fills the air.." );
  endif;
  STOP;

:M2_FLOAT     ! Remove an object's weight              pwr = 10, rng=1
  if object.weight < 255 then
    object.weight = object.weight / 2 + 1;
    writeln( "The ", object.type, " is now much lighter.." );
  else
    writeln( "It's didn't work.  The ", object.type, " is too heavy." );
  endif;
  STOP;

:M2_ANALYZE   ! Discover object's properties           pwr = 10, rng=1
  if npc.count then ! It's a character we cast this thing on..
    writeln( npc.name, ", ", npc.class, ", Lvl ", npc.level,
             ", AC ", npc.ac, ", HP ", npc.hp );
  else
    gosub ODETAIL;
  endif;
    STOP;

:M2_ZOOM      ! View the world.. 
  viewpcx( world );
  if success then
    pause;
  endif;
  paint( screen );
  STOP;


!
! Award experience points (if any)
!
:DCSPEXIT
  if L9 then
    write( L9, " foes were ", S0 );
    if L5 then  
      writeln( " for a total of +", L5, " experience!" );
      inc( player.exp, L5 );           ! Grant experience..
    else
      writeln( " With no effect" );
    endif;
  else
    writeln( "No effect.." );
  endif;
  STOP;

!
! SUBROUTINE: X_TARGET
!
! Selects a target to cast the spell on
!
:X_TARGET
  write( s0, " what:" );
  L3 = locate;               ! Identify an object or character to cast on !
  if failure then
    writeln( "nothing.." );
    STOP;
  endif;
  if L3 > L2 then
    writeln( "You must get closer.." );
    STOP;
  endif;
  if npc.count then ! It's a character, not an object..
    if npc.type = HOSTILE then
      writeln( npc.name );  ! Monster's class is type of terrain mobility !
    else
      writeln( npc.class ); ! Human, elf, dwarf, etc..       !
    endif;
    if L0 = DESTROY  or L0 = DUPLICATE or
       L0 = RECHARGE or L0 = FLOAT then
      writeln( "This spell only work's on objects!" );
      STOP;
    endif;
  else
    writeln( object.type );  ! Food, weapon, ring, etc..      !
  endif;
  return;

!
! SUBROUTINE: ODETAIL
!
! Display an object's detailed analysis
!
:ODETAIL
  write( "Name: ", object.name );
  write( ", Type: ", object.type );
  if object.type = FOOD or object.type = POTION  then
    if object.class then
      write( ", Class: ", object.class );
      if object.class <> CURE then
        write( ", Units: ", object.units );
      endif;
    endif;
  elsif object.type = WEAPON then
    write( "Class: ", object.class, 
           ", Hands: ", object.hands, 
           ", Range: ", object.range, 
           ", Damage: ", object.damage );
    if object.ammoneeded then
      write( ", Needs ammo type: ", object.ammo_type );
    endif;
  elsif object.type = AMMO then
    write( "Ammo Type: ", object.ammotype );
    if object.traptype then
      write( ", Poisoned" );
    endif;
    if object.damage then
      write( ", Extra Damage: ", object.damage );
    endif;
  elsif object.type = ARMOR or object.type = SHIELD then
    write( "Armor Class: ", object.ac );
    if object.cursed then
      write( " Cursed!" );
    endif;
  elsif object.type = AMULET or object.type = RING or object.type = GEMS then
    if object.class then
      write( "Class: ", object.class );
      write( ", Charges: ", object.charges );
      if object.class <> CURE then
        write( ", Units: ", object.units );
        if object.permanent then
          write( ", Permanent!" );
        else
          write( ", Temporary" );
        endif;
      endif;
      if object.cursed then
        write( ", Cursed!" );
      endif;
    endif;
  elsif object.type = SCROLL then
    write( "Class: ", object.class );
  elsif object.type = STAFF then
    write( "Class: ", object.class, ", Charges: ", object.charges );
  elsif object.type = CHEST then
    if object.locktype then
      write( "Locked!" );
      if object.traptype = 0 then
        write( ", no traps" );
      elsif object.traptype = 1 then
        write( ", poison trap" );
      else
        write( ", bomb damage: ", object.traptype );
      endif;
    endif;
! elsif object.type = KEYS     then
!   nothing special about it
! elsif object.type = BOOK     then
!   nothing special about it
! elsif object.type = GOLDSACK then
!   nothing special about it
! elsif object.type = TORCH    then
!   nothing special about it
! elsif object.type = LANTERN  then
!   nothing special about it
! elsif object.type = ROPE     then
!   nothing special about it
! elsif object.type = HOOKS    then
!   nothing special about it
! elsif object.type = MIRROR   then
!   nothing special about it
! elsif object.type = SIGN     then
!   nothing special about it
  elsif object.type = VEHICLE then
    write( "Class: ", object.class );
! else
!   user defined type?
  endif;
  if object.weight > 1 and object.weight < 256 then
    write( ", Weight: ", object.weight );
  endif;
  if object.count > 1 then
    write( ", Count: ", object.count );
  endif;
  return;

