Post new topic    
Metal Slime
Send private message
Timestream Saga - Arcadia Incident Report (Demo Version) 
 PostThu Apr 30, 2009 6:21 am
Send private message Reply with quote
A game approaches! Command?

This game is still only basically a demo. It has no ending, leaving off somewhere in the middle of the "4th" mission. I am hoping the prospect of playing something unique and new will overcome this limitation.
Every day's a sale. Every sale a win.
Metal Slime
Send private message
OH GOD A ZELDA SCRIPT 
 PostTue May 05, 2009 10:25 pm
Send private message Reply with quote
There's an issue with this script regarding wall collision checking - namely that there isn't any. I'd like to fix that, but before then, I'll post what is essentially the meat and bones of Arcadia Incident Report's main plotscript. So here goes:

Code:
script,lifebar,begin
 FOE10HP := 3
 FOE11HP := 3
 FOE12HP := 3
 FOE13HP := 3
 FOE14HP := 3
 FOE15HP := 3
 FOE16HP := 3
 FOE17HP := 3
 FOE18HP := 3
 FOE19HP := 3
 set tag (tag:safe,off)


This sequence starts the script up and sets every enemy on the map to have 3 HP. It also turns a tag off, just because.

Code:

 if (checktag(tag:safe) == on) then (show no value)
 wait (1)
 while (checktag (tag:safe) == off) do (


This segment is mainly redundant but is necessery when combined with another script. Mainly it causes the game to NOT display your health when you're safe. It also sets up the loop and the meat of the script when you aren't safe...

Code:

 (
 set hero speed (me,0)


   if (key is pressed (key:Pageup)) then (set hero direction (me,right), put hero (me,hero-x +

hero-speed, hero-y -- hero-speed))

    if (key is pressed (key:right)) then (set hero direction (me,right),put hero (me,hero-x +

hero-speed,hero-y))

if (key is pressed (key:Pagedown)) then (set hero direction (me,right), put hero (me,hero-x + hero-speed,

hero-y + hero-speed))

if (key is pressed (key:Home)) then (set hero direction (me,left), put hero (me,hero-x -- hero-speed, hero-y

-- hero-speed))

if (key is pressed (key:left)) then (set hero direction (me,left),put hero (me,hero-x -- hero-speed,hero-y))

if (key is pressed (key:End)) then (set hero direction (me,left), put hero (me,hero-x -- hero-speed, hero-y

+ hero-speed))

if (key is pressed (key:up)) then (set hero direction (me,up), put hero (me,hero-x,hero-y -- hero-speed))
    
if (key is pressed (key:down)) then (set hero direction (me,down), put hero (me,hero-x,hero-y + hero-speed))
)


Craziness here. Firstly, setting the hero's speed to ZERO all but disables the player controlled input for walking with the default OHR keys. Their walking speed is reset when entering a "safe" zone, thus creating the illusion of total control in and out of battles.

hero-x is the hero's X position in pixels.
hero-y is the hero's Y position in pixels too.
hero-speed is the hero's innate "speed" stat, 1,2,4,5,10,or 20. By default this value is 4, but equipment can change this stat (and must ONLY change it to one of the listed values!!).

The script then runs a case by case basis for movement by checking keys. You'll note that it's presently set up to use a numpad for walking, and that moving on a "diagonal" sets you to face either the left or right aspect of that diagonal. There's no real reason to do that, aside from playable area essentially being all but a widescreen resolution at 16x9 tiles, and longstanding game tradition. Eventually the extra "diagonals" will get rewritten to simply check if two keys are being pressed at once, but not for now.

The basic gist is that if a directional key is pressed, the hero is "moved" by it's "speed" in pixels in that direction.

An astute observer of OHRRPGCE plotscripting will very quickly realize that there is NO checking for wall collision at this point. Mostly this is an artifact of the code's original tile-based movement. I would like to fix this with a VERY simple check. Ideally, this would be done by checking whether the TILES around the hero's sprite have an "A" passability bitset, and not checking the actual walls themselves - then simply disallow moving the hero sprite into the boundaries of that tile. I've a feeling this would be faster than checking each individual wall passability, but I could be wrong - and I have no idea on how to do either.


Code:

 if (checktag(tag:safe) == on) then (show no value)
 KYLEHP := get hero stat(hero:Kyle,stat:HP,current stat)
 hero-x := hero pixel x(me)
 hero-y := hero pixel y(me)
 hero-speed := get hero stat(hero:Kyle,stat:Speed,current stat)
 show value (KYLEHP)


Again, the redundant check for hero HP. For some reason, this step has to appear multiple times. It is also here that the various variables are defined and continuously updated. Player HP is displayed in real time, as we will shortly see.

Code:

  if ( KYLEHP >= (100) ) then ( KYLEHP := 99 )
 if (KYLEHP >= (50)) then (  Alter NPC (0,NPCstat:picture,32),Alter NPC (9,NPCstat:picture,35))
 if (KYLEHP <= (49)) then (  Alter NPC (0,NPCstat:picture,33),Alter NPC (9,NPCstat:picture,36))
 if (KYLEHP <= (25)) then (  Alter NPC (0,NPCstat:picture,34),Alter NPC (9,NPCstat:picture,37))
 if (get hero stat (me,stat:MP,current stat) == (3)) then (  Set NPC direction (0,up))
 if (get hero stat (me,stat:MP,current stat) == (2)) then (  Set NPC direction (0,right))
 if (get hero stat (me,stat:MP,current stat) == (1)) then (  Set NPC direction (0,down))
 if (get hero stat (me,stat:MP,current stat) == (0)) then (  Set NPC direction (0,left))
 if (KYLEHP <= (0)) then ( KYLEHP := 99 , death , exit script )
 delete item (item:TIMER,1)


These steps quickly check the hero's hp and mp, then alter a pair of NPCs to visually display changes in the hero's status. This is mostly the "color scale" warning used throughout Arcadia Incident of blue-yellow-red. MP is a simpler check of simply rotating one NPC roundabout to display how many grenades/flashbangs the player has left. It also starts the death script if the player's HP ever drops below zero. Finally, it removes ONE item called "timer", which is integral to how often enemies can attack you (it's the period of invincibility you get, and you CAN remove it!)

Code:

#process FOE hp
 if (FOE10HP == 3) then (set NPC direction (20,up))
 if (FOE10HP == 2) then (set NPC direction (20,right))
 if (FOE10HP == 1) then (set NPC direction (20,down))
 if (FOE10HP <= 0) then (destroy NPC (20),FOE10,FOE10HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))


This sequence will get repeated no more and no less than ten times with different NPCs. It tracks how much health a given foe has, and alters its own lifebar graphic accordingly. Once the NPC drops to zero hp or less, it kills the graphic, runs the foe self destruction script, gives you a little money, experience, and makes this particular enemy do one of three scream sound effects. Nifty. Fast, too.

Code:

 if (FOE11HP == 3) then (set NPC direction (21,up))
 if (FOE11HP == 2) then (set NPC direction (21,right))
 if (FOE11HP == 1) then (set NPC direction (21,down))
 if (FOE11HP <= 0) then (destroy NPC (21),FOE11,FOE11HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))
 if (FOE12HP == 3) then (set NPC direction (22,up))
 if (FOE12HP == 2) then (set NPC direction (22,right))
 if (FOE12HP == 1) then (set NPC direction (22,down))
 if (FOE12HP <= 0) then (destroy NPC (22),FOE12,FOE12HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))
 if (FOE13HP == 3) then (set NPC direction (23,up))
 if (FOE13HP == 2) then (set NPC direction (23,right))
 if (FOE13HP == 1) then (set NPC direction (23,down))
 if (FOE13HP <= 0) then (destroy NPC (23),FOE13,FOE13HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))
 if (FOE14HP == 3) then (set NPC direction (24,up))
 if (FOE14HP == 2) then (set NPC direction (24,right))
 if (FOE14HP == 1) then (set NPC direction (24,down))
 if (FOE14HP <= 0) then (destroy NPC (24),FOE14,FOE14HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))
 if (FOE15HP == 3) then (set NPC direction (25,up))
 if (FOE15HP == 2) then (set NPC direction (25,right))
 if (FOE15HP == 1) then (set NPC direction (25,down))
 if (FOE15HP <= 0) then (destroy NPC (25),FOE15,FOE15HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))
 if (FOE16HP == 3) then (set NPC direction (26,up))
 if (FOE16HP == 2) then (set NPC direction (26,right))
 if (FOE16HP == 1) then (set NPC direction (26,down))
 if (FOE16HP <= 0) then (destroy NPC (26),FOE16,FOE16HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))
 if (FOE17HP == 3) then (set NPC direction (27,up))
 if (FOE17HP == 2) then (set NPC direction (27,right))
 if (FOE17HP == 1) then (set NPC direction (27,down))
 if (FOE17HP <= 0) then (destroy NPC (27),FOE17,FOE17HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))
 if (FOE18HP == 3) then (set NPC direction (28,up))
 if (FOE18HP == 2) then (set NPC direction (28,right))
 if (FOE18HP == 1) then (set NPC direction (28,down))
 if (FOE18HP <= 0) then (destroy NPC (28),FOE18,FOE18HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))
 if (FOE19HP == 3) then (set NPC direction (29,up))
 if (FOE19HP == 2) then (set NPC direction (29,right))
 if (FOE19HP == 1) then (set NPC direction (29,down))
 if (FOE19HP <= 0) then (destroy NPC (29),FOE19,FOE19HP := 3
  get money (2)
  play sound (random (13,15),false,true)
  give experience (hero:kyle,1))


Told you it would be repeated often.


This whole bit below just looks to see if the hero is invincible, THEN cycles through the enemy collision detection

Code:

if ((inventory (6))<=0) then (


This checks to see if you have any of those "Timer" items, indicating your invincibility. If you have none, the game will check if you're within range of an enemy.

Code:

     if ((hero-x) -- npc pixel x(10) << 30 &&
          npc pixel x(10) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(10) << 30 &&
          npc pixel y(10) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))


If the enemy is even remotely close to the player, it'll try and attack them. This segment gets repeated a LOT.

Code:

     if ((hero-x) -- npc pixel x(11) << 30 &&
          npc pixel x(11) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(11) << 30 &&
          npc pixel y(11) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))

     if ((hero-x) -- npc pixel x(12) << 30 &&
          npc pixel x(12) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(12) << 30 &&
          npc pixel y(12) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))

     if ((hero-x) -- npc pixel x(13) << 30 &&
          npc pixel x(13) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(13) << 30 &&
          npc pixel y(13) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))

     if ((hero-x) -- npc pixel x(14) << 30 &&
          npc pixel x(14) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(14) << 30 &&
          npc pixel y(14) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))

     if ((hero-x) -- npc pixel x(15) << 30 &&
          npc pixel x(15) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(15) << 30 &&
          npc pixel y(15) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))

     if ((hero-x) -- npc pixel x(16) << 30 &&
          npc pixel x(16) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(16) << 30 &&
          npc pixel y(16) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))

     if ((hero-x) -- npc pixel x(17) << 30 &&
          npc pixel x(17) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(17) << 30 &&
          npc pixel y(17) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))

     if ((hero-x) -- npc pixel x(18) << 30 &&
          npc pixel x(18) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(18) << 30 &&
          npc pixel y(18) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))

     if ((hero-x) -- npc pixel x(19) << 30 &&
          npc pixel x(19) -- (hero-x) << 30 &&
          (hero-y) -- npc pixel y(19) << 30 &&
          npc pixel y(19) -- (hero-y) << 30 ) then (if (checktag (tag:INVINCIBLE) == off ) then (attacked))

   )


See?

Code:

    if   ((NPC Y (10) == Hero Y (me)) or (NPC X (10) == Hero X (me))) then, begin
   Alter NPC (10,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (10,NPCstat:move type,NPCmovetype:wander)
    end


This is the enemy "AI", and checks their movements. The basic gist is that if the hero's X or Y coordinates match a given NPC's, then the NPC behavior will change accordingly. If you're in the same x or y axis, this particular foe will try and chase you (as in it's spotted you), but if neither condition is met it'll simply wander around searching for the player. Different enemies can be configured to have different behaviour protocols depending on their x/y position, OR if you're clever they can also have a third or fourth set of behaviors that kick in when they're within a certain DISTANCE of the player. I'd like to cover this at a later date, but for now, this enemy behavior is adequate for a weak foe.

Also this segment will conditionally be repeated, albeit differently for each enemy possible.

Code:

    if   ((NPC Y (11) == Hero Y (me)) or (NPC X (11) == Hero X (me))) then, begin
   Alter NPC (11,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (11,NPCstat:move type,NPCmovetype:wander)
    end
    if   ((NPC Y (12) == Hero Y (me)) or (NPC X (12) == Hero X (me))) then, begin
   Alter NPC (12,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (12,NPCstat:move type,NPCmovetype:wander)
    end
    if   ((NPC Y (13) == Hero Y (me)) or (NPC X (13) == Hero X (me))) then, begin
   Alter NPC (13,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (13,NPCstat:move type,NPCmovetype:wander)
    end
    if   ((NPC Y (14) == Hero Y (me)) or (NPC X (14) == Hero X (me))) then, begin
   Alter NPC (14,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (14,NPCstat:move type,NPCmovetype:wander)
    end
    if   ((NPC Y (15) == Hero Y (me)) or (NPC X (15) == Hero X (me))) then, begin
   Alter NPC (15,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (15,NPCstat:move type,NPCmovetype:wander)
    end
    if   ((NPC Y (16) == Hero Y (me)) or (NPC X (16) == Hero X (me))) then, begin
   Alter NPC (16,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (16,NPCstat:move type,NPCmovetype:wander)
    end
    if   ((NPC Y (17) == Hero Y (me)) or (NPC X (17) == Hero X (me))) then, begin
   Alter NPC (17,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (17,NPCstat:move type,NPCmovetype:wander)
    end
    if   ((NPC Y (18) == Hero Y (me)) or (NPC X (18) == Hero X (me))) then, begin
   Alter NPC (18,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (18,NPCstat:move type,NPCmovetype:wander)
    end
    if   ((NPC Y (19) == Hero Y (me)) or (NPC X (19) == Hero X (me))) then, begin
   Alter NPC (19,NPCstat:move type,NPCmovetype:chaseyou)
    end, else, begin
   Alter NPC (19,NPCstat:move type,NPCmovetype:wander)
    end


See? Thankfully it's almost over.

Code:

 wait (1)
 )
 exit script
end


And the end of the script. It does the ONE required wait for a loop, then keeps repeating UNTIL the "safe" tag is inevitably activated, then it terminates immediately.

Any hints for how to check "walls" and/or NPC passability would be wonderful.
Every day's a sale. Every sale a win.
Display posts from previous: