Layered Walkabout / Visible Equippment / Could use a hand

Ask and answer questions about making games and related topics. Unrelated topics go in that other forum.

Moderators: marionline, SDHawk

User avatar
DWRL
Red Slime
Posts: 35
Joined: Wed Jan 15, 2020 2:26 am
Location: Germany
Contact:

Layered Walkabout / Visible Equippment / Could use a hand

Post by DWRL »

Hello,

I know I read about this somewhere, but can't seem to find it right now, so sorry for asking again an old question :zombie:

Basically, I want my player to be able to customize his hero, which would end up in having the player walkabout being comprised of 4 layers:

Basesprite (m/f)
Haircut
Clothes / Armour
Weapon

The basesprite and haircut would be chosen at start, clothes and weapon would be dependant on the equipped armour and weapon.
All layers are walkabouts sized the same (to keep things simpler).
(Btw, the character creation menu is not the problem, this works well ;) )

Right now I would change the walkabout to be my basesprite dependent on player choice, no sweat there.
Storing which walkabout has been chosen for the other layers is no problem either (e.g. global variables, for the quickest way, same for the palettes).

Additionally I use the three-frame walking script, and here my dilemma begins.
Right now, it is a tad above my level, but I feel there must be an 'easy' way to simply 'stamp' the other walkabouts atop...

Any suggestions?
Last edited by DWRL on Sat Mar 07, 2020 3:42 pm, edited 2 times in total.
User avatar
kylekrack
Liquid Metal Slime
Posts: 1240
Joined: Mon Jun 16, 2014 8:58 am
Location: USA
Contact:

Post by kylekrack »

The easy part is loading the additional layers. You can use load walkabout sprite() to make the sprite appear, and then set parent(handle, getHeroSlice(me)) to make it follow the hero's position. (You will likely need to adjust the specific positioning of the sprite with the set horiz/vert align/anchor.)

Animating the sprite is another story. You might be able to simplify it by setting each sprite's frame (hair, clothes, etc.) to the base sprite's frame every tick. I'm not sure what complications that may add, especially with 3 frame walking.
My pronouns are they/them
Ps. I love my wife
User avatar
Bird
Slime Knight
Posts: 227
Joined: Thu Jan 26, 2012 2:19 pm
Location: Germany

Post by Bird »

Oh! Witch2.rpg used it beautifully. Have a look.
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Actually, you should write "set parent(slice, getHeroSprite(me))" instead of "set parent(slice, getHeroSlice(me))", so that it will work if there is a foot-offset on the map or if the hero Z changes (eg riding an airship). Those change the position of the hero walkabout sprite relative to its parent, the walkabout container slice.

In order to make the overlays animate, you could write a script that every tick updates the overlaid sprites so that they have the same frame as the base sprite. You will want to make this script loop using timers instead of a while loop, so that it doesn't get paused if other scripts run:

Code: Select all

define constant(1, timer: overlays)
script, update overlays, begin
  set sprite frame (..., get sprite frame(get hero sprite(me)))

  set timer(timer:overlays, 0, 1, @update overlays)  # Run this script again next next
end
But there's a problem. The script doesn't run until the tick after the sprite frame has changed, due to the order in which things are run each frame. Try it and see whether it annoys you. (Increasing the frame rate might make it less noticable). It is possible to work around that problem, using something derived from this script, but it's quite complex.

If you use three-frame walking then you could also make the overlay sprites use more three frames too. If you don't then they will simply use two frames, but everything I wrote above is still true. Find the line in the three-frame script: "set spriteset number(slice, current spriteset)", and add some logic to change the spritesets of the overlay slices too.

The three-frame walking script is going to be obsolete very soon.
User avatar
DWRL
Red Slime
Posts: 35
Joined: Wed Jan 15, 2020 2:26 am
Location: Germany
Contact:

Post by DWRL »

@kylekrack: Thanks, you did kickstart me here :D
@bird: Wow. This is helpful, thank you!


Actually, my biggest problems at the moment are nomenclature and slices.
Once I replaced all variable names in the three-frame-walk script (e.g. 'current spriteset' to 'current bodySet') I had less problems.
Not knowing what words are keywords and which are functions/commands isn't exactly helpful, especially while trying to wrap my head around slices and learning the language :v:

(On a side question, is hamsterscript related to / derived from any other language? Right now I use python syntax highlighting, which makes the scripts by far more readable, but maybe there is something other my editor might know about?)

Right now my script works and puts everything nicely together, but seems to suddenly change the overlayed walkabout from #9 to #1 for some reason...
For the tick problem I just made the hero sprite set in the editor transparent and used the script for the body too. This way, it all was nicely in sync. The miniscule delay on turning around didn't bother me too much (yet).
The three-frame walking script is going to be obsolete very soon.
Might I ask if we talk about a palatable timeframe here, say two to three months or something like that?
If yes I am perfectly happy to let this rest for now 'till I can do without it, as I don't want to use unnecessary code, and guess it might lead to a cleaner implementation for the layers as well.

Oh, and a first look at the character creation menu :)

Image
Last edited by DWRL on Mon Mar 09, 2020 10:57 pm, edited 1 time in total.
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

That's a beautiful menu!

The syntax of HamsterSpeak is highly unusual; unfortunately you probably won't find any other language supported by your code editor of choice that is whitespace-insensitive. One solution is to write all names in your scripts in camelCase, like other languages. I wrote a HS mode for emacs myself. Syntax highlighting is very nice to have. There's a language definition for Notepad++ available, and I think some people in Discord also created their own for... VSCode? Sublime Text? I can't remember. Or you can use Hamster Whisper, which has a help key to show the documentation for the command under the cursor; very helpful.

Ah! Making the walkabout sprite (body sprite) invisible is a clever workaround.

I want to switch to the new sprite animation system this month, in time for the next release. That will then mean that I can expose the ability to add more frames to spritesets (it's already implemented but disabled, because the builtin animations wouldn't use the new frames, and thescript commands haven't been updated yet).

In fact, I also wanted to have builtin support for automatically changing the frames of walkabout overlay sprites, so that they match the direction/frame of the base sprite. It's a common thing to want to do. But that will take me longer; it might still be a long time away.
Last edited by TMC on Tue Mar 10, 2020 3:35 pm, edited 1 time in total.
User avatar
DWRL
Red Slime
Posts: 35
Joined: Wed Jan 15, 2020 2:26 am
Location: Germany
Contact:

Post by DWRL »

Here is the script as I currently have it, in case anybody might find it useful, or find something to improve :)

It needs the walkabout for the hero to be set to one of the same size as wished, but completely transparent.
The actual visible walkabout is 'PlayerBase', to avoid the visual inconsistency by the 1 tick delay mentioned by TMC.

The numbers in PlayerSettings directly translate to walkabout numbers or palette numbers.

Feel free to criticize, maybe I did something incredibly stupid here and haven't realized yet :v:

Code: Select all

define constant(1, timer: redrawDoll)

global variable, begin
	# Gender, 1; Hairstyle, 23, Haircolor: 4, Skintone: 5, Clothes: 67
	1, PlayerSettings
	# 0: Reset needed, 1: No reset needed
	2, ResetPlayerDoll
	# PlayerWalk, layerBase, PlayerHair, PlayerCloth
	3, PlayerBase
	4, PlayerHair
	# Not implemented yet
	#5, PlayerCloth
	end



plotscript, Update Doll, begin
	if(ResetPlayerDoll == 0) then, begin
		# TEMP, need to tie in to Character Creation
		if(PlayerSettings == 0) then, begin
			PlayerSettings := 020841399
			end
		
		# pGender:number of walkabout to be used as a base
		# pHairstyle: number of walkabout to be used as a hair.
		# pHaircolor: number of palette used for hair
		# pSkintone: number of palette used for skin
		# pClothes: number of palette used for clothes
		variable(pGender, pHairstyle, pHaircolor, pSkintone, pClothes, pVisCloth)
		pGender := PlayerSettings / 100000000
		pHairstyle := (PlayerSettings, mod, 100000000) / 10000000
		pHaircolor := (PlayerSettings, mod, 10000000) / 100000
		pSkintone := (PlayerSettings, mod, 100000) / 10000
		pClothes := (PlayerSettings, mod, 10000) / 100
		# Not implemented yet
		#pVisCloth := (PlayerSettings, mod, 100)
		
		if&#40;PlayerBase <> 0&#41; then &#40;free slice&#40;PlayerBase&#41;&#41;
		if&#40;PlayerHair <> 0&#41; then &#40;free slice&#40;PlayerHair&#41;&#41;
		
		# &#40;+ 7 if female, offset to female hair graphics &#40;i.e. walkabouts 2-8 for males, 9-15 for females&#41;
		if&#40;pGender == 1&#41; then &#40;pHairstyle &#58;= pHairstyle + 7&#41;

		PlayerBase &#58;= load walkabout sprite&#40;pGender, pSkintone&#41;
		PlayerHair &#58;= load walkabout sprite&#40;pHairstyle, pHaircolor&#41;

		set parent&#40;PlayerBase, getHeroSprite&#40;me&#41;&#41;
		set parent&#40;PlayerHair, getHeroSprite&#40;me&#41;&#41;
		
		ResetPlayerDoll &#58;= 1
		end


	else if&#40;ResetPlayerDoll == 1&#41; then, begin
		variable&#40;frame&#41;
		frame &#58;= get sprite frame &#40;lookup slice&#40;sl&#58;walkabout sprite component, get hero slice&#40;me&#41;&#41;&#41;
		set sprite frame &#40;PlayerBase, frame&#41;
		set sprite frame &#40;PlayerHair, frame&#41;
		end
		
	set timer&#40;timer&#58;redrawDoll, 0, 1, @Update Doll&#41;  # Run this script again next next 
	end
Last edited by DWRL on Sat Jun 13, 2020 12:57 pm, edited 3 times in total.
User avatar
Bird
Slime Knight
Posts: 227
Joined: Thu Jan 26, 2012 2:19 pm
Location: Germany

Post by Bird »

The power of MATH! Beautiful! Kids, you have to pay attention in school, if you want to compress the informations in one variable instead of six.

Although it only works because the OHR doesn't use floating point numbers... else there would be problems at rounding, I think. Code 020341399 will result in hairstyle #20 as intended, but 020841399 would result in 20,8 which would be #21, if rounded.
User avatar
DWRL
Red Slime
Posts: 35
Joined: Wed Jan 15, 2020 2:26 am
Location: Germany
Contact:

Post by DWRL »

To be honest, it wouldn't have occured to me if I hadn't seen it in the three-frame walking script :angel:
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

By coincidence (I think) Prifurin posted a script a couple days ago to store a date and time like 202006041859 in a single value, but ran into the problem that HamsterSpeak values are capped at 2.147 billion. So you only get 9 decimal digits, and need to use two variables for that.

Also worth mentioning that in HS you can put spaces in numbers, like "PlayerSettings := 0 20 84 13 99 ". Most useful for writing 100 000 000 instead of 100000000.

BTW, you can replace

Code: Select all

lookup slice&#40;sl&#58;walkabout sprite component, get hero slice&#40;me&#41;&#41;
with "get hero sprite(me)"
User avatar
kylekrack
Liquid Metal Slime
Posts: 1240
Joined: Mon Jun 16, 2014 8:58 am
Location: USA
Contact:

Post by kylekrack »

It would be possible to store those values in a string instead of a variable. If you had 0$="0 20 84 13 99" (which would likely be created by using "append number(0, value)" for each player settings value in most cases) it could be as long as you want. Reading it would be complicated, though, since there's no arrays or string split function.
My pronouns are they/them
Ps. I love my wife
User avatar
Bird
Slime Knight
Posts: 227
Joined: Thu Jan 26, 2012 2:19 pm
Location: Germany

Post by Bird »

TMC wrote:By coincidence (I think) Prifurin posted a script a couple days ago to store a date and time like 202006041859 in a single value, but ran into the problem that HamsterSpeak values are capped at 2.147 billion. So you only get 9 decimal digits, and need to use two variables for that.
If we would cut the year number to the last two digits (so "19" instead of "2019"), it is possible to calculate everything back to seconds and currently have a 9-digit-number as a result. That would work until 2067, then the variable would grow farther than the 2,147 billion limit. If we declare 2020 as year 0, the terrible end can be postponed about 20 years to 2087. However if we could abandon the tiny seconds, we would be well set for the future.
kylekrack wrote:It would be possible to store those values in a string instead of a variable. If you had 0$="0 20 84 13 99" (which would likely be created by using "append number(0, value)" for each player settings value in most cases) it could be as long as you want. Reading it would be complicated, though, since there's no arrays or string split function.
How was it with strings, that can be stored after the game was quit? They needed to be exported to a file, right? Someone did this somewhere...
User avatar
DWRL
Red Slime
Posts: 35
Joined: Wed Jan 15, 2020 2:26 am
Location: Germany
Contact:

Post by DWRL »

Bird wrote:(...)Although it only works because the OHR doesn't use floating point numbers... else there would be problems at rounding, I think.(...)
I guess in that case we'd need (and might have) a floor operator.
Bird wrote:(...)we would be well set for the future.
But think of those video game archaeologists in the year 100000 and beyond. What will they do? :devil:
TMC wrote:By coincidence (I think) Prifurin posted a script a couple days ago to store a date and time like 202006041859 in a single value, but ran into the problem that HamsterSpeak values are capped at 2.147 billion. So you only get 9 decimal digits, and need to use two variables for that.
Sometimes ideas are just in the air. I was just dumbfounded by the line
"extradata := current frame + current spriteset * 10 + base spriteset * 100 000"
When I finally figured it out, it was quite clever. I am still far too used to lists and dictionaries, so it would have taken quite some time for me to realign my thinking into something like that.
TMC wrote:Also worth mentioning that in HS you can put spaces in numbers, like "PlayerSettings := 0 20 84 13 99 ". Most useful for writing 100 000 000 instead of 100000000.

BTW, you can replace

Code: Select all

lookup slice&#40;sl&#58;walkabout sprite component, get hero slice&#40;me&#41;&#41;
with "get hero sprite(me)"
Far better, thanks :)


-
Update,
I had problems with loading save states, I guess my grasp of what the OHR does and doesn't isn't as firm as it could be.
(Seems the globals stored the slice handles just fine, only the slices themselves were quite nonexistent after saving and loading the game... XD)

Now the script is two-tiered, one does put 'Setup Doll' as the autorun script for the map, and the magic happens ;)
(Not cleaned up, straight out of the editor, so just excuse the many hashes. My editor makes them red, so it is easier navigating the script file.)

Code: Select all

# SCRIPT
# Show the Command menu and change selection
##########################################
plotscript, Setup Doll, begin
	# TEMP, need to tie in to Character Creation
	if&#40;PlayerSettings == 0&#41; then, begin
		PlayerSettings &#58;= 0 2 08 4 13 99
		end
		
	variable&#40;pGender, pHairstyle, pHaircolor, pSkintone, pClothes, pVisCloth&#41;
	pGender &#58;= PlayerSettings / 100000000
	pHairstyle &#58;= &#40;PlayerSettings, mod, 100000000&#41; / 10000000
	pHaircolor &#58;= &#40;PlayerSettings, mod, 10000000&#41; / 100000
	pSkintone &#58;= &#40;PlayerSettings, mod, 100000&#41; / 10000
	pClothes &#58;= &#40;PlayerSettings, mod, 10000&#41; / 100
	# Not implemented yet
	#pVisCloth &#58;= &#40;PlayerSettings, mod, 100&#41;
		
	pHairstyle &#58;= pHairstyle + 2
	if&#40;pGender == 1&#41; then &#40;pHairstyle &#58;= pHairstyle + 7&#41;

	PlayerBase &#58;= load walkabout sprite&#40;pGender, pSkintone&#41;
	PlayerHair &#58;= load walkabout sprite&#40;pHairstyle, pHaircolor&#41;

	set parent&#40;PlayerBase, getHeroSprite&#40;me&#41;&#41;
	set parent&#40;PlayerHair, getHeroSprite&#40;me&#41;&#41;
		
		
	ResetPlayerDoll &#58;= 1
	Update Doll

	end
	##########################################



# SCRIPT
# Show the Command menu and change selection
##########################################
plotscript, Update Doll, begin
	if&#40;ResetPlayerDoll == 0&#41; then, begin
		Setup Doll
		end
	else, begin
		variable&#40;frame&#41;
		frame &#58;= get sprite frame &#40;getHeroSprite&#40;me&#41;&#41;
		set sprite frame &#40;PlayerBase, frame&#41;
		set sprite frame &#40;PlayerHair, frame&#41;
		end
		

	set timer&#40;timer&#58;redrawDoll, 0, 1, @Update Doll&#41;  # Run this script again next next 
	end
	##########################################
User avatar
Spoonweaver
Liquid Metal King Slime
Posts: 6461
Joined: Mon Dec 08, 2008 7:07 am
Contact:

Post by Spoonweaver »

Why does your script convert indvidual choices into 1 variable and then convert them back again?
why not just have the editor or equip screen set pGender pHairstyle pHaircolor pSkintone and pClothes seperately and leave them seperate in stead of smashing them into PlayerSettings?
Am I missing something?
User avatar
DWRL
Red Slime
Posts: 35
Joined: Wed Jan 15, 2020 2:26 am
Location: Germany
Contact:

Post by DWRL »

Spoonweaver wrote:Why does your script convert indvidual choices into 1 variable and then convert them back again?
why not just have the editor or equip screen set pGender pHairstyle pHaircolor pSkintone and pClothes seperately and leave them seperate in stead of smashing them into PlayerSettings?
Am I missing something?
This way it can all be stored in one global variable.
Post Reply