• Welcome to Smashboards, the world's largest Super Smash Brothers community! Over 250,000 Smash Bros. fans from around the world have come to discuss these great games in over 19 million posts!

    You are currently viewing our boards as a visitor. Click here to sign up right now and start on your path in the Smash community!

Completed Tech Grab

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
This code causes players that grab each other at the same time to immediately break out. It was requested by Stormghetti Stormghetti , who was looking for something similar to the new grab tech in Smash Ultimate.

It comes with a few parameters that can be adjusted from the edit menu in Melee Code Manager. Feel free to make any suggestions.


Code:
-==-

Tech Grabs - 1.0
Characters that grab eachother at the same time will cancel out.
Parameters can be adjusted from <TGrab_params>
[Punkline]

<TGrab_params>
4E800021
# the following are user parameters:

3FCCCCCD  # animation speed (floating point, 1.6 by default )

03        # flags: +1 = enable, +2 = enforceFacing, +4 = enforceHitbox, +8 = grapple option
000000    # padding

00000000  # FX flagfield, bool variables

# the following is used to create a custom aura, and can be changed:
58000000 00000052 00004040  # SFX1
58000000 000000F3 00005040  # SFX2
54000000 03F90000 00000000 00000000 00000000  # GFX
36000050 FF8000FF  # set light
3C000012 FF800020  # set light blend rate
48000000 FFFFFF00  # set overlay
4C000012 FFFFFF90  # set overlay blend rate
2C000012  # wait 18 frames
44000000  # kill light
4C000018 FFFFFF00  # set overlay blend rate
2C000018  # wait
30000000  # kill overlay and light
28000000  # terminate aura

# end of parameters

1.02 ------ 800da9d8 --- 4bfa31f5 -> Branch
80030010 2C0000D4 2C8000D6 4C423382 9001001C 40A2009C
bl <TGrab_params>
7D0802A6 88080004 7C001120 83E31A58 80BF002C 409F0080 409E0014 80C30030 80A5002C 7C062800 4182006C 40BD0010 88032219 70050010 41A2005C 41BC0010 3FE0800D 63FFBD10 93E1001C 80EDC18C 80C70020 38E00020 80A80008 38000000 7C001120 34E7FFFF 2C860000 4C423382 4182001C 7C1A3000 80C60008 4082FFE8 3D208000 7D203C30 7CA50378 90A80008 C0228044
bl 0x8007DBCC
00000000
1.02 ------ 800daa28 --- bb410030 -> Branch
83E1001C 2C1F0000 40A00008 93FC21A0 BB410030 00000000
1.02 ------ 800db980 --- 881f234c -> Branch
bl <TGrab_params>
7C6802A6 80A30008 38000000 2C050000 41A20098 7C001120 80CDC18C 90030008 809F1A58 80C60020 38E00020 34E7FFFF 2C860000 4C423382 41820070 7C1E3000 80C60008 4082FFE8 3D208000 7D203C30 7CA90039 41A20054 8164002C 39400001 3983000C 38000000 915F0430 900B0408 919F0410 914B0430 901F0408 918B0410 C0230000 C0429A20 EC2100B2 807F1A58
bl 0x8006f190
bl <TGrab_params>
7C6802A6 C0230000 7FC3F378
bl 0x8006f190
881F234C 00000000
Code:
-==-
!
ASM - Tech Grabs - 1.0
Characters that grab eachother at the same time will cancel out.
Parameters can be adjusted from <TGrab_params>
[Punkline]

<TGrab_params>
blrl
# User options:
.set enabled,        1
# Tech only occurs if code is enabled (can be toggled during game)

.set enforceFacing,  1
# Tech only occurs if players are facing towards eachother

.set enforceHitbox,  0
# Tech only occurs if both grab hitboxes are out (VERY tight windows)

.set grapple,        0
# Tech occurs after grapple action is completed (see Link/Samus)

_0x00:
.float 1.6
# animation speed of CatchCut and CaptureCut

_0x04:
.byte (enabled<<0)+(enforceFacing<<1)+(enforceHitbox<<2)+(grapple<<3)
.align 2

_0x08:
.long 0
# 32-bit array of bools,
# used to keep track of up to 32 player GObjs requiring post-action effects

_0x0C:
_custom_player_aura:
# frame 0:
.long 0x58000000, 0x00000052, 0x00004040 # SFX1
.long 0x58000000, 0x000000F3, 0x00005040 # SFX2
.long 0x54000000, 0x03F90000, 0x00000000, 0x00000000, 0x00000000 # GFX1
.long 0x36000050, 0xFF8000FF # set additive light
.long 0x3C000012, 0xFF800020 # blend light
.long 0x48000000, 0xFFFFFF00 # set overlay
.long 0x4C000012, 0xFFFFFF90 # blend overlay
.long 0x2C000012 # wait out blends
# frame 18:
.long 0x44000000 # kill light
.long 0x4C000018, 0xFFFFFF00 # fade overlay
.long 0x2C000018 # wait for fade
# frame 50:
.long 0x30000000 # kill overlay/lights
.long 0x28000000 # terminate aura




1.02 ------ 800da9d8 --- 4bfa31f5 -> Branch
# bl    ->0x8007DBCC
# just as breakout timer is being assigned as argument for call

# r3 = breakout assignee's player data
# r4 = unk int argument (0 immediate)
# f1 = breakout timer to assign
# r31 is safe to use

# offsets
.set xOptions,    0x4
.set xFXflags,    0x8
.set xFacing,     0x2C
.set xFacingPrev, 0x30
.set xGrabber,    0x1A58
.set xAnimIntr,   0x21A0

# registers
.set rParams,   8
.set rNext,     6
.set rCount,    7
.set rFlags,    5
.set rPData,    3
.set rPlayer,   26
.set rGrabber,  31

# bools
.set bEnabled,     31
.set bCheckFacing, 30
.set bCheckHitbox, 29
.set bGrapple,     28

# other
.set Catch,     0xD4  # ASIDs
.set CatchDash, 0xD6
.set breakoutAnimInterrupt, 0x800dbd10

lwz r0, 0x10(rPData)
cmpwi r0, Catch
cmpwi cr1, r0, CatchDash
cror  eq, eq, eq+4
stw  r0, 0x1C(sp)
bne+ _return
# check for action state
# this will be the most likely to be false, so it's checked first

bl <TGrab_params>
mflr rParams
lbz r0, xOptions(rParams)
mtcrf 0b000001, r0
lwz rGrabber, xGrabber(rPData)
lwz r5, 0x2C(rGrabber)
# rParams and rGrabber have been loaded
# cr7 contains option bools
# r5 holds rGrabber player data
# r3 holds rPlayer player data

_check_enabled:
bf- bEnabled, _return
# if disabled, then don't do anything

_check_facing:
bf- bCheckFacing, _check_hitbox
  lwz r6, xFacingPrev(rPData)
  lwz r5, xFacing(r5)
  cmpw r6, r5
  beq- _return
  # if checking facing, return when players are facing the same direction

_check_hitbox:
bf+ bCheckHitbox, _check_grapple
  lbz r0, 0x2219(rPData)
  andi. r5, r0, 0x10
  beq+ _return
  # if checking for hitbox, only tech if both player's hitboxes are out


_check_grapple:
bt+ bGrapple, _setup_loop
  lis r31, breakoutAnimInterrupt@h
  ori r31, r31, breakoutAnimInterrupt@l
  stw r31, 0x1C(sp)
  # player will not wait for catch to pull player towards grabber

_setup_loop:
lwz r7, -0x3e74(r13)
lwz rNext, 0x20(r7)
li  rCount, 32
lwz rFlags, xFXflags(rParams)
li r0, 0
mtcrf 0b00000001, r0
# registers are ready for loop
# cr7 is cleared

_for_each_player_GObj:
  subic. rCount, rCount, 1
  cmpwi  cr1, rNext, 0
  cror   eq, eq, eq+4
  beq- _exit_loop
  # termination conditions

  cmpw rPlayer, rNext
  lwz  rNext, 0x8(rNext)
  bne+ _for_each_player_GObj
  # iterate loop if player doesn't match rNext

  lis r9, 0x8000
  srw r0, r9, rCount
  or  rFlags, rFlags, r0
  # player has been flagged true for FX memory

_exit_loop:
stw rFlags, xFXflags(rParams)
# update FX memory

lfs f1, -0x7FBC(rtoc)
# set f1 argument to 0 to immediately induce catch cut before the next frame

_return:
bl 0x8007DBCC
# original instruction
.long 0




1.02 ------ 800daa28 --- bb410030 -> Branch
# after action state change, from above function context
# r28 = player being grabbed

.set xAnimIntr, 0x21A0

lwz r31, 0x1C(sp)
cmpwi r31, 0
bge+ _return
# r31 has last been used to load in 0x43300000 for casting purposes
# if the grapple check was enabled, then it is now set to an address
# MEM1 addresses use the sign bit, so a comparison to 0 is all we need

  _apply_anti_grapple:
  stw r31, xAnimIntr(r28)
  # this sets the animation interrupt to that of a "caught" player
  # for long-distance grabs, like those from link or samus;
  # this will cause the grab to break before grapple pulls the other player

_return:
lmw    r26, 0x0030 (sp)
.long 0



1.02 ------ 800db980 --- 881f234c -> Branch
# lbz    r0, 0x234C (r31)
# just after CatchCut call

# r31 = player data of person who was grabbed
# r30 = player GObj of person who was grabbed

# offsets
.set xAnimSpeed, 0x0
.set xOptions,   0x4
.set xFXflags,   0x8
.set xAura,      0xC
.set xColorReg,  0x408
.set xGrabber,   0x1A58
.set rParams,    3  # registers
.set rGrabber,   4
.set rFlags,     5
.set rNext,      6
.set rCount,     7
.set rPData,     31
.set rPlayer,    30

bl <TGrab_params>
mflr rParams
lwz  rFlags, xFXflags(rParams)
li   r0, 0
cmpwi rFlags, 0
beq+ _return
# do nothing if flags word is empty
# else, set up loop

mtcrf 0b00000001, r0
lwz  rNext, -0x3e74(r13)
stw  r0, xFXflags(rParams)
lwz  rGrabber, xGrabber(rPData)
lwz  rNext, 0x20(rNext)
li   rCount, 32
# FX have been cleared
# cr7 has been cleared
# rFlags = old flags
# ready for loop

_for_each_player_GObj:
  subic. rCount, rCount, 1
  cmpwi  cr1, rNext, 0
  cror   eq, eq, eq+4
  beq- _no_FX
  # termination conditions

  cmpw rPlayer, rNext
  lwz  rNext, 0x8(rNext)
  bne+ _for_each_player_GObj
  # iterate loop if player doesn't match rNext
  # else, exit loop

_exit_loop:
lis r9, 0x8000
srw r0, r9, rCount
and. r9, rFlags, r0
beq+ _no_FX
# if GObj is found, check for its flag in rFlags
# if it's TRUE, then apply effects according to user params

  _FX:

  _apply_custom_aura:
  lwz  r11, 0x2C(rGrabber)
  li  r10, 1
  addi r12, rParams, xAura
  li  r0, 0
  stw r10, xColorReg+0x28(rPData)
  stw r0,  xColorReg+0x0(r11)
  stw r12, xColorReg+0x8(rPData)
  stw r10, xColorReg+0x28(r11)
  stw r0,  xColorReg+0x0(rPData)
  stw r12, xColorReg+0x8(r11)
  # custom color auras have been applied to each player

  _apply_custom_animSpeed:
  lfs f1, xAnimSpeed(rParams)
  lfs f2, -0x65e0(rtoc)
  fmuls f1, f1, f2
  lwz r3, xGrabber(rPData)
  bl 0x8006f190
  bl <TGrab_params>
  mflr rParams
  lfs f1, xAnimSpeed(rParams)
  mr r3, rPlayer
  bl 0x8006f190

_no_FX:

_return:
lbz    r0, 0x234C (r31)
.long 0

---

To edit the user parameters, modify the <TGrab_params> function according to the comments.

- enabled: TRUE by default
TRUE: code will check for tech grab conditions
FALSE: code will ignore conditions, and use normal grab mechanics


- enforceFacing: TRUE by default
TRUE: tech only occurs if players are facing towards each other
FALSE: grabs from behind can be teched


- enforceHitbox: FALSE by default
TRUE: tech only occurs if both players have their hitboxes out during a grab
FALSE: tech occurs when the action state for grabbing is detected


- grapple: FALSE by default
TRUE: tech occurs only after grab has resolved -- hookshot/grapplebeam still pulls
FALSE: tech forces a grab to resolve on the frame of being captured


- animationSpeed: 1.6 by default
# this can be adjusted to change the speed of the recoil animations
# the CaptureCut animation will be ~66.6% of the speed of CatchCut, making them about the same duration


- customAura: see included event string
# audio/visual cues are created with a color register event string that can be modified
# see this post for more details


 
Last edited:

The Cape

Smash Master
Joined
May 16, 2004
Messages
4,478
Location
Carlisle, PA
This looks like it could roll into the Universal Port Fix I was talking about. Any ideas about grabbing ledges?
 

HillustratedJ36

Smash Cadet
Joined
Jun 17, 2015
Messages
43
Location
Lansing, MI
Slippi.gg
MIKE#274
*SF3 Third Strike parry sound*
Definitely something I have seen before...
Man, Ultimate techs backported to Melee? Oh what wonder.

A similar function is in Melee Light if I remember right...
 

The Cape

Smash Master
Joined
May 16, 2004
Messages
4,478
Location
Carlisle, PA
Sorry, not quite sure what you mean. Do you have any suggestions?
With port priority it functions for your hit lag during throws (code to fix) who gets the grab when they overlap (you have here) and who grabs the ledge when two people are falling past it at the same time.

Is it possible to make it so that the person with more ECB covering the ledge grabs it, but if they are both exactly equal, no one grabs it?
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
With port priority it functions for your hit lag during throws (code to fix) who gets the grab when they overlap (you have here) and who grabs the ledge when two people are falling past it at the same time.

Is it possible to make it so that the person with more ECB covering the ledge grabs it, but if they are both exactly equal, no one grabs it?
Oh, I hadn’t actually considered that grabbing would use port priority like that. Thanks for explaining. Well, in my experience port priority pops up from the fact that player GObjs get checked in order (or sometimes in reverse order). In the case of these tech grabs, the problem is solved by actually allowing the grab to go through -- it just cancels the effect by invoking the breakout state immediately, and then speeding up the grabee’s recovery animation to match that of the grabber’s recovery animation.

I’ll look into ledge grabbing priority and see if I can find what's causing its behavior.

---

*SF3 Third Strike parry sound*
Definitely something I have seen before...
Man, Ultimate techs backported to Melee? Oh what wonder.

A similar function is in Melee Light if I remember right...
Hah, I haven’t had any experience with importing custom SFX; but if you replace a normal sound with the SF3 parry sound then it would probably be accessible from the replaced SFX ID.

To customize the sounds used in this code, open up the code in MCM’s edit menu (or a text editor) and find the following lines near the top:

58000000 00000052 00004040 # SFX1
58000000 000000F3 00005040 # SFX2


These lines define the sounds 0x00000052 (wind gust?) and 0x000000F3 (mine click) so that they play together. You can remove one to play a single sound, or even add a new line to play a third sound. If you replace the ID with another one, it will change what sound is played.
 
Last edited:

The Cape

Smash Master
Joined
May 16, 2004
Messages
4,478
Location
Carlisle, PA
Oh, I hadn’t actually considered that grabbing would use port priority like that. Thanks for explaining. Well, in my experience port priority pops up from the fact that player GObjs get checked in order (or sometimes in reverse order). In the case of these tech grabs, the problem is solved by actually allowing the grab to go through -- it just cancels the effect by invoking the breakout state immediately, and then speeding up the grabee’s recovery animation to match that of the grabber’s recovery animation.

I’ll look into ledge grabbing priority and see if I can find what's causing its behavior.
For the grab breaks that you have here, does it check if any part of any grab box is overlapping? What about things like Koopa Klaw vs a grab or Aerial Koopa Klaw vs Samus's grapple grab (ground only)?
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
For the grab breaks that you have here, does it check if any part of any grab box is overlapping?
You can enable the enforceHitbox option by adding +0x04 to the flags byte up near the top of the code.

It has a comment that looks like this:
Code:
03        # flags:  +1 = enable,  +2 = enforceFacing,  +4 = enforceHitbox,  +8 = grapple option
By default, this is off -- causing only one of the grab hitbox collisions to be enforced.

If you change that 03 to a 07, then techs will only trigger when both grab hitboxes are out, and at least one of them makes contact with the other character. It’s a much tighter timing window, so I kept it off by default. I figured it would still be desirable though, so I also kept it as an option.

By default, enforceFacing is also enabled, so the players will also need to be facing each other. There is otherwise no additional collision detection.

---

What about things like Koopa Klaw vs a grab or Aerial Koopa Klaw vs Samus's grapple grab (ground only)?
I had thought about creating a whitelist for defining action state triggers, which would allow for things like special grabs to also be tech-able. That might be a feature in the next update. Ranged grabs like Samus's grapplebeam should already be techable, so this would enable Koopa Klaw vs Samus grab.

I had not thought about aerial grabs though. I think it could be done, but the recoil animation would probably have to use a different action state in order to look/function correctly. I’m sure it could be made to work somehow, so I’ll look into that as well.
 
Last edited:

The Cape

Smash Master
Joined
May 16, 2004
Messages
4,478
Location
Carlisle, PA
So I was experimenting with this today. I changed the 03 to 07 as I feel that works better. The only issue I see here is that allows grabs to be broken even when outranged. To test I was looking at Pikachu and Marth and grabbing at a distance where only Pikachu should be grabbed. Testing this again with the 03 bit changed to 0F and what happened is Pikachu missed his grab, then Marth grabbed on the second frame and it broke the grab because Pikachu's grab box was still active, this timing was due to spacing. I primarily changed the bit to test Samus grapple and that won out (as it should) in ties, but with that this also made he grab box with her hand (which grabs airborne opponents as well) always win the tie.

I personally feel that it should break only if both character's grab boxes overlap with the body boxes of the other player, not just the one.

The other grab scenario I tested was Koopa Klaw, air and ground, against Marth grab. Bowser always won if the grabs tied as it should be with command grabs I feel. There are not many of them, but they should take priority over normal grabs. The question is, is that a port thing?

Checked again and it is. So command grabs vs normal grabs is still determined by port. The way I would improve this is as follows:

- Grab breaks only happen if both grab boxes overlap with both body boxes, if only one grab box overlaps one body box, even if hitting another grab box it grabs
- Command Grabs such as Koopa Klaw and Kirby Inhale always win ties so long as they touch a body box
- Grapple grabs follow the normal rules of breaks and priority, but if they are the grapple portion of the hitbox, they win. Generally this will be outranging an opponent and hitting the first point showed, but in the rare instance of the extender grabbing a person right next to you it would apply. A way to apply this may be to make it so that grabs that only grab grounded people always win and those that grab air and ground tie?
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
The question is, is that a port thing?

Checked again and it is. So command grabs vs normal grabs is still determined by port.
No, I tried to explain this in part with my earlier response:
I had thought about creating a whitelist for defining action state triggers, which would allow for things like special grabs to also be tech-able. That might be a feature in the next update. Ranged grabs like Samus's grapplebeam should already be techable, so this would enable Koopa Klaw vs Samus grab.

I had not thought about aerial grabs though. I think it could be done, but the recoil animation would probably have to use a different action state in order to look/function correctly. I’m sure it could be made to work somehow, so I’ll look into that as well.
To elaborate: in its current version (1.0) -- the code only recognizes explicitly “normal” grab action states, and ignores the rest.

The code triggers the tech when it detects a scenario in which the character being grabbed is in the “grabbing” action state. This just comes down to to comparing a number to a value known at compile time, which can be quickly done with a few hard-coded instructions. The problem with this solution is that it doesn’t scale very well, so the more action states that need to be checked, the bigger the effect is on code size.

So the “whitelist” solution i proposed for an update would turn this problem into a short list of possible exceptions -- basically a list of action state numbers that count as a grab. It’s kind of like making a frame speed modifier, where each entry specifies an action state for the code to recognize and target.

By creating a small loop inside of the code that reads from a list of exception states instead of hardcoded ones, it would be possible to define (and customize which) command grabs as tech grab states. Only then would you see an effect from using moves like koopa claw.

---

Concerning port priority: as I said this code does nothing about port priority. It’s a simple exploit of the breakout timer, basically meaning that it should be inconsequential who does the grabbing. The problem that you're observing is just vanilla game behavior, not any behavior caused by the code. This would be fixed if the code was triggered by command grabs via a whitelist.

The Cape The Cape , as you know from our other conversations, I’m currently developing a fix for ledge grab port priority. I would imagine that grabbing port priority is essentially the same as ledge grabs -- where an order of operations that starts with some variable updates and possibly ends in a conditional action state change is encapsulated in some kind of “for each player” loop. If the updated variables determine conditions for the action state change, then the whole system of checking is closed for each player, and is basically blind to the updates not yet made in other players further down the GObj chain.

Designing a fix for this is hard to do, because it basically requires mixing up the order in which the game does things -- and if the game uses a bunch of callback functions to do these things, then what needs to be rearranged might be scattered across many character functions.

For fixing ledge grabs, this is a matter of delaying the action state change until each player’s ECB flags have been updated. A similar fix might work for grab priority by delaying the catch action, but would have virtually no effect on this code because each player immediately breaks out of their given actions regardless of who “catches” the other person.

So, while I’d be interested in looking into grab port priority in the future as a separate issue, I don’t think it would actually have the effect you’re thinking of for this code.

---

The way I would improve this is as follows:

- Grab breaks only happen if both grab boxes overlap with both body boxes, if only one grab box overlaps one body box, even if hitting another grab box it grabs
- Command Grabs such as Koopa Klaw and Kirby Inhale always win ties so long as they touch a body box
- Grapple grabs follow the normal rules of breaks and priority, but if they are the grapple portion of the hitbox, they win. Generally this will be outranging an opponent and hitting the first point showed, but in the rare instance of the extender grabbing a person right next to you it would apply. A way to apply this may be to make it so that grabs that only grab grounded people always win and those that grab air and ground tie?
I think giving command grabs a “winning” priority value would be an easy thing to do for the whitelist feature, so I’ll include that as an option

As for the second collision detection, I will see if I can find a way to do that independently from the natural collision detection, but it may take some research. Am I correct to assume that this would also solve the grapple scenario you described; since both players would have to be in close proximity to land each of their grabs?

And thanks for the feedback. These are all good suggestions.
 
Last edited:

The Cape

Smash Master
Joined
May 16, 2004
Messages
4,478
Location
Carlisle, PA
The way I would improve this is as follows:

- Grab breaks only happen if both grab boxes overlap with both body boxes, if only one grab box overlaps one body box, even if hitting another grab box it grabs
- Command Grabs such as Koopa Klaw and Kirby Inhale always win ties so long as they touch a body box
- Grapple grabs follow the normal rules of breaks and priority, but if they are the grapple portion of the hitbox, they win. Generally this will be outranging an opponent and hitting the first point showed, but in the rare instance of the extender grabbing a person right next to you it would apply. A way to apply this may be to make it so that grabs that only grab grounded people always win and those that grab air and ground tie?


So with this a bit further to expand on your comments.

The first point is essentially removing the fact that the grab break occurs if even one body box is overlapped with a grab and a grab box and changing that to require both in that situation to trigger the grab break. This would give the benefit to characters with more range on their grabs like Marth as they can touch their grab box over a hurt box without having their own hurtbox being grabbed.

The second point should have non Z grabs always win regardless of current vanilla port priority. These would include: Kirby inhale, Bowser Koopa Klaw, Mewtwo Confusion, Yoshi Egg Lay, Ganon Dark Dive, C. Falcon Falcon Dive all the air and ground versions of each of course.

The third point would be fixed with the first point now that I think about it as they would be overlapping a hurt box and generally another grab would not be overlapping their hurt box.

Again, these are completely my own opinions, but this may be a way to solve port priority for grabs in it's entirety without having to rewrite the commands used. This would initiate the grab breaks in the only situation where two characters are overlapping grab boxes and hurt boxes at the same time. It's not as clean as your ledge priority fix by distance, but I think it does an excellent job of doing this in general.

And Punkline Punkline if we want to add this into the UPF stuff, we could make it instead of triggering a grab break/release make it just plain ignore the "Catch" action in the above states

One last piece I thought of. The enforce facing might not be needed with the need to overlap two hurt boxes, but even if it did it would need to be whitelisted with Samus's extender likely as that can grab behind her, as can some grabs such as Kirby inhale
 
Last edited:
Top Bottom