Skip to content

Instantly share code, notes, and snippets.

@y-ack
Last active July 18, 2022 07:28
Show Gist options
  • Select an option

  • Save y-ack/457dc3d34c93ce325c7c4afb4cb1cc93 to your computer and use it in GitHub Desktop.

Select an option

Save y-ack/457dc3d34c93ce325c7c4afb4cb1cc93 to your computer and use it in GitHub Desktop.

Revisions

  1. y-ack revised this gist Jul 18, 2022. 1 changed file with 7 additions and 7 deletions.
    14 changes: 7 additions & 7 deletions landmaker_damage_pushback_ywy.txt
    Original file line number Diff line number Diff line change
    @@ -39,8 +39,8 @@ table: damage values by structure level [1]

    e.g. breaking 2 silvers (structure level=1), at pusher position 2
    adds
    ` 2*1 + 22
    ` + 2*1 + 22
    2*1 + 22
    + 2*1 + 22
    for 48 raw damage from structures

    note that 7 push is almost all the way down the board;
    @@ -70,8 +70,8 @@ until a minimum push damage threshold of 4 (at 180 seconds) [1]

    the remainder goes into piece damage, i.e.:

    `push damage += raw damage / push threshold`
    `piece damage += raw damage % push threshold`
    push damage += raw damage / push threshold
    piece damage += raw damage % push threshold

    in other words, <60s into a match, it takes 9 rawdmg for 1 push;
    between 60 and 90s, 8 rawdmg is 1 push; and 180s+ is 4 dmg/push
    @@ -132,12 +132,12 @@ value of 0, a player makes two breaks: 1B+4, then 1S

    at pusher 2, **15** raw damage is required to achieve pushback.
    the first break, 1 bronze and 4 house pieces:
    `(2*0 + 8) + (4) = 12`
    (2*0 + 8) + (4) = 12
    12/15 is insufficient to trigger pushback

    the second break, 1 silver:
    `(2*1 + 22) = 24`
    12 previously accumulated + 24 = 36
    (2*1 + 22) = 24
    12 previously accumulated + 24 = 36
    36/15 is sufficient to trigger pushback,
    so pushback will occur this turn, and
    (given that we have no incoming damage)
  2. y-ack revised this gist Jul 18, 2022. 1 changed file with 151 additions and 59 deletions.
    210 changes: 151 additions & 59 deletions landmaker_damage_pushback_ywy.txt
    Original file line number Diff line number Diff line change
    @@ -1,43 +1,77 @@
    # LAND MAKER ~ DAMAGE AND PUSHBACK [ywy] REV.0 2022/03/26
    # LAND MAKER ~ DAMAGE AND PUSHBACK [ywy] REV.1 2022/07/18
    addresses apply for: landmakrj

    ## RAW DAMAGE
    raw damage is calculated at clear time by 0x96680,
    which runs once for every tile cleared, including the launched tile.
    (larger structures have one 'primary' tile selected for processing)
    ## terminology:
    'break' refers to a shot action that hits a piece on a corner,
    causing them to disappear and send damage.
    'placing' refers to a shot action that does not break.
    'building' refers to pieces transformed into houses by a placing
    shot action.
    'pushback' refers to the behavior of the pusher retracting as a
    result of breaking with specific damage output requirements met.
    not to be confused with
    'PUSHBACK' refers to an internal pusher state used by both item
    arrows and 'pushback' as defined above.

    nonbuilding tiles are worth half a damage but
    a) counted separately
    b) rounded down when incorporated into raw damage
    single buildings are worth 1 damage
    ## damage and pushback
    ### raw damage
    raw damage for each piece is calculated at break time by $96680,
    which runs once for each piece cleared, including the shot tile.
    (larger structures count are a single 'piece')

    non-building tiles (including items) are worth half a damage,
    but they are counted separately from building damage, so that
    leftover half-damage carries over between breaks.

    single buildings are worth 1 damage,
    structures are worth
    min(pusher_position, 7) * structure_level + structure_value
    `min(pusher_position, 7) * structure_level + structure_value`

    where pusher position 0 is fully retracted and position 1 looks like
    https://cdn.discordapp.com/attachments/455404849626873869/957277010512728104/32080.png

    |*| STRUCTURE | VALUE | HEX |
    |0| bronze | 8 | 8h |
    |1| silver | 22 | 16h |
    |2| gold | 38 | 26h |
    |3| platinum | 54 | 36h |
    | | STRUCTURE | VALUE | HEX |
    |0| bronze | 8 | 8h |
    |1| silver | 22 | 16h |
    |2| gold | 38 | 26h |
    |3| platinum | 54 | 36h |
    table: damage values by structure level [1]

    e.g. breaking 2 silvers, with pusher position 2 [see 2]
    e.g. breaking 2 silvers (structure level=1), at pusher position 2
    adds
    2*1 + 22
    + 2*1 + 22
    ` 2*1 + 22
    ` + 2*1 + 22
    for 48 raw damage from structures

    note that 7 push is almost all the way down the board;
    large structures will not be able to take advantage of it.
    assuming one did break a gold structure at 5 push, 5*2 == 10 extra raw damage.

    ## DAMAGE CONVERSION
    0xAB03E applies received damage
    -------------------------------------------------------------------------------
    [1] internal tile level assigns nonstructure `0` and bronze starting at 2,
    but level used in structure damage is `(internal level - 2)` ($96696)
    [2] pusher row is stored as index into board, div 16 for position here.


    push damage += raw damage / (9 - push threshold modifier)
    piece damage += raw damage % (9 - push threshold modifier)
    the push threshold modifier is based on match time elapsed.
    at 60 seconds the push threshold lowers by 1,
    decreasing again every 30s, up to 5 times.
    ### damage conversion
    $AB03E applies received damage

    raw damage is converted into two types of damage
    when it is sent to the opponent (represented by glowing orbs),
    'piece damage' and 'push damage,'
    but the conversion is affected by margin time.

    the push damage conversion threshold starts at 9,
    meaning 9 raw damage is needed for 1 push damage.
    when the round elapsed time reaches 60 seconds,
    the push damage threshold decreases by 1,
    and further decreases every 30 seconds after that,
    until a minimum push damage threshold of 4 (at 180 seconds) [1]

    the remainder goes into piece damage, i.e.:

    `push damage += raw damage / push threshold`
    `piece damage += raw damage % push threshold`

    in other words, <60s into a match, it takes 9 rawdmg for 1 push;
    between 60 and 90s, 8 rawdmg is 1 push; and 180s+ is 4 dmg/push
    @@ -46,46 +80,104 @@ remainder damage that doesn't go towards push goes into piece.
    the push threshold influences nuisance tile accumulation!

    if incoming push damage >= 3, the "DANGER" voice line plays.
    -------------------------------------------------------------------------------
    [1] (strictly speaking, this is a modifier that counts up and is subtracted
    from 9 at damage conversion time, but a view of `(9 - modifier)` as
    `push threshold` is simpler)

    ### pushback

    ## PUSHBACK
    0x953A4
    pushback($953A4) is evaluated /whenever damage is sent/.
    damage is sent on every frame that raw damage is >= 1.
    (note that **all** breaks will send at least 1 damage;
    breaking an item (0.5(shot tile)+0.5(item))
    or single tile (0.5+0.5) will both evaluate pushback.)

    pushback has an internal accumulator for raw damage sent.
    you can think of it like an invisible meter.
    internally, pushback accumulates raw damage sent.
    it can be thought of like an invisible meter.
    "pusher [position]" refers to the amount of board covered/topmost line

    - when pusher is at 0, the meter resets.
    - when pusher is NOT at 0,
    - the meter threshold for pushback occurring is `REQ[pusher] + 2`
    - for every contiguous group of tiles cleared [3]:
    - if accumulated pushback meter exceeds the requirement:
    - the threshold is subtracted for the meter
    - a 'push back this turn' flag is set

    y believes the following to be true (requires further verification)
    - you /cannot/ push back more than once per shot
    - including by using an arrow item with excess buffered pushback dmg(?)
    - you /can/ drain from the pushback meter more than once per shot,
    if multiple damage sources evaluate that turn [3]

    |*| REQ| +2 |
    |0| 15 | 17 |
    |1| 15 | 17 |
    |2| 13 | 15 |
    |3| 9 | 11 |
    |4| 6 | 8 |
    |5| 4 | 6 |
    |6| 2 | 4 |
    |7| 1 | 3 |
    |8| 1 | 3 |
    |9| 1 | 3 |
    - the requirement for pushback is `REQ[pusher] + 2`
    - the total raw damage this frame is added to the total accumulated pushback
    - if accumulated pushback meter exceeds the requirement:
    - the threshold is subtracted for the meter
    - the push state is set to PUSHBACK

    | | REQ| +2 |
    |0| 15 | 17 | (ignore this line when calculating)
    |1| 15 | 17 |
    |2| 13 | 15 |
    |3| 9 | 11 |
    |4| 6 | 8 |
    |5| 4 | 6 |
    |6| 2 | 4 |
    |7| 1 | 3 |
    |8| 1 | 3 |
    |9| 1 | 3 |
    table: pushback meter threshold lookup.
    note that pusher 0 (and 9?) cannot actually be encountered.
    - pusher 0 is fully retracted, and the threshold
    is not considered if damage is sent at this position
    - pusher 9 is off of the board.

    -------------------------------------------------------------------------------
    [1] internal tile level assigns nonstructure `0` and bronze starting at 2,
    but level used in structure damage is `(internal level - 2)` (0x96696)
    [2] 4 rows if counting staggered individually.
    image shows pusher position 1 for purposes of damage. https://cdn.discordapp.com/attachments/455404849626873869/957277010512728104/32080.png
    pusher row is stored as index into board, div 16 for position here.
    [3] e.g. star items & launched tile counted separately (needs verification?)

    for help visualizing pushback meter accumulation and requirements, see scripts for mame and fbneo:
    https://gist.github.com/y-ack/b17cd4a25b673dcfc7303ad8f5c60770

    #### example
    given a pusher position of 2 and initial accumulated pushback
    value of 0, a player makes two breaks: 1B+4, then 1S

    at pusher 2, **15** raw damage is required to achieve pushback.
    the first break, 1 bronze and 4 house pieces:
    `(2*0 + 8) + (4) = 12`
    12/15 is insufficient to trigger pushback

    the second break, 1 silver:
    `(2*1 + 22) = 24`
    12 previously accumulated + 24 = 36
    36/15 is sufficient to trigger pushback,
    so pushback will occur this turn, and
    (given that we have no incoming damage)
    pusher position will be **1** for the next turn.

    the pushback value vs requirement is now
    21/17,
    meaning the next shot that sends damage (any break) will also trigger pushback.

    #### esoterics
    fundamentally, the behavior of pushback is
    "sending enough damage will retreat the pusher."
    however, there are other subtle behaviors hidden in the already unexplained mechanic:

    firstly, while every breaking shot will evaluate damage,
    it is possible for damage to be counted over multiple frames.
    the most obvious case is with **star items**, where the shot tile and item
    are counted 40 frames before the tiles eliminated are counted.
    additionally, it seems that there is some limit to the number of pieces
    that can be counted while sweeping over the board each frame,
    such that masses of single tiles send damage over multiple frames.
    damage being evaluated on multiple frames means
    pushback can be evaluated multiple times per break,
    and because there is no check for whether pushback state has already occurred,
    the pushback accumulator can drain multiple times with no benefit to the player.
    this bug could be prevented by checking whether the push state is
    already PUSHBACK before checking the pushback requirement.

    similarly, because arrow items
    1) activate on break
    2) set the same PUSHBACK state,
    breaking an arrow will drain pushback if possible, and unless there are
    tiles in the danger zone, this is essentially 'wasted' pushback.

    the second behavior has to do with pushback evaluation being triggered
    by sending damage. this is another separation of the actions of
    shooting a tile without sending damage (placing) and
    shooting a tile and sending damage (breaking).
    no matter how much pushback 'meter' is stored up,
    the pusher cannot be repelled without making a breaking shot.
    the other side of this is that pushback cannot be /drained/
    without breaking tiles.
    this includes the behavior of resetting when the pusher is fully retracted.
  3. y-ack revised this gist Apr 23, 2022. No changes.
  4. y-ack revised this gist Mar 27, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion landmaker_damage_pushback_ywy.txt
    Original file line number Diff line number Diff line change
    @@ -56,7 +56,7 @@ you can think of it like an invisible meter.

    - when pusher is at 0, the meter resets.
    - when pusher is NOT at 0,
    - the meter threshold for pushback occuring is `REQ[pusher] + 2`
    - the meter threshold for pushback occurring is `REQ[pusher] + 2`
    - for every contiguous group of tiles cleared [3]:
    - if accumulated pushback meter exceeds the requirement:
    - the threshold is subtracted for the meter
  5. y-ack created this gist Mar 27, 2022.
    91 changes: 91 additions & 0 deletions landmaker_damage_pushback_ywy.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,91 @@
    # LAND MAKER ~ DAMAGE AND PUSHBACK [ywy] REV.0 2022/03/26
    addresses apply for: landmakrj

    ## RAW DAMAGE
    raw damage is calculated at clear time by 0x96680,
    which runs once for every tile cleared, including the launched tile.
    (larger structures have one 'primary' tile selected for processing)

    nonbuilding tiles are worth half a damage but
    a) counted separately
    b) rounded down when incorporated into raw damage
    single buildings are worth 1 damage
    structures are worth
    min(pusher_position, 7) * structure_level + structure_value

    |*| STRUCTURE | VALUE | HEX |
    |0| bronze | 8 | 8h |
    |1| silver | 22 | 16h |
    |2| gold | 38 | 26h |
    |3| platinum | 54 | 36h |
    table: damage values by structure level [1]

    e.g. breaking 2 silvers, with pusher position 2 [see 2]
    adds
    2*1 + 22
    + 2*1 + 22
    for 48 raw damage from structures

    note that 7 push is almost all the way down the board;
    large structures will not be able to take advantage of it.
    assuming one did break a gold structure at 5 push, 5*2 == 10 extra raw damage.

    ## DAMAGE CONVERSION
    0xAB03E applies received damage

    push damage += raw damage / (9 - push threshold modifier)
    piece damage += raw damage % (9 - push threshold modifier)
    the push threshold modifier is based on match time elapsed.
    at 60 seconds the push threshold lowers by 1,
    decreasing again every 30s, up to 5 times.

    in other words, <60s into a match, it takes 9 rawdmg for 1 push;
    between 60 and 90s, 8 rawdmg is 1 push; and 180s+ is 4 dmg/push
    note the modulo operator for nuisance tile damage:
    remainder damage that doesn't go towards push goes into piece.
    the push threshold influences nuisance tile accumulation!

    if incoming push damage >= 3, the "DANGER" voice line plays.

    ## PUSHBACK
    0x953A4

    pushback has an internal accumulator for raw damage sent.
    you can think of it like an invisible meter.
    "pusher [position]" refers to the amount of board covered/topmost line

    - when pusher is at 0, the meter resets.
    - when pusher is NOT at 0,
    - the meter threshold for pushback occuring is `REQ[pusher] + 2`
    - for every contiguous group of tiles cleared [3]:
    - if accumulated pushback meter exceeds the requirement:
    - the threshold is subtracted for the meter
    - a 'push back this turn' flag is set

    y believes the following to be true (requires further verification)
    - you /cannot/ push back more than once per shot
    - including by using an arrow item with excess buffered pushback dmg(?)
    - you /can/ drain from the pushback meter more than once per shot,
    if multiple damage sources evaluate that turn [3]

    |*| REQ| +2 |
    |0| 15 | 17 |
    |1| 15 | 17 |
    |2| 13 | 15 |
    |3| 9 | 11 |
    |4| 6 | 8 |
    |5| 4 | 6 |
    |6| 2 | 4 |
    |7| 1 | 3 |
    |8| 1 | 3 |
    |9| 1 | 3 |
    table: pushback meter threshold lookup.
    note that pusher 0 (and 9?) cannot actually be encountered.

    -------------------------------------------------------------------------------
    [1] internal tile level assigns nonstructure `0` and bronze starting at 2,
    but level used in structure damage is `(internal level - 2)` (0x96696)
    [2] 4 rows if counting staggered individually.
    image shows pusher position 1 for purposes of damage. https://cdn.discordapp.com/attachments/455404849626873869/957277010512728104/32080.png
    pusher row is stored as index into board, div 16 for position here.
    [3] e.g. star items & launched tile counted separately (needs verification?)