phylll / mychs-macro-magic

A simple, sane, and friendly little scripting language for your Roll20 macros.
MIT License
0 stars 0 forks source link

Midgard-Skripte: Kritische Ereignisse automatisch auswürfeln, ausgeben und die Folgen abwickeln #3

Closed phylll closed 2 years ago

phylll commented 3 years ago

Dependencies: MMM feature requests

Pseudocode:

set customizable cCriticalSuccessTable = "<name of roll table>"
set customizable cCriticalFailureTable = "<name of roll table>"
...
set defenseRoll = roll(defenseRollExpr)

if iscritical(defenseRoll)
  set criticalSuccessEvent = roll("1t[" & cCriticalSuccessTable & "]")
  set criticalSuccessDescription = getprop(criticalSuccessEvent, "name")
  set criticalSuccessImageURL = getprop(criticalSuccessEvent, "avatar")

  chat: ${criticalSuccessDescription} [x](${criticalSuccessImageURL})

  // Process special cases (as per https://midgard.alienn.net/doku.php?id=kritischer_erfolg:abwehr)
  if isMeleeAttack and (criticalSuccessEvent >= 3 and criticalSuccessEvent <= 6)
    // attacker loses weapon 
    set lostWeaponDistance = roll("1d6-1")
    set lostWeaponDirection = roll("1d4") // technically, "criticalSuccessEvent - 2"
    set lostWeaponPositionX = ...
    set lostWeaponPositionY = ...
    spawn token ("lost_weapon", lostWeaponPositionX, lostWeaponPositionY)
  else if isMeleeAttack and criticalSuccessEvent == 7 
    // attacker falls/stumbles
    queue "Attacker stumbles", 1 round no attack or defense to tracker
    set token (attacker, "status_dead")
  else if isMeleeAttack and criticalSuccessEvent == 8
     // Melee: Light hit on attacker, no defense possible. Ranged Attack: +2 on next defense.
     set critLightExtraDamage = roll("1d6")
     output damage information against attacker's endurance
  else if isMeleeAttack and criticalSuccessEvent == 9
     set critHeavyExtraDamage = roll("1d6")
     output damage information against attacker's health and endurance
  else if isMeleeAttack and criticalSuccessEvent == 10
     set critHeavyExtraDamage = roll("1d6")
     set critLostConsciousness = roll("1d6")
     set token for lost consciousness
     queue "Attacker unconscious", critLostConsciousness rounds to tracker
     output damage information against attacker's health and endurance
  end if

else if isfumble(defenseRoll)

  // analogous

end if
phylll commented 3 years ago

Now that MMM#78 is resolved, spawning new tokens and working with them (assigning control over them, at least) will require waiting for SpawnDefaultToken 0.19 to be installed through the official system (currently we have 0.17 in both games, 0.19 is dated 2021-04-14). Then we'll be able to play with giving newly spawned tokens a unique token_name using the --tokenName attribute, which will hopefully make it possible to access them using token_mod --controlledby.

phylll commented 2 years ago

The two dependencies remain, and token_mod would need to be installed.

phylll commented 2 years ago

Any smart way of doing this would also build upon https://github.com/michael-buschbeck/mychs-macro-magic/issues/160 and use MMM functions

phylll commented 2 years ago
  1. Any token can concurrently carry several (lingering) critical effects.
  2. All permanent effects are serious injuries, indicated by setting the corresponding serious injury status marker. Therefore, all other critical effects are combinations of immediate, one-off (gone after the next action of the same type), or transitory effects that linger for a number of combat rounds. If there is a lingering periodic effect, the same duration affects all but the immediate effect.
  3. Effects can be positive or negative, and hit/stick with both the token that rolled the critical and their opponent.

All of this means that there are too many different effects to map even the existence of one to an individual status marker. We need a single status marker that signifies "some active critical effect on this token" (suggestion: blue). The optional number may be used to indicate the number of parallel active effects or the number of rounds until the last effect expires.

The combat scripts already have several handlers for severe injury effects that can be easily expanded to handle critical effects, as well. So far, there are handlers for prohibited actions, modifiers on actions, and end-of-round effects. We may need to add an after-action handler for one-off effects that change the next action of the same type, whether in the current or next round.

The basic logic model would then be this:

It looks as if the only non-standardizable part are the immediate effects where we might have to roll dice for odds of destroying magic weapons, move tokens, spawn new tokens etc. All one-off and periodic effects, in contrast, fall into the same few simple types as those from serious injuries: prohibit simple types of action or put modifiers on them. So any critical effect assigned to a token may be described by something like this struct:

set criticalEffect = {
    label: "xxx",
    desc: "xxx",
    immediate: "!mmm do ...",
    persistent: persistentEffect
}
set persistentEffect = {
    expiry: { type: (what to count), counter: (how many of type) },
    rollModifiers: { *actionType*: modifier, *actionType*: modifier, ... },
    *noProhibitedAction1*: true,
    *noProhibitedAction2*: true,
    ...
    marker: (which additional marker is linked to this effect, and needs to be removed at expiry)
}

Let's see how to implement the individual effects.

Kritischer Fehler bei der Abwehr

🎲 desc pseudocode
01–10 Du verlierst kurz das Gleichgewicht und brauchst etwas Zeit, um wieder kampfbereit zu sein. Du bekommst auf Deinen nächsten Angriff (in der laufenden oder folgenden Runde) -2 auf den EW: Angriff kannst jedoch ohne Abzug abwehren (konzentrierte Abwehr ist nicht möglich). addCriticalEffect(myID, { expiry: { count: 1, type: "attack" }, rollModifiers: { "attack": -2 } } )
11–20 Du verlierst kurz das Gleichgewicht und brauchst etwas Zeit, um wieder kampfbereit zu sein. Du kannst Deinen nächsten Angriff (in der laufenden oder folgenden Runde) nicht durchführen, jedoch kannst Du normal abwehren (konzentrierte Abwehr ist nicht möglich). addCriticalEffect(myID, { expiry: { count: 1, type: "attack" }, noAttack: true, noFocusedDefense: true } )
21–30 Deine Verteidigungswaffe wird zerstört. Bei magischen Waffen wird mit 1W100 auf den magischen Bonuswert (*10%) gewürfelt, ob diese auch zerstört ist. Bei Verteidigung ohne Waffe, verlierst Du kurz das Gleichgewicht und musst eine Runde aussetzen. Du bekommst -2 auf alle EW der nächsten Runde (konzentrierte Abwehr ist nicht möglich). if using mundane weapon: chat(destroyed), else if using magic weapon: roll() for weapon destruction; else addCriticalEffect(myID, { expiry: { count: 1, type: "round" }, rollModifiers: { "attack": -2, "defense": -2 }, noFocusedDefense: true } )
31-40 Du lässt Deine Verteidigungswaffe fallen. Sie fällt auf das Feld, auf dem Du dich befindest. Du setzt die nächste Runde aus um Deine Waffe aufzuheben. Es gibt in der nächsten Runde jedoch keinen Vorteil für Deinen Gegner und keinen Nachteil für Deine Verteidigung (konzentrierte Abwehr ist nicht möglich). Bei Verteidigung ohne Waffe, verlierst Du das Gleichgewicht und musst eine Runde aussetzen. Es gibt in der nächsten Runde jedoch keinen Vorteil für Deinen Gegner und keinen Nachteil für Deine Verteidigung (konzentrierte Abwehr ist nicht möglich). addCriticalEffect(myID, { expiry: { count: 1, type: "round" }, noAttack: true; noFocusedDefense: true } )
41-50 Du wirst ein Feld nach hinten gedrängt (Nahkampf) oder der Schwung Deiner Ausweichbewegung (Fernkampf) reißt dich um ein Feld nach hinten mit. Alternativ nach links (1-2), rechts (3-4) oder nach vorne (5-6). Im Nahkampf kann Dein Gegner Dir augenblicklich folgen oder sich lösen. Im Handgemenge ist Deine Sicht behindert. Du kannst in der folgenden Runde nicht angreifen, da Du Dir Blut oder Schweiß aus den Augen wischen oder eine verrutschte Kopfbedeckung zurechtrücken musst (konzentrierte Abwehr ist nicht möglich). if isBrawl(): addCriticalEffect(myID, { expiry: { count: 1, type: "round" }, noAttack: true, noFocusedDefense: true } ); else: moveToken(), tell melee opponent their options
51-60 Deine Sicht wird behindert. Du kannst in der folgenden Runde nicht angreifen, da Du Dir Blut oder Schweiß aus den Augen wischen oder eine verrutschte Kopfbedeckung zurechtrücken musst (konzentrierte Abwehr ist nicht möglich). addCriticalEffect(myID, { expiry: { count: 1, type: "round" }, noAttack: true, noFocusedDefense: true } )
61-70 Du gibst Dir in der Verteidigung eine Blöße. Im Nahkampf oder Handgemenge darf Dein Gegner sofort außer der Reihe einen zusätzlichen EW:Angriff machen, der nicht abgewehrt werden darf. Im Fernkampf kannst Du dem nächsten Schuss oder Wurf (in der laufenden oder folgenden Runde) nicht ausweichen und daher keinen WW:Abwehr würfeln (konzentrierte Abwehr ist nicht möglich). addCriticalEffect(myID, { expiry: { count: 1, type: "defense" }, noDefense: true } )
71-80 Du verstauchst Dir Deinen Fuß. Die Bewegungsweite verringert sich für 2W6 Runden um ein Drittel. set cap on .B, set counter / subsq. rounds: counter--
81-90 Du prallst unglücklich mit Deinem Gegner zusammen (Nahkampf oder Handgemenge) oder gegen ein Hindernis (Fernkampf) und bist kurzzeitig benommen. Im Nahkampf oder Handgemenge kannst Du in der folgenden Runde weder angreifen noch abwehren. Dein Gegner leidet unter denselben Folgen – aber nur, wenn ihm ein PW:Gewandtheit misslingt. Im Fernkampf kannst Du dem nächsten Schuss oder Wurf (in der laufenden oder folgenden Runde) nicht ausweichen und daher keinen WW:Abwehr würfeln (konzentrierte Abwehr ist nicht möglich) und zusätzlich entfällt auch Dein nächster EW:Angriff (in der laufenden oder folgenden Runde). Eine konzentrierte Abwehr ist nicht möglich. addCriticalEffect(myID, { expiry: { count: 1, type: "round" }, noAttack: true, noDefense: true } ); if not isSuccess(roll(foeID.Gw)): same for foeID
91-99 Du rutscht aus und stürzt zu Boden. Im Handgemenge darf Dein Gegner einen zusätzlichen Angriff starten, der nicht abgewehrt werden darf. if isBrawl(): addCriticalEffect(myID, { expiry: { count: 1, type: "defense" }, noDefense: true } )
100 Du stürzt und verlierst für 1W6 Runden das Bewusstsein. addCriticalEffect(myID, { expiry: { count: roll("1d6"), type: "round" }, marker: "status_sleepy" } )
phylll commented 2 years ago

Throwing around weapons once there is a selected token (to which offset relates):

!Spawn --name|tokenMuleWeapons --side|rand --offset|2,2 --order|bottom --controlledby|all --tokenProps|name:Ork 5's Weapon,showname:1
phylll commented 2 years ago

Seems to work nicely in the 2.0.0-pre versions of combat scripts.