Making all tiles in a range passable/impassable

Make games! Discuss those games here.

Moderators: Bob the Hamster, marionline, SDHawk

User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Making all tiles in a range passable/impassable

Post by crowtongue »

I'm implementing a "look" feature to my game from the menu. How it works is you select the option from the menu, it "pauses" the game and gives you control of a outlined box which can float around your current screen over top of any tile, and when you press spacebar it pops up a textbox describing the tile (or in some cases switches to another screen with a puzzle.)

I'm doing this by switching the "hero" to the box (or cursor as I call it) and storing the information about where the hero is in variables and replace the graphic with an appropriate slice. So far so good, I have this part working great.

Now I can use "suspend hero walls" and have the cursor able to wander anywhere, and I can even restrict camera movement with focus camera, but I'm looking for a way to make the cursor unable to move out of the screen.

I am able to go through the borders of the screen and make the last tiles impassable, but there are two problems I'm faced with.

1. I can't seem to make a loop without going through each row manually that will turn tiles to passable.

In python I would use a couple of "For n in range" lines with one nested in the other, but I'm kind of confused about how to achieve this here.

Code: Select all

for (j,1,16) do (
		for (k,1,8) do (
			write pass block(top_left_x, top_left_y,0)
			increment (top_left_y, 1)
		)
		increment(top_left_x,1)
		)
this is my initial attempt which doesn't work, I'd like to know how to improve it and also what I'm doing wrong.

2. Changing all of the tiles back after I'm done seems like a challenging idea. I had a couple of ideas I'd like some feedback on.
- One involves using an if function that would check the value of each map tile. If it isn't one of a certain bunch of values then it would be changed back to being impassable.
- The other is that while I am not using layers (I'm still pretty new to OHRRPGCE and my game is very simple visually) I am wondering if it would be easier to store all impassable objects on a separate layer and change each tile that isn't of the default "blank" tile value to passable/impassable as needed.

What are your thoughts?
Last edited by crowtongue on Wed May 01, 2013 6:01 am, edited 1 time in total.
Chronoboy
Slime Knight
Posts: 281
Joined: Tue Nov 30, 2010 6:01 am
Location: Canada

Re: Making all tiles in a range passable/impassable

Post by Chronoboy »

crowtongue wrote:2. Changing all of the tiles back after I'm done seems like a challenging idea. I had a couple of ideas I'd like some feedback on.
- One involves using an if function that would check the value of each map tile. If it isn't one of a certain bunch of values then it would be changed back to being impassable.
- The other is that while I am not using layers (I'm still pretty new to OHRRPGCE and my game is very simple visually) I am wondering if it would be easier to store all impassable objects on a separate layer and change each tile that isn't of the default "blank" tile value to passable/impassable as needed.

What are your thoughts?
Changing the tiles back is the easy part, look at the reset map state plotscript function:

Code: Select all

reset map state (whichdata)
Reloads original unaltered map data from the RPG file.

reset map state (mapstate:passmap)
TMC
Metal King Slime
Posts: 4101
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

(Also, if you make other modifications to the map which you want to preserve you can use savemapstate and loadmapstate.)

Firstly just answering your for loop question, pretty simple (a 15x9 rectangle):

Code: Select all

for (x, top left x, top left x + 14) do (
  for (y, top left y, top left y + 8) do (
    write pass block (x, y, 0)
  )
)
Also, note that you can write "top_left_y += 1" as in Python. And that the way you were doing it, you need to reset "top_left_y := actual_top_left_y" before the second for loop (for that matter, don't give your variables names that lie!)

But there's a complication: if you're in the middle of the map (and stationary) there will be half tiles visible along each edge of the screen, but if the map crops and you're at a corner, there will be full tiles, and 16x10 tiles will be totally on-screen.

So you might like to check the actual camera position in order to handle that case:

Code: Select all

rect width := 15
rect height := 9
if (camera pixel x, mod, 20 == 0) then (rect width += 1)
if (camera pixel y, mod, 20 == 0) then (rect height += 1)
Also if you have a wrap-around map, everything is way more complicated.

Other thoughts: I would be inclined to use an NPC instead of changing the hero walkabout sprite and having the player move that around (and use an on keypress script to move the NPC). To safely use the hero you have to disable random battles, disable obstruction (which forces you to disable all NPCs so they don't walk through each other, even if you didn't want to), disable harm tiles (by setting the flash and damage to 0), disable doors, disable camera panning, and maybe caterpillar too. Also if you're moving an NPC with an on-keypress script, then you can prevent the player from leaving the screen without having to paint walls around it.

The on-key-press script would look like:

Code: Select all

global variable(1, npc cursor)
plotscript, npc move onkeypress, begin
  if (npc cursor == 0) then (exit script)  # 'npc reference' always returns non-zero for a valid NPC
  if (npc is moving (npc cursor) == false) then (
    # I'm leaving implementation of "walk npc in bounds" to you; it should check the npc won't be leaving
    # the screen, and if so calls "walk npc"
    if (key is pressed (key:left)) then (walk npc in bounds(left))
    # Use elseif to prevent moving in two directions at once
    else if (key is pressed (key:right)) then (walk npc in bounds(right))
    else if (key is pressed (key:up)) then (walk npc in bounds(up))
    else if (key is pressed (key:down)) then (walk npc in bounds(down))
  )
end
Don't tell an NPC to move in two directions at once, it'll move diagonally (which probably means glitchy wall checking)
Last edited by TMC on Wed May 01, 2013 11:37 am, edited 3 times in total.
User avatar
Meowskivich
Blubber Bloat
Posts: 2199
Joined: Tue Mar 06, 2012 12:38 am
Location: Earth
Contact:

Post by Meowskivich »

couldn't you use the mouse for looking? just an idea.
dOn'T MiNd mE! i'M jUsT CoNtAgIoUs!!!
Play Orbs CCG: http://orbsccg.com/r/4r6x :V
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

Thank you for your suggestions.

Chronoboy - it's helpful to know about reset map data so thank you for that.

TMC - You're absolutely right. I had initially thought about using NPC's but mistakenly decided that programming the "walk" function would be more work then just using a blank hero.

I do have one question about "walk npc in bounds". Do I set that up as a script? I'm kind of unclear on if there is a function equivalent in plotscripting...

Meowskivich - Using the mouse seems like an intuitive idea, but I can only really find one other good way to use that in my game, and there are several where I can't use it at all... I'm not big on only sort of supporting something. Thanks for the suggestion though!
Last edited by crowtongue on Thu May 02, 2013 6:31 am, edited 2 times in total.
TMC
Metal King Slime
Posts: 4101
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Something like

Code: Select all


script, walk npc in bounds, direction, begin
  variable (x, y)
  x := npc x(npc cursor)
  y := npc y(npc cursor)
  switch (direction) do(
    case(left) x -= 1
    case(right) x += 1
    case(up) y -= 1
    case(down) y += 1
  )
  if &#40;camera pixel x <= x * 20 && camera pixel x + 320 >= x * 20 + 20
      && camera pixel y <= y * 20 && camera pixel y + 200 >= y * 20 + 20&#41; then &#40;
    walk npc &#40;npc cursor, direction, 1&#41;
  &#41;
end
Also, my bad, use npciswalking not npcismoving.

edit: fix script, which was mangled by the html parser
Last edited by TMC on Thu May 02, 2013 6:14 pm, edited 1 time in total.
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

Thank you. The dictionary talked about scripts, but didn't really mention how to call them, so I wasn't sure if that's what you were suggesting.

This works a lot better than what I had in mind.
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

any idea why it would say key: left is undefined?
User avatar
Bob the Hamster
Liquid Metal King Slime
Posts: 7460
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

crowtongue wrote:any idea why it would say key: left is undefined?
do you have:

Code: Select all

include,scancode.hsi
at the beginning of your script file?
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

derp. Nope I did not.

Thank you.
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

So the NPC spawns fine, but the problem I'm having is the hero moves, not the NPC. If I suspend player, neither of them move.

Is there a better way to suspend the hero? I also tried using "wait for key."

Code: Select all

plotscript, look, begin
	variable&#40;hero_posx, hero_posy&#41;
	
	
	hero_posx &#58;= hero X &#40;hero&#58;Hero&#41;  
	hero_posy &#58;= hero Y &#40;hero&#58;Hero&#41;
	npc cursor &#58;= NPC reference&#40;0,0&#41;
	create NPC&#40;npc cursor, hero_posx, hero_posy&#41;
	
	wait for key &#40;cancel key&#41;
	focus camera &#40;hero_posx,hero_posy&#41;
	
	
  	if &#40;npc cursor == 0&#41; then &#40;exit script&#41;  # 'npc reference' always returns non-zero for a valid NPC 
  	if &#40;npc is walking &#40;npc cursor&#41; == false&#41; then &#40; 
    		if &#40;key is pressed &#40;key&#58;Left&#41;&#41; then &#40;walk npc in bounds&#40;left&#41;&#41; 
    		# Use elseif to prevent moving in two directions at once 
    		else if &#40;key is pressed &#40;key&#58;Right&#41;&#41; then &#40;walk npc in bounds&#40;right&#41;&#41; 
    		else if &#40;key is pressed &#40;key&#58;Up&#41;&#41; then &#40;walk npc in bounds&#40;up&#41;&#41;
    		else if &#40;key is pressed &#40;key&#58;Down&#41;&#41; then &#40;walk npc in bounds&#40;down&#41;&#41; 
    	&#41;
	
	
end

script, walk npc in bounds, direction, begin 
  variable &#40;x, y&#41; 
  x &#58;= npc x&#40;npc cursor&#41; 
  y &#58;= npc y&#40;npc cursor&#41; 
  switch &#40;direction&#41; do&#40; 
    case&#40;left&#41; x -= 1 
    case&#40;right&#41; x += 1 
    case&#40;up&#41; y -= 1 
    case&#40;down&#41; y += 1 
  &#41; 
  if &#40;camera pixel x <x>= x * 20 + 20 
      && camera pixel y <y>= y * 20 + 20&#41; then &#40; 
    walk npc &#40;npc cursor, direction, 1&#41; 
  &#41; 
end 
User avatar
Bob the Hamster
Liquid Metal King Slime
Posts: 7460
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

You definitely want "suspend player"

I have added some comments to the script:

Code: Select all

plotscript, look, begin
   variable&#40;hero_posx, hero_posy&#41;
   
   
   hero_posx &#58;= hero X &#40;hero&#58;Hero&#41; 
   hero_posy &#58;= hero Y &#40;hero&#58;Hero&#41;
   npc cursor &#58;= NPC reference&#40;0,0&#41;
   create NPC&#40;npc cursor, hero_posx, hero_posy&#41;
   
   # The script pauses here and absolutely nothing happens until the cancel key is pressed
   wait for key &#40;cancel key&#41;
   focus camera &#40;hero_posx,hero_posy&#41;
   
   # This code here only gets checked for a single tick and then the script terminates
     if &#40;npc cursor == 0&#41; then &#40;exit script&#41;  # 'npc reference' always returns non-zero for a valid NPC
     if &#40;npc is walking &#40;npc cursor&#41; == false&#41; then &#40;
          if &#40;key is pressed &#40;key&#58;Left&#41;&#41; then &#40;walk npc in bounds&#40;left&#41;&#41;
          # Use elseif to prevent moving in two directions at once
          else if &#40;key is pressed &#40;key&#58;Right&#41;&#41; then &#40;walk npc in bounds&#40;right&#41;&#41;
          else if &#40;key is pressed &#40;key&#58;Up&#41;&#41; then &#40;walk npc in bounds&#40;up&#41;&#41;
          else if &#40;key is pressed &#40;key&#58;Down&#41;&#41; then &#40;walk npc in bounds&#40;down&#41;&#41;
       &#41;

end 
There are a couple different ways to check for the arrow keys on every tick, but the simplest is probably a "while" loop

Code: Select all

plotscript, look, begin
   variable&#40;hero_posx, hero_posy&#41;
   suspend player   
   
   hero_posx &#58;= hero X &#40;hero&#58;Hero&#41; 
   hero_posy &#58;= hero Y &#40;hero&#58;Hero&#41;
   npc cursor &#58;= NPC reference&#40;0,0&#41;
   create NPC&#40;npc cursor, hero_posx, hero_posy&#41;
   
   focus camera &#40;hero_posx,hero_posy&#41;
   
   while&#40;true&#41; do&#40;   
     if &#40;npc cursor == 0&#41; then &#40;exit script&#41;  # 'npc reference' always returns non-zero for a valid NPC
     if &#40;npc is walking &#40;npc cursor&#41; == false&#41; then &#40;
          if &#40;key is pressed &#40;key&#58;Left&#41;&#41; then &#40;walk npc in bounds&#40;left&#41;&#41;
          # Use elseif to prevent moving in two directions at once
          else if &#40;key is pressed &#40;key&#58;Right&#41;&#41; then &#40;walk npc in bounds&#40;right&#41;&#41;
          else if &#40;key is pressed &#40;key&#58;Up&#41;&#41; then &#40;walk npc in bounds&#40;up&#41;&#41;
          else if &#40;key is pressed &#40;key&#58;Down&#41;&#41; then &#40;walk npc in bounds&#40;down&#41;&#41;
       &#41;
     if &#40;key is pressed&#40;key&#58;ESC&#41; || key is pressed&#40;key&#58;Alt&#41;&#41; then&#40;
       break
     &#41;
     wait&#40;1&#41;
   &#41;
   resume player
end 
Last edited by Bob the Hamster on Thu May 02, 2013 8:44 pm, edited 1 time in total.
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

Fantastic! One other thing I had to chance was the

"if (npc cursor == 0) then (exit script)" part

The npc reference was indeed 0. There are still a couple changes I need to make (like disabling the main menu during this script, and deleting the NPC after it terminates) but other than that it now works perfectly. Thanks!
TMC
Metal King Slime
Posts: 4101
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

James didn't notice that you used "NPC reference" incorrectly. It returns a reference to an existing NPC, but you placed the "npc cursor := NPC reference(0,0) " line before the "create NPC" line. Either you should swap the order of those lines, or just write "npc cursor := create NPC(npc cursor, hero_posx, hero_posy)"

The reason the broken script worked anyway is because NPC reference returns 0 for a nonexistent NPC, which happens to be the ID number of the NPC. All NPC commands accept either an NPC reference or an ID number.
TMC
Metal King Slime
Posts: 4101
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

BTW, I just noticed two other bugs. "hero X (hero:Hero)" is wrong. The argument to heroX is a slot in the caterpillar party, not a hero ID (wow, the dictionary doesn't even document that). You should instead write "hero X (find hero(hero:Hero))". Again you probably didn't notice because hero:Hero is ID 0 and the leader of the party. Also there's no "camera follows hero (0)" at the end of the script, but you probably realised that.
Post Reply