@@ -370,11 +370,13 @@ func (m *Manager) sheet(msg engine.Message, fields []string) string {
370370 }
371371 m .ensureAbilities (ctx , pkey )
372372 sheet , _ := m .store .HGetAll (ctx , sheetKey (pkey ))
373+ class , _ := m .store .GetStr (ctx , classKey (pkey ))
373374 desc := alignName (sheet ["align" ])
374- if class , _ := m . store . GetStr ( ctx , classKey ( pkey )); class != "" {
375+ if class != "" {
375376 desc += " " + class
376377 }
377- return fmt .Sprintf ("%s the %s (lvl %d) — %s" , name , desc , sheet ["level" ], abilityLine (sheet ))
378+ return fmt .Sprintf ("%s the %s (lvl %d) — HP %d/%d · %s" ,
379+ name , desc , sheet ["level" ], curHP (sheet , class ), maxHP (sheet , class ), abilityLine (sheet ))
378380}
379381
380382// adminVerb handles the privileged !rpg commands (pause/resume/push/hog). They are
@@ -558,6 +560,9 @@ func (m *Manager) Tick() {
558560 ctx := context .Background ()
559561 key := sheetKey (p .key )
560562 m .moveOnMap (ctx , p .key ) // wander the world map (cosmetic; happens every tick)
563+ if m .tickHP (ctx , p .key ) {
564+ continue // downed and recovering — no progress this tick
565+ }
561566 ttl , err := m .store .HIncr (ctx , key , "ttl" , - step )
562567 if err != nil {
563568 continue
@@ -597,9 +602,8 @@ func (m *Manager) battle(ctx context.Context, p player, level int64) {
597602 effPow = myPow * 111 / 100
598603 }
599604 // Class: your primary ability's modifier sharpens (or dulls) your attack.
600- if cls , _ := m .store .GetStr (ctx , classKey (p .key )); cls != "" {
601- effPow += classAttackMod (mine , cls )
602- }
605+ myClass , _ := m .store .GetStr (ctx , classKey (p .key ))
606+ effPow += classAttackMod (mine , myClass )
603607 if effPow < 0 {
604608 effPow = 0
605609 }
@@ -615,8 +619,17 @@ func (m *Manager) battle(ctx context.Context, p player, level int64) {
615619 }
616620
617621 verb , dir , sign := "won" , "sooner" , int64 (- 1 )
622+ downed := false
618623 if ! win {
619624 verb , dir , sign = "lost" , "later" , int64 (1 )
625+ // Losing the bout also costs blood — and can leave you downed.
626+ hurt := int64 (m .roll (int (level )+ 3 ) + 2 )
627+ if crit {
628+ hurt *= 2
629+ }
630+ m .damage (ctx , p .key , hurt )
631+ after , _ := m .store .HGetAll (ctx , sheetKey (p .key ))
632+ downed = isDowned (after , myClass )
620633 }
621634 _ , _ = m .store .HIncr (ctx , sheetKey (p .key ), "ttl" , sign * amt )
622635
@@ -626,6 +639,9 @@ func (m *Manager) battle(ctx context.Context, p player, level int64) {
626639 }
627640 m .out .Say (p .network , p .channel , fmt .Sprintf ("🗡️ %s [%d] challenged %s [%d] in combat and %s%s — %ds %s." ,
628641 p .nick , myPow , opp .nick , oppPow , verb , critStr , amt , dir ))
642+ if downed {
643+ m .out .Say (p .network , p .channel , fmt .Sprintf ("💢 %s is beaten down to 0 HP and must recover before pressing on." , p .nick ))
644+ }
629645}
630646
631647const eventOdds = 6 // ~1-in-N chance an event fires each tick
0 commit comments