diff --git a/README.md b/README.md index 1fad8a5b3..b960a593d 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,6 @@ If you turn the [Doom logo upside down](https://www.reddit.com/r/Doom/comments/8 * UMAPINFO support, compliant to Rev 2.2 of the [spec](https://github.com/kraflab/umapinfo). * MBF21 compatibility level, compliant to Rev 1.4 of the [spec](https://github.com/kraflab/mbf21). * SMMU-style swirling animated flats. - * Customization of the extended Boom HUD using the [WOOFHUD](https://github.com/fabiangreffrath/woof/blob/master/docs/woofhud.md) lump. ## Usage @@ -204,6 +203,11 @@ Copyright: © TobiasKosmos. License: [CC-BY-3.0](https://creativecommons.org/licenses/by/3.0/) and [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/) +Files: `base/all-all/sbardef.lmp` +Copyright: + © 2024 Ethan Watson. +License: [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/) + Files: `cmake/FindSDL2.cmake, cmake/FindSDL2_net.cmake` Copyright: © 2018 Alex Mayfield. License: [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) diff --git a/base/all-all/dig033.png b/base/all-all/dig033.png new file mode 100644 index 000000000..36777b821 Binary files /dev/null and b/base/all-all/dig033.png differ diff --git a/base/all-all/dig37.png b/base/all-all/dig037.png similarity index 100% rename from base/all-all/dig37.png rename to base/all-all/dig037.png diff --git a/base/all-all/dig43.png b/base/all-all/dig043.png similarity index 100% rename from base/all-all/dig43.png rename to base/all-all/dig043.png diff --git a/base/all-all/dig45.png b/base/all-all/dig045.png similarity index 100% rename from base/all-all/dig45.png rename to base/all-all/dig045.png diff --git a/base/all-all/dig46.png b/base/all-all/dig046.png similarity index 100% rename from base/all-all/dig46.png rename to base/all-all/dig046.png diff --git a/base/all-all/dig47.png b/base/all-all/dig047.png similarity index 100% rename from base/all-all/dig47.png rename to base/all-all/dig047.png diff --git a/base/all-all/dig0.png b/base/all-all/dig048.png similarity index 100% rename from base/all-all/dig0.png rename to base/all-all/dig048.png diff --git a/base/all-all/dig1.png b/base/all-all/dig049.png similarity index 100% rename from base/all-all/dig1.png rename to base/all-all/dig049.png diff --git a/base/all-all/dig2.png b/base/all-all/dig050.png similarity index 100% rename from base/all-all/dig2.png rename to base/all-all/dig050.png diff --git a/base/all-all/dig3.png b/base/all-all/dig051.png similarity index 100% rename from base/all-all/dig3.png rename to base/all-all/dig051.png diff --git a/base/all-all/dig4.png b/base/all-all/dig052.png similarity index 100% rename from base/all-all/dig4.png rename to base/all-all/dig052.png diff --git a/base/all-all/dig5.png b/base/all-all/dig053.png similarity index 100% rename from base/all-all/dig5.png rename to base/all-all/dig053.png diff --git a/base/all-all/dig6.png b/base/all-all/dig054.png similarity index 100% rename from base/all-all/dig6.png rename to base/all-all/dig054.png diff --git a/base/all-all/dig7.png b/base/all-all/dig055.png similarity index 100% rename from base/all-all/dig7.png rename to base/all-all/dig055.png diff --git a/base/all-all/dig8.png b/base/all-all/dig056.png similarity index 100% rename from base/all-all/dig8.png rename to base/all-all/dig056.png diff --git a/base/all-all/dig9.png b/base/all-all/dig057.png similarity index 100% rename from base/all-all/dig9.png rename to base/all-all/dig057.png diff --git a/base/all-all/dig58.png b/base/all-all/dig058.png similarity index 100% rename from base/all-all/dig58.png rename to base/all-all/dig058.png diff --git a/base/all-all/diga.png b/base/all-all/dig065.png similarity index 100% rename from base/all-all/diga.png rename to base/all-all/dig065.png diff --git a/base/all-all/digb.png b/base/all-all/dig066.png similarity index 100% rename from base/all-all/digb.png rename to base/all-all/dig066.png diff --git a/base/all-all/digc.png b/base/all-all/dig067.png similarity index 100% rename from base/all-all/digc.png rename to base/all-all/dig067.png diff --git a/base/all-all/digd.png b/base/all-all/dig068.png similarity index 100% rename from base/all-all/digd.png rename to base/all-all/dig068.png diff --git a/base/all-all/dige.png b/base/all-all/dig069.png similarity index 100% rename from base/all-all/dige.png rename to base/all-all/dig069.png diff --git a/base/all-all/digf.png b/base/all-all/dig070.png similarity index 100% rename from base/all-all/digf.png rename to base/all-all/dig070.png diff --git a/base/all-all/digg.png b/base/all-all/dig071.png similarity index 100% rename from base/all-all/digg.png rename to base/all-all/dig071.png diff --git a/base/all-all/digh.png b/base/all-all/dig072.png similarity index 100% rename from base/all-all/digh.png rename to base/all-all/dig072.png diff --git a/base/all-all/digi.png b/base/all-all/dig073.png similarity index 100% rename from base/all-all/digi.png rename to base/all-all/dig073.png diff --git a/base/all-all/digj.png b/base/all-all/dig074.png similarity index 100% rename from base/all-all/digj.png rename to base/all-all/dig074.png diff --git a/base/all-all/digk.png b/base/all-all/dig075.png similarity index 100% rename from base/all-all/digk.png rename to base/all-all/dig075.png diff --git a/base/all-all/digl.png b/base/all-all/dig076.png similarity index 100% rename from base/all-all/digl.png rename to base/all-all/dig076.png diff --git a/base/all-all/digm.png b/base/all-all/dig077.png similarity index 100% rename from base/all-all/digm.png rename to base/all-all/dig077.png diff --git a/base/all-all/dign.png b/base/all-all/dig078.png similarity index 100% rename from base/all-all/dign.png rename to base/all-all/dig078.png diff --git a/base/all-all/digo.png b/base/all-all/dig079.png similarity index 100% rename from base/all-all/digo.png rename to base/all-all/dig079.png diff --git a/base/all-all/digp.png b/base/all-all/dig080.png similarity index 100% rename from base/all-all/digp.png rename to base/all-all/dig080.png diff --git a/base/all-all/digq.png b/base/all-all/dig081.png similarity index 100% rename from base/all-all/digq.png rename to base/all-all/dig081.png diff --git a/base/all-all/digr.png b/base/all-all/dig082.png similarity index 100% rename from base/all-all/digr.png rename to base/all-all/dig082.png diff --git a/base/all-all/digs.png b/base/all-all/dig083.png similarity index 100% rename from base/all-all/digs.png rename to base/all-all/dig083.png diff --git a/base/all-all/digt.png b/base/all-all/dig084.png similarity index 100% rename from base/all-all/digt.png rename to base/all-all/dig084.png diff --git a/base/all-all/digu.png b/base/all-all/dig085.png similarity index 100% rename from base/all-all/digu.png rename to base/all-all/dig085.png diff --git a/base/all-all/digv.png b/base/all-all/dig086.png similarity index 100% rename from base/all-all/digv.png rename to base/all-all/dig086.png diff --git a/base/all-all/digw.png b/base/all-all/dig087.png similarity index 100% rename from base/all-all/digw.png rename to base/all-all/dig087.png diff --git a/base/all-all/digx.png b/base/all-all/dig088.png similarity index 100% rename from base/all-all/digx.png rename to base/all-all/dig088.png diff --git a/base/all-all/digy.png b/base/all-all/dig089.png similarity index 100% rename from base/all-all/digy.png rename to base/all-all/dig089.png diff --git a/base/all-all/digz.png b/base/all-all/dig090.png similarity index 100% rename from base/all-all/digz.png rename to base/all-all/dig090.png diff --git a/base/all-all/dig91.png b/base/all-all/dig091.png similarity index 100% rename from base/all-all/dig91.png rename to base/all-all/dig091.png diff --git a/base/all-all/dig93.png b/base/all-all/dig093.png similarity index 100% rename from base/all-all/dig93.png rename to base/all-all/dig093.png diff --git a/base/all-all/sbardef.lmp b/base/all-all/sbardef.lmp new file mode 100644 index 000000000..65adc53ae --- /dev/null +++ b/base/all-all/sbardef.lmp @@ -0,0 +1,2002 @@ +{ + "type": "statusbar", + "version": "1.1.0", + "metadata": null, + "data": + { + "numberfonts": + [ + { + "name": "BigRed", + "type": 0, + "stem": "STT" + }, + { + "name": "SmallGrey", + "type": 0, + "stem": "STG" + }, + { + "name": "SmallYellow", + "type": 0, + "stem": "STYS" + } + ], + "hudfonts": + [ + { + "name": "Console", + "type": 2, + "stem": "STCFN" + }, + { + "name": "Digits", + "type": 0, + "stem": "DIG" + } + ], + "statusbars": + [ + { + "height": 200, + "fullscreenrender": false, + "fillflat": null, + "children": + [ + { + "graphic": + { + "x": 160, + "y": 168, + "alignment": 1, + "patch": "STBAR", + "tranmap": null, + "translation": null, + "conditions": null, + "children": null + } + }, + { + "facebackground": + { + "x": 143, + "y": 169, + "alignment": 0, + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 15, + "param": 0 + } + ], + "children": null + } + }, + { + "face": + { + "x": 143, + "y": 168, + "alignment": 0, + "tranmap": null, + "translation": null, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 44, + "y": 171, + "alignment": 2, + "font": "BigRed", + "tranmap": null, + "translation": null, + "type": 4, + "param": 0, + "maxlength": 3, + "conditions": + [ + { + "condition": 4, + "param": 0 + } + ], + "children": null + } + }, + { + "percent": + { + "x": 104, + "y": 171, + "alignment": 2, + "font": "BigRed", + "tranmap": null, + "translation": null, + "type": 0, + "param": 0, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "percent": + { + "x": 235, + "y": 171, + "alignment": 2, + "font": "BigRed", + "tranmap": null, + "translation": null, + "type": 1, + "param": 0, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 138, + "y": 171, + "alignment": 2, + "font": "BigRed", + "tranmap": null, + "translation": null, + "type": 2, + "param": 0, + "maxlength": 2, + "conditions": + [ + { + "condition": 14, + "param": 2 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 104, + "y": 168, + "alignment": 0, + "patch": "STARMS", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 15, + "param": 2 + } + ], + "children": + [ + { + "graphic": + { + "x": 7, + "y": 4, + "alignment": 0, + "patch": "STGNUM2", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 7, + "param": 2 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 7, + "y": 4, + "alignment": 0, + "patch": "STYSNUM2", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 6, + "param": 2 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 19, + "y": 4, + "alignment": 0, + "patch": "STGNUM3", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 7, + "param": 3 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 19, + "y": 4, + "alignment": 0, + "patch": "STYSNUM3", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 6, + "param": 3 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 31, + "y": 4, + "alignment": 0, + "patch": "STGNUM4", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 7, + "param": 4 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 31, + "y": 4, + "alignment": 0, + "patch": "STYSNUM4", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 6, + "param": 4 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 7, + "y": 14, + "alignment": 0, + "patch": "STGNUM5", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 7, + "param": 5 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 7, + "y": 14, + "alignment": 0, + "patch": "STYSNUM5", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 6, + "param": 5 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 19, + "y": 14, + "alignment": 0, + "patch": "STGNUM6", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 7, + "param": 6 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 19, + "y": 14, + "alignment": 0, + "patch": "STYSNUM6", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 6, + "param": 6 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 31, + "y": 14, + "alignment": 0, + "patch": "STGNUM7", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 7, + "param": 7 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 31, + "y": 14, + "alignment": 0, + "patch": "STYSNUM7", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 6, + "param": 7 + } + ], + "children": null + } + } + ] + } + }, + { + "number": + { + "x": 288, + "y": 173, + "alignment": 2, + "font": "SmallYellow", + "tranmap": null, + "translation": null, + "type": 3, + "param": 0, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 314, + "y": 173, + "alignment": 2, + "font": "SmallYellow", + "tranmap": null, + "translation": null, + "type": 5, + "param": 0, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 288, + "y": 179, + "alignment": 2, + "font": "SmallYellow", + "tranmap": null, + "translation": null, + "type": 3, + "param": 1, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 314, + "y": 179, + "alignment": 2, + "font": "SmallYellow", + "tranmap": null, + "translation": null, + "type": 5, + "param": 1, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 288, + "y": 185, + "alignment": 2, + "font": "SmallYellow", + "tranmap": null, + "translation": null, + "type": 3, + "param": 3, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 314, + "y": 185, + "alignment": 2, + "font": "SmallYellow", + "tranmap": null, + "translation": null, + "type": 5, + "param": 3, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 288, + "y": 191, + "alignment": 2, + "font": "SmallYellow", + "tranmap": null, + "translation": null, + "type": 3, + "param": 2, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 314, + "y": 191, + "alignment": 2, + "font": "SmallYellow", + "tranmap": null, + "translation": null, + "type": 5, + "param": 2, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 171, + "alignment": 0, + "patch": "STKEYS0", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 1 + }, + { + "condition": 11, + "param": 4 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 171, + "alignment": 0, + "patch": "STKEYS3", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 11, + "param": 1 + }, + { + "condition": 10, + "param": 4 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 171, + "alignment": 0, + "patch": "STKEYS3", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 1 + }, + { + "condition": 10, + "param": 4 + }, + { + "condition": 13, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 171, + "alignment": 0, + "patch": "STKEYS6", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 1 + }, + { + "condition": 10, + "param": 4 + }, + { + "condition": 12, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 181, + "alignment": 0, + "patch": "STKEYS1", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 2 + }, + { + "condition": 11, + "param": 5 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 181, + "alignment": 0, + "patch": "STKEYS4", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 11, + "param": 2 + }, + { + "condition": 10, + "param": 5 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 181, + "alignment": 0, + "patch": "STKEYS4", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 2 + }, + { + "condition": 10, + "param": 5 + }, + { + "condition": 13, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 181, + "alignment": 0, + "patch": "STKEYS7", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 2 + }, + { + "condition": 10, + "param": 5 + }, + { + "condition": 12, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 191, + "alignment": 0, + "patch": "STKEYS2", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 3 + }, + { + "condition": 11, + "param": 6 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 191, + "alignment": 0, + "patch": "STKEYS5", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 11, + "param": 3 + }, + { + "condition": 10, + "param": 6 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 191, + "alignment": 0, + "patch": "STKEYS5", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 3 + }, + { + "condition": 10, + "param": 6 + }, + { + "condition": 13, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 239, + "y": 191, + "alignment": 0, + "patch": "STKEYS8", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 3 + }, + { + "condition": 10, + "param": 6 + }, + { + "condition": 12, + "param": 1 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 2, + "y": 160, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 0, + "font": "Digits", + "conditions": + [ + { + "condition": 19, + "param": 6 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 2, + "y": 153, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 1, + "font": "Digits", + "conditions": + [ + { + "condition": 19, + "param": 6 + }, + { + "condition": 20, + "param": 0 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 2, + "y": 160, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 1, + "font": "Digits", + "conditions": + [ + { + "condition": 19, + "param": 6 + }, + { + "condition": 21, + "param": 0 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 2, + "y": 152, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 0, + "font": "Digits", + "conditions": + [ + { + "condition": 19, + "param": 1 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 2, + "y": 146, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 1, + "font": "Digits", + "conditions": + [ + { + "condition": 19, + "param": 1 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 8, + "alignment": 34, + "tranmap": null, + "translation": null, + "type": 2, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 0, + "alignment": 34, + "tranmap": null, + "translation": null, + "type": 3, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 8, + "alignment": 0, + "tranmap": null, + "translation": null, + "type": 4, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 167, + "alignment": 42, + "tranmap": null, + "translation": null, + "type": 5, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 167, + "alignment": 9, + "tranmap": null, + "translation": null, + "type": 6, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 0, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 7, + "font": "Console", + "duration": 4, + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 52, + "alignment": 1, + "tranmap": null, + "translation": "CRGOLD", + "type": 8, + "font": "Console", + "duration": 2.5, + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 8, + "alignment": 16, + "tranmap": null, + "translation": "CRGOLD", + "type": 9, + "font": "Console", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 160, + "alignment": 16, + "tranmap": null, + "translation": "CRGOLD", + "type": 10, + "font": "Console", + "conditions": + [ + { + "condition": 19, + "param": 1 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 160, + "alignment": 1, + "tranmap": null, + "translation": "CRGOLD", + "type": 10, + "font": "Console", + "conditions": + [ + { + "condition": 19, + "param": 2 + } + ], + "children": null + } + } + ] + }, + { + "height": 200, + "fullscreenrender": true, + "fillflat": null, + "children": + [ + { + "canvas": + { + "x": 0, + "y": 0, + "alignment": 0, + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 18, + "param": 0 + } + ], + "children": + [ + { + "facebackground": + { + "x": 19, + "y": 162, + "alignment": 16, + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 15, + "param": 0 + } + ], + "children": null + } + }, + { + "face": + { + "x": 20, + "y": 161, + "alignment": 16, + "tranmap": null, + "translation": null, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 53, + "y": 175, + "alignment": 16, + "font": "BigRed", + "tranmap": null, + "translation": null, + "type": 0, + "param": 0, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "graphic": + { + "x": 292, + "y": 189, + "alignment": 32, + "patch": "CLIPA0", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 5, + "param": 0 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 295, + "y": 186, + "alignment": 32, + "patch": "SHELA0", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 5, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 297, + "y": 192, + "alignment": 32, + "patch": "FTNKA0", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 5, + "param": 2 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 295, + "y": 195, + "alignment": 32, + "patch": "ROCKA0", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 5, + "param": 3 + } + ], + "children": null + } + }, + { + "number": + { + "x": 285, + "y": 175, + "alignment": 34, + "font": "BigRed", + "tranmap": null, + "translation": null, + "type": 4, + "param": 0, + "maxlength": 3, + "conditions": + [ + { + "condition": 4, + "param": 0 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 125, + "y": 192, + "alignment": 16, + "patch": "ARM1A0", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 11, + "param": 15 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 125, + "y": 192, + "alignment": 16, + "patch": "ARM2A0", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 15 + } + ], + "children": null + } + }, + { + "number": + { + "x": 145, + "y": 175, + "alignment": 16, + "font": "BigRed", + "tranmap": null, + "translation": null, + "type": 1, + "param": 0, + "maxlength": 3, + "conditions": null, + "children": null + } + }, + { + "number": + { + "x": 300, + "y": 5, + "alignment": 34, + "font": "BigRed", + "tranmap": null, + "translation": null, + "type": 2, + "param": 0, + "maxlength": 2, + "conditions": + [ + { + "condition": 14, + "param": 2 + } + ], + "children": null + } + }, + { + "canvas": + { + "x": 310, + "y": 168, + "alignment": 0, + "tranmap": null, + "translation": null, + "conditions": null, + "children": + [ + { + "graphic": + { + "x": 0, + "y": 0, + "alignment": 32, + "patch": "STKEYS0", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 1 + }, + { + "condition": 11, + "param": 4 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 0, + "alignment": 32, + "patch": "STKEYS3", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 11, + "param": 1 + }, + { + "condition": 10, + "param": 4 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 0, + "alignment": 32, + "patch": "STKEYS3", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 1 + }, + { + "condition": 10, + "param": 4 + }, + { + "condition": 13, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 0, + "alignment": 32, + "patch": "STKEYS6", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 1 + }, + { + "condition": 10, + "param": 4 + }, + { + "condition": 12, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 10, + "alignment": 32, + "patch": "STKEYS1", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 2 + }, + { + "condition": 11, + "param": 5 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 10, + "alignment": 32, + "patch": "STKEYS4", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 11, + "param": 2 + }, + { + "condition": 10, + "param": 5 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 10, + "alignment": 32, + "patch": "STKEYS4", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 2 + }, + { + "condition": 10, + "param": 5 + }, + { + "condition": 13, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 10, + "alignment": 32, + "patch": "STKEYS7", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 2 + }, + { + "condition": 10, + "param": 5 + }, + { + "condition": 12, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 20, + "alignment": 32, + "patch": "STKEYS2", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 3 + }, + { + "condition": 11, + "param": 6 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 20, + "alignment": 32, + "patch": "STKEYS5", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 11, + "param": 3 + }, + { + "condition": 10, + "param": 6 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 20, + "alignment": 32, + "patch": "STKEYS5", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 3 + }, + { + "condition": 10, + "param": 6 + }, + { + "condition": 13, + "param": 1 + } + ], + "children": null + } + }, + { + "graphic": + { + "x": 0, + "y": 20, + "alignment": 32, + "patch": "STKEYS8", + "tranmap": null, + "translation": null, + "conditions": + [ + { + "condition": 10, + "param": 3 + }, + { + "condition": 10, + "param": 6 + }, + { + "condition": 12, + "param": 1 + } + ], + "children": null + } + } + ] + } + }, + { + "widget": + { + "x": 20, + "y": 154, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 0, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 20, + "y": 147, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 1, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 8, + "alignment": 34, + "tranmap": null, + "translation": null, + "type": 2, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 0, + "alignment": 34, + "tranmap": null, + "translation": null, + "type": 3, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 8, + "alignment": 0, + "tranmap": null, + "translation": null, + "type": 4, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 167, + "alignment": 42, + "tranmap": null, + "translation": null, + "type": 5, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 167, + "alignment": 9, + "tranmap": null, + "translation": null, + "type": 6, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 0, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 7, + "font": "Console", + "duration": 4, + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 68, + "alignment": 1, + "tranmap": null, + "translation": "CRGOLD", + "type": 8, + "font": "Console", + "duration": 2.5, + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 8, + "alignment": 16, + "tranmap": null, + "translation": "CRGOLD", + "type": 9, + "font": "Console", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 200, + "alignment": 9, + "tranmap": null, + "translation": "CRGOLD", + "type": 10, + "font": "Console", + "conditions": + [ + { + "condition": 19, + "param": 2 + } + ], + "children": null + } + } + ] + } + } + ] + }, + { + "height": 200, + "fullscreenrender": true, + "fillflat": null, + "children": + [ + { + "widget": + { + "x": 0, + "y": 192, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 0, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 184, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 1, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 8, + "alignment": 34, + "tranmap": null, + "translation": null, + "type": 2, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 0, + "alignment": 34, + "tranmap": null, + "translation": null, + "type": 3, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 8, + "alignment": 0, + "tranmap": null, + "translation": null, + "type": 4, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 200, + "alignment": 42, + "tranmap": null, + "translation": null, + "type": 5, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 200, + "alignment": 9, + "tranmap": null, + "translation": null, + "type": 6, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 0, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 7, + "font": "Console", + "duration": 4, + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 68, + "alignment": 1, + "tranmap": null, + "translation": "CRGOLD", + "type": 8, + "font": "Console", + "duration": 2.5, + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 8, + "alignment": 16, + "tranmap": null, + "translation": "CRGOLD", + "type": 9, + "font": "Console", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 200, + "alignment": 9, + "tranmap": null, + "translation": "CRGOLD", + "type": 10, + "font": "Console", + "conditions": + [ + { + "condition": 19, + "param": 2 + } + ], + "children": null + } + } + ] + } + ] + } +} diff --git a/base/all-all/sbhuddef.lmp b/base/all-all/sbhuddef.lmp new file mode 100644 index 000000000..678e58cb4 --- /dev/null +++ b/base/all-all/sbhuddef.lmp @@ -0,0 +1,257 @@ +{ + "type": "hud", + "version": "1.0.0", + "data": + { + "hudfonts": + [ + { + "name": "Console", + "type": 2, + "stem": "STCFN" + }, + { + "name": "Digits", + "type": 0, + "stem": "DIG" + } + ], + "widgets": + [ + { + "widget": + { + "x": 2, + "y": 160, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 0, + "font": "Digits", + "conditions": + [ + { + "condition": 19, + "param": 6 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 2, + "y": 153, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 1, + "font": "Digits", + "conditions": + [ + { + "condition": 19, + "param": 6 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 2, + "y": 152, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 0, + "font": "Digits", + "conditions": + [ + { + "condition": 19, + "param": 1 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 2, + "y": 146, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 1, + "font": "Digits", + "conditions": + [ + { + "condition": 19, + "param": 1 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 8, + "alignment": 34, + "tranmap": null, + "translation": null, + "type": 2, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 0, + "alignment": 34, + "tranmap": null, + "translation": null, + "type": 3, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 8, + "alignment": 0, + "tranmap": null, + "translation": null, + "type": 4, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 320, + "y": 167, + "alignment": 42, + "tranmap": null, + "translation": null, + "type": 5, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 167, + "alignment": 9, + "tranmap": null, + "translation": null, + "type": 6, + "font": "Digits", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 0, + "alignment": 16, + "tranmap": null, + "translation": null, + "type": 7, + "font": "Console", + "duration": 4, + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 52, + "alignment": 1, + "tranmap": null, + "translation": "CRGOLD", + "type": 8, + "font": "Console", + "duration": 2.5, + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 8, + "alignment": 16, + "tranmap": null, + "translation": "CRGOLD", + "type": 9, + "font": "Console", + "conditions": null, + "children": null + } + }, + { + "widget": + { + "x": 0, + "y": 160, + "alignment": 16, + "tranmap": null, + "translation": "CRGOLD", + "type": 10, + "font": "Console", + "conditions": + [ + { + "condition": 19, + "param": 1 + } + ], + "children": null + } + }, + { + "widget": + { + "x": 160, + "y": 160, + "alignment": 1, + "tranmap": null, + "translation": "CRGOLD", + "type": 10, + "font": "Console", + "conditions": + [ + { + "condition": 19, + "param": 2 + } + ], + "children": null + } + } + ] + } +} diff --git a/base/all-all/woofhud.lmp b/base/all-all/woofhud.lmp deleted file mode 100644 index d661da369..000000000 --- a/base/all-all/woofhud.lmp +++ /dev/null @@ -1,37 +0,0 @@ -hud 0 -rate topleft -compact bottomleft -monsec topleft -sttime topleft -coord topright -fps topright -cmd bottomright -speed bottomcenter - -hud 1 -rate topleft -armor bottomleft -health bottomleft -ammo bottomleft -weapon bottomleft -keys bottomleft -monsec bottomleft -sttime bottomleft -coord topright -fps topright -cmd bottomright -speed bottomcenter - -hud 2 -rate topleft -health topright -armor topright -ammo bottomright -weapon bottomright -keys bottomleft -monsec bottomleft -sttime bottomleft -coord topright -fps topright -cmd bottomright -speed bottomcenter diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 7d8c03f3d..32889ff74 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -5,9 +5,7 @@ set(WOOF_DOCS mbf.txt mbfedit.txt mbffaq.txt - options.txt - woofhud.lmp - woofhud.md) + options.txt) if(WIN32) install(FILES ${WOOF_DOCS} DESTINATION docs) diff --git a/docs/woofhud.lmp b/docs/woofhud.lmp deleted file mode 100644 index 9187e0e77..000000000 --- a/docs/woofhud.lmp +++ /dev/null @@ -1,33 +0,0 @@ -// Copy this to autoload/doom-all for alternative HUD arrangements. -// Thanks @liPillON . - -hud 0 -title topleft -coords topright -fps topright -stats bottomright -time bottomright - -hud 1 -title topleft -coords topright -fps topright -armor bottomleft -health bottomleft -ammo bottomleft -weapons bottomleft -keys bottomleft -stats bottomright -time bottomright - -hud 2 -title topleft -stats topright -time topright -coords topright -fps topright -keys bottomleft -health bottomleft -armor bottomleft -weapons bottomright -ammo bottomright diff --git a/docs/woofhud.md b/docs/woofhud.md deleted file mode 100644 index 0a9b0ee78..000000000 --- a/docs/woofhud.md +++ /dev/null @@ -1,121 +0,0 @@ -# WOOFHUD - -Woof! supports the WOOFHUD lump to customize the appearance of the extended Boom HUD. - -## Description - -The Boom HUD shows information about the player's health, armor, weapons, ammo and keys using different widgets, i.e. lines of text and symbols. It is usually made visible by hitting the F5 key, and repeatedly hitting the F5 key toggles through three different modes: the "minimal" mode which shows only the most basic information, the "compact" mode which shows all information in the lower left corner of the screen and the "distributed" mode which shows information spread across the corners of the screen. - -The WOOFHUD lump can be used to modify the positions of these widgets for each mode. -This lump may either get embedded into a PWAD, or provided by the user on the command line or through the autoload feature. - -## Format - -The WOOFHUD lump is in text format and consists of paragraphs, which are separated by blank lines. Each paragraph begins with a line starting with the keyword `hud` and a number for the HUD mode which is to be modified: `0` for minimal, `1` for compact and `2` for distributed. -The following lines start with the name of the HUD widget which is to be positioned followed by either a keyword giving the position relative to the screen or two numbers giving the absolute X and Y screen coordinates. - -Possible values for the HUD widget names: - - * "title" or "levelname" - * "message" - * "secret" - * "armor" - * "health" - * "ammo" - * "weapon" or "weapons" - * "keys" - * "monsec" or "stats" - * "sttime" or "time" - * "coord" or "coords" - * "fps" or "rate" - * "cmd" or "commands" - * "compact" - * "speed" - -Possible values for the widget position keywords: - - * "topleft" or "upperleft" - * "topright" or "upperright" - * "topcenter" or "uppercenter" - * "bottomleft" or "lowerleft" - * "bottomright" or "lowerright" - * "bottomcenter" or "lowercenter" - -When using relative screen positioning, the widgets are aligned "first come, first serve". For example, the first widget in a paragraph that is aligned with the "bottomleft" keyword will end up in the very bottom-left area of the screen and each following widget that is aligned with the same keyword will get stacked one line above. - -Absolute X and Y screen coordinates are limited to the low-resolution non-widescreen visible area of the screen, i.e. `0 <= X < 320` and `0 <= Y < 200`. Negative values will get interpreted relative to the right or lower edges of the screen, respectively. If the "Widescreen Widget Arrangement" feature is enabled, widgets will get aligned with respect to the widescreen area of the screen (new in Woof! 14.0.0). - -## Examples - -The following example represents the current default alignments of the Boom HUD widgets: - -``` -hud 0 -rate topleft -compact bottomleft -monsec topleft -sttime topleft -coord topright -fps topright -cmd bottomright -speed bottomcenter - -hud 1 -rate topleft -armor bottomleft -health bottomleft -ammo bottomleft -weapon bottomleft -keys bottomleft -monsec bottomleft -sttime bottomleft -coord topright -fps topright -cmd bottomright -speed bottomcenter - -hud 2 -rate topleft -health topright -armor topright -ammo bottomright -weapon bottomright -keys bottomleft -monsec bottomleft -sttime bottomleft -coord topright -fps topright -cmd bottomright -speed bottomcenter -``` - -An alternative approach to the distributed HUD, using absolute screen coordinates, could look like this: - -``` -hud 2 -health 224 0 -armor 224 8 -ammo 200 -8 -weapon 200 -16 -keys 2 -8 -monsec 2 8 -sttime 2 16 -coord 200 8 -fps 224 16 -``` - -## Remarks - -The "title" widget is only visible if the Automap is enabled. The "monsec", "sttime" and "coord" widgets are only visible if they are explicitly enabled in the Options menu (separately for Automap and HUD). The "fps" widget is only visible if the SHOWFPS cheat is enabled. - -The "speed" widget is only visible if the SPEED cheat is enabled. Repeating the cheat cycles through different units. - -The "compact" widget is a minimal widget showing only health, armor and ammo information. It is enabled by default in the minimal Boom HUD mode. - -A centered widget does not allow for any other left or right aligned widget on the same line. - -HUD modes without a paragraph remain unchanged. Widgets which are not mentioned in a paragraph will *never* be visible in the respective HUD mode. So, it is a good idea to *always* include the five widgets which make up the `hud 0` paragraph in the example above in *any* other paragraph. -The Vanilla Doom widgets (i.e. "title", "message", "secret"), however, will *always* be visible, whether they are explicitly mentioned in a paragraph or not (new in Woof! 12.0.0). - -It is currently impossible to use the WOOFHUD lump to modify the appearance of the Status Bar or the Crispy HUD. However, when using the Crispy HUD or the Automap, the visible widgets will align corresponding to the last active HUD mode. - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4f65b3cef..a01565cdb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,9 +28,7 @@ set(WOOF_SOURCES hu_command.c hu_command.h hu_coordinates.c hu_coordinates.h hu_crosshair.c hu_crosshair.h - hu_lib.c hu_lib.h hu_obituary.c hu_obituary.h - hu_stuff.c hu_stuff.h i_3dsound.c i_endoom.c i_endoom.h i_flickstick.c i_flickstick.h @@ -129,8 +127,9 @@ set(WOOF_SOURCES s_musinfo.c s_musinfo.h s_sound.c s_sound.h sounds.c sounds.h - st_lib.c st_lib.h + st_sbardef.c st_sbardef.h st_stuff.c st_stuff.h + st_widgets.c st_widgets.h statdump.c statdump.h tables.c tables.h u_mapinfo.c u_mapinfo.h @@ -282,11 +281,13 @@ if(MSVC) target_link_options(woof-setup PRIVATE "/MANIFEST:NO") endif() -add_custom_command(TARGET woof POST_BUILD +add_custom_target(woof-base COMMAND ${CMAKE_COMMAND} -E tar cf - "$/woof.pk3" --format=zip . + "${CMAKE_CURRENT_BINARY_DIR}/woof.pk3" --format=zip . WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/base") +add_dependencies(woof woof-base) + # Install # # Rename woof-com and woof-exe executables. @@ -313,9 +314,10 @@ if(WIN32) else() install(TARGETS woof woof-setup RUNTIME DESTINATION .) endif() - install(FILES "$/woof.com" DESTINATION .) - install(FILES "$/woof.exe" DESTINATION .) - install(FILES "$/woof.pk3" DESTINATION .) + install(FILES "$/woof.com" + "$/woof.exe" + "$/woof.pk3" + DESTINATION .) else() install(TARGETS woof woof-setup RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES "$/woof.pk3" diff --git a/src/am_map.c b/src/am_map.c index 51bd00722..9bd8afdbb 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -28,7 +28,6 @@ #include "doomdef.h" #include "doomstat.h" #include "doomtype.h" -#include "hu_stuff.h" #include "i_video.h" #include "m_config.h" #include "m_input.h" @@ -39,11 +38,11 @@ #include "p_setup.h" #include "p_spec.h" #include "r_defs.h" -#include "r_draw.h" #include "r_main.h" #include "r_state.h" #include "r_things.h" #include "st_stuff.h" +#include "st_widgets.h" #include "tables.h" #include "v_flextran.h" #include "v_fmt.h" @@ -2381,12 +2380,6 @@ void AM_ColorPreset(void) *mapcolors[i].var = mapcolors[i].color[mapcolor_preset]; } - // [FG] immediately apply changes if the automap is visible through the menu - if (automapactive && menu_backdrop != MENU_BG_TEXTURE) - { - HU_Start(); - } - // [crispy] Make secret wall colors independent from PLAYPAL color indexes if (mapcolor_preset == AM_PRESET_CRISPY) { diff --git a/src/d_items.c b/src/d_items.c index d0c9f85d2..7c8612939 100644 --- a/src/d_items.c +++ b/src/d_items.c @@ -44,8 +44,9 @@ weaponinfo_t weaponinfo[NUMWEAPONS+2] = S_NULL, 1, 0, - WPF_FLEEMELEE | WPF_AUTOSWITCHFROM | WPF_NOAUTOSWITCHTO - }, + WPF_FLEEMELEE | WPF_AUTOSWITCHFROM | WPF_NOAUTOSWITCHTO, + 1 + }, { // pistol am_clip, @@ -56,8 +57,9 @@ weaponinfo_t weaponinfo[NUMWEAPONS+2] = S_PISTOLFLASH, 1, 0, - WPF_AUTOSWITCHFROM - }, + WPF_AUTOSWITCHFROM, + 2 + }, { // shotgun am_shell, @@ -68,7 +70,8 @@ weaponinfo_t weaponinfo[NUMWEAPONS+2] = S_SGUNFLASH1, 1, 0, - WPF_NOFLAG + WPF_NOFLAG, + 3 }, { // chaingun @@ -80,7 +83,8 @@ weaponinfo_t weaponinfo[NUMWEAPONS+2] = S_CHAINFLASH1, 1, 0, - WPF_NOFLAG + WPF_NOFLAG, + 4 }, { // missile launcher @@ -92,7 +96,8 @@ weaponinfo_t weaponinfo[NUMWEAPONS+2] = S_MISSILEFLASH1, 1, 0, - WPF_NOAUTOFIRE + WPF_NOAUTOFIRE, + 5 }, { // plasma rifle @@ -104,7 +109,8 @@ weaponinfo_t weaponinfo[NUMWEAPONS+2] = S_PLASMAFLASH1, 1, 0, - WPF_NOFLAG + WPF_NOFLAG, + 6 }, { // bfg 9000 @@ -116,7 +122,8 @@ weaponinfo_t weaponinfo[NUMWEAPONS+2] = S_BFGFLASH1, 40, 0, - WPF_NOAUTOFIRE + WPF_NOAUTOFIRE, + 7 }, { // chainsaw @@ -128,7 +135,8 @@ weaponinfo_t weaponinfo[NUMWEAPONS+2] = S_NULL, 1, 0, - WPF_NOTHRUST | WPF_FLEEMELEE | WPF_NOAUTOSWITCHTO + WPF_NOTHRUST | WPF_FLEEMELEE | WPF_NOAUTOSWITCHTO, + 1 }, { // super shotgun @@ -140,8 +148,9 @@ weaponinfo_t weaponinfo[NUMWEAPONS+2] = S_DSGUNFLASH1, 2, 0, - WPF_NOFLAG - }, + WPF_NOFLAG, + 3 + }, { 0 }, diff --git a/src/d_items.h b/src/d_items.h index 20e8abb3a..a120a69b9 100644 --- a/src/d_items.h +++ b/src/d_items.h @@ -57,6 +57,8 @@ typedef struct int ammopershot; int intflags; int flags; + // id24 + int slot; } weaponinfo_t; extern weaponinfo_t weaponinfo[NUMWEAPONS+2]; diff --git a/src/d_main.c b/src/d_main.c index 59ff075db..c0ad1a4b8 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -43,9 +43,7 @@ #include "f_finale.h" #include "f_wipe.h" #include "g_game.h" -#include "hu_stuff.h" #include "i_endoom.h" -#include "i_gamepad.h" #include "i_glob.h" #include "i_input.h" #include "i_printf.h" @@ -78,6 +76,7 @@ #include "s_sound.h" #include "sounds.h" #include "st_stuff.h" +#include "st_widgets.h" #include "statdump.h" #include "u_mapinfo.h" #include "v_fmt.h" @@ -255,16 +254,14 @@ void D_Display (void) { static boolean viewactivestate = false; static boolean menuactivestate = false; - static boolean inhelpscreensstate = false; - static boolean fullscreen = false; static gamestate_t oldgamestate = GS_NONE; static int borderdrawcount; int wipestart; - boolean done, wipe, redrawsbar; + boolean done, wipe; if (demobar && PLAYBACK_SKIP) { - if (HU_DemoProgressBar(false)) + if (ST_DemoProgressBar(false)) { I_FinishUpdate(); return; @@ -285,8 +282,6 @@ void D_Display (void) } } - redrawsbar = false; - wipe = false; // save the current screen if about to wipe @@ -315,7 +310,7 @@ void D_Display (void) } if (gamestate == GS_LEVEL && gametic) - HU_Erase(); + ST_Erase(); switch (gamestate) // do buffered drawing { @@ -324,24 +319,14 @@ void D_Display (void) break; if (automapactive) { - static overlay_t last_automapoverlay; if (!automapoverlay) { // [FG] update automap while playing R_RenderPlayerView(&players[displayplayer]); AM_Drawer(); - if (last_automapoverlay && scaledviewheight == 200) - { - redrawsbar = true; - } } - last_automapoverlay = automapoverlay; + ST_Drawer(); } - if (wipe || (scaledviewheight != 200 && fullscreen) // killough 11/98 - || (inhelpscreensstate && !inhelpscreens)) - redrawsbar = true; // just put away the help screen - ST_Drawer(scaledviewheight == 200, redrawsbar ); // killough 11/98 - fullscreen = scaledviewheight == 200; // killough 11/98 break; case GS_INTERMISSION: WI_Drawer(); @@ -358,10 +343,10 @@ void D_Display (void) // draw the view directly if (gamestate == GS_LEVEL && automap_off && gametic) - R_RenderPlayerView (&players[displayplayer]); - - if (gamestate == GS_LEVEL && gametic) - HU_Drawer (); + { + R_RenderPlayerView(&players[displayplayer]); + ST_Drawer(); + } // clean up border stuff if (gamestate != oldgamestate && gamestate != GS_LEVEL) @@ -381,26 +366,23 @@ void D_Display (void) borderdrawcount = 3; if (borderdrawcount) { - R_DrawViewBorder (); // erase old menu stuff - HU_Drawer (); + R_DrawViewBorder(); // erase old menu stuff + ST_Drawer(); borderdrawcount--; } } menuactivestate = menuactive; viewactivestate = viewactive; - inhelpscreensstate = inhelpscreens; oldgamestate = wipegamestate = gamestate; if (gamestate == GS_LEVEL && automapactive && automapoverlay) { AM_Drawer(); - ST_Drawer(scaledviewheight == 200, redrawsbar); - HU_Drawer(); + ST_Drawer(); - // [crispy] force redraw of status bar and border + // [crispy] force redraw of border viewactivestate = false; - inhelpscreensstate = true; } // draw pause pic @@ -423,7 +405,7 @@ void D_Display (void) NetUpdate(); // send out any new accumulation if (demobar && demoplayback) - HU_DemoProgressBar(true); + ST_DemoProgressBar(true); // normal update if (!wipe) @@ -861,7 +843,7 @@ static boolean FileContainsMaps(const char *filename) { for (int m = 1; m < 35; ++m) { - if (CheckMapLump(MAPNAME(1, m), filename)) + if (CheckMapLump(MapName(1, m), filename)) { return true; } @@ -873,7 +855,7 @@ static boolean FileContainsMaps(const char *filename) { for (int m = 1; m < 10; ++m) { - if (CheckMapLump(MAPNAME(e, m), filename)) + if (CheckMapLump(MapName(e, m), filename)) { return true; } @@ -2448,12 +2430,10 @@ void D_DoomMain(void) S_Init(snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ ); I_Printf(VB_INFO, "HU_Init: Setting up heads up display."); - HU_Init(); - MN_SetHUFontKerning(); I_Printf(VB_INFO, "ST_Init: Init status bar."); ST_Init(); - ST_Warnings(); + MN_SetHUFontKerning(); // andrewj: voxel support I_Printf(VB_INFO, "VX_Init: "); diff --git a/src/doomdef.h b/src/doomdef.h index 2c457e746..d86e22759 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -176,6 +176,33 @@ typedef enum { NUMPOWERS, } powertype_t; +typedef enum +{ + item_noitem = -1, + item_messageonly, + item_bluecard, + item_yellowcard, + item_redcard, + item_blueskull, + item_yellowskull, + item_redskull, + item_backpack, + item_healthbonus, + item_stimpack, + item_medikit, + item_soulsphere, + item_megasphere, + item_armorbonus, + item_greenarmor, + item_bluearmor, + item_areamap, + item_lightamp, + item_berserk, + item_invisibility, + item_radsuit, + item_invulnerability, +} itemtype_t; + // Power up durations (how many seconds till expiration). typedef enum { INVULNTICS = (30*TICRATE), diff --git a/src/doomstat.c b/src/doomstat.c index 0ff988b0f..dea3dd6aa 100644 --- a/src/doomstat.c +++ b/src/doomstat.c @@ -119,7 +119,7 @@ int center_weapon; int view_bobbing_pct; int weapon_bobbing_pct; -char *MAPNAME(int e, int m) +char *MapName(int e, int m) { static char name[9]; diff --git a/src/doomstat.h b/src/doomstat.h index 51211d1be..cb5ebdf16 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -63,7 +63,7 @@ typedef struct extern GameVersions_t gameversions[]; -extern char *MAPNAME(int e, int m); +extern char *MapName(int e, int m); // Set if homebrew PWAD stuff has been added. extern boolean modifiedgame; diff --git a/src/f_finale.c b/src/f_finale.c index 788febe3c..1bb1ae621 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -27,7 +27,6 @@ #include "doomstat.h" #include "doomtype.h" #include "g_game.h" -#include "hu_lib.h" #include "info.h" #include "m_misc.h" // [FG] M_StringDuplicate() #include "m_swap.h" @@ -35,6 +34,8 @@ #include "r_state.h" #include "s_sound.h" #include "sounds.h" +#include "st_sbardef.h" +#include "st_stuff.h" #include "u_mapinfo.h" #include "v_fmt.h" #include "v_video.h" diff --git a/src/g_game.c b/src/g_game.c index 3485e5637..a89bd00a1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -40,8 +40,8 @@ #include "doomtype.h" #include "f_finale.h" #include "g_game.h" +#include "hu_command.h" #include "hu_obituary.h" -#include "hu_stuff.h" #include "i_gamepad.h" #include "i_gyro.h" #include "i_input.h" @@ -83,6 +83,7 @@ #include "s_sound.h" #include "sounds.h" #include "st_stuff.h" +#include "st_widgets.h" #include "statdump.h" // [FG] StatCopy() #include "tables.h" #include "u_mapinfo.h" @@ -819,7 +820,7 @@ void G_BuildTiccmd(ticcmd_t* cmd) // Buttons - cmd->chatchar = HU_dequeueChatChar(); + cmd->chatchar = ST_DequeueChatChar(); if (M_InputGameActive(input_fire)) cmd->buttons |= BT_ATTACK; @@ -1058,9 +1059,6 @@ static void G_DoLoadLevel(void) { displayplayer = consoleplayer; // view the guy you are playing } - // [Alaux] Update smooth count values - st_health = players[displayplayer].health; - st_armor = players[displayplayer].armorpoints; gameaction = ga_nothing; // Set the initial listener parameters using the player's initial state. @@ -1077,7 +1075,6 @@ static void G_DoLoadLevel(void) //jff 4/26/98 wake up the status bar in case were coming out of a DM demo // killough 5/13/98: in case netdemo has consoleplayer other than green ST_Start(); - HU_Start(); // killough: make -timedemo work on multilevel demos // Move to end of function to minimize noise -- killough 2/22/98: @@ -1207,7 +1204,7 @@ int G_GotoNextLevel(int *pEpi, int *pMap) !demorecording && !demoplayback && !menuactive) { - char *name = MAPNAME(epsd, map); + char *name = MapName(epsd, map); if (W_CheckNumForName(name) == -1) displaymsg("Next level not found: %s", name); @@ -1328,8 +1325,7 @@ boolean G_Responder(event_t* ev) // killough 9/29/98: reformatted if (gamestate == GS_LEVEL - && (HU_Responder(ev) || // chat ate the event - ST_Responder(ev) || // status window ate it + && (ST_Responder(ev) || // status window ate it AM_Responder(ev) || // automap ate it WS_Responder(ev))) // weapon slots ate it { @@ -1355,7 +1351,6 @@ boolean G_Responder(event_t* ev) while (!playeringame[displayplayer] && displayplayer!=consoleplayer); ST_Start(); // killough 3/7/98: switch status bar views too - HU_Start(); S_UpdateSounds(players[displayplayer].mo); // [crispy] re-init automap variables for correct player arrow angle if (automapactive) @@ -1704,7 +1699,7 @@ static void G_WriteLevelStat(void) } } - strcpy(levelString, MAPNAME(gameepisode, gamemap)); + strcpy(levelString, MapName(gameepisode, gamemap)); G_FormatLevelStatTime(levelTimeString, leveltime, false); G_FormatLevelStatTime(totalTimeString, totalleveltimes + leveltime, true); @@ -1756,9 +1751,6 @@ static void G_DoCompleted(void) if (automapactive) AM_Stop(); - // Rebuild the Time widget to get rid of the Use-button timer - HU_widget_rebuild_sttime(); - wminfo.nextep = wminfo.epsd = gameepisode -1; wminfo.last = gamemap -1; @@ -2384,7 +2376,7 @@ static uint64_t G_Signature(int sig_epi, int sig_map) int lump, i; char name[9]; - strcpy(name, MAPNAME(sig_epi, sig_map)); + strcpy(name, MapName(sig_epi, sig_map)); lump = W_CheckNumForName(name); @@ -2698,11 +2690,6 @@ static void G_DoLoadGame(void) // done Z_Free(savebuffer); - // [Alaux] Update smooth count values; - // the same procedure is done in G_LoadLevel, but we have to repeat it here - st_health = players[displayplayer].health; - st_armor = players[displayplayer].armorpoints; - if (setsizeneeded) R_ExecuteSetViewSize(); @@ -2943,7 +2930,7 @@ void G_Ticker(void) // killough 9/29/98: split up switch statement // into pauseable and unpauseable parts. - gamestate == GS_LEVEL ? P_Ticker(), ST_Ticker(), AM_Ticker(), HU_Ticker() : + gamestate == GS_LEVEL ? P_Ticker(), ST_Ticker(), AM_Ticker() : paused & 2 ? (void) 0 : gamestate == GS_INTERMISSION ? WI_Ticker() : gamestate == GS_FINALE ? F_Ticker() : @@ -3792,7 +3779,7 @@ mapentry_t *G_LookupMapinfo(int episode, int map) int i; char lumpname[9]; - strcpy(lumpname, MAPNAME(episode, map)); + strcpy(lumpname, MapName(episode, map)); for (i = 0; i < U_mapinfo.mapcount; i++) { @@ -3826,13 +3813,13 @@ int G_ValidateMapName(const char *mapname, int *pEpi, int *pMap) { if (sscanf(mapuname, "E%dM%d", &epi, &map) != 2) return 0; - strcpy(lumpname, MAPNAME(epi, map)); + strcpy(lumpname, MapName(epi, map)); } else { if (sscanf(mapuname, "MAP%d", &map) != 1) return 0; - strcpy(lumpname, MAPNAME(epi = 1, map)); + strcpy(lumpname, MapName(epi = 1, map)); } if (epi > 4) @@ -3868,7 +3855,7 @@ void G_InitNew(skill_t skill, int episode, int map) episode = 1; // Disable all sanity checks if there are custom episode definitions. They do not make sense in this case. - if (!EpiCustom && W_CheckNumForName(MAPNAME(episode, map)) == -1) + if (!EpiCustom && W_CheckNumForName(MapName(episode, map)) == -1) { if (gamemode == retail) diff --git a/src/hu_command.c b/src/hu_command.c index 0e995da2c..cb3bfc3b7 100644 --- a/src/hu_command.c +++ b/src/hu_command.c @@ -21,8 +21,9 @@ #include "d_event.h" #include "doomstat.h" #include "hu_command.h" -#include "i_printf.h" #include "m_misc.h" +#include "st_sbardef.h" +#include "st_widgets.h" #include "v_video.h" boolean hud_command_history; @@ -267,13 +268,14 @@ void HU_UpdateCommandHistory(const ticcmd_t *cmd) UpdateHudCmdText(current); } -void HU_BuildCommandHistory(hu_multiline_t *const multiline) +void HU_BuildCommandHistory(sbe_widget_t *widget) { hud_cmd_item_t *hud_cmd = current; + ST_ClearLines(widget); for (int i = 0; i < hud_command_history_size; i++) { - HUlib_add_string_keep_space(multiline, hud_cmd->buf); + ST_AddLine(widget, hud_cmd->buf); hud_cmd = hud_cmd->prev; } } diff --git a/src/hu_command.h b/src/hu_command.h index 8ed1a420d..4cefc1fb5 100644 --- a/src/hu_command.h +++ b/src/hu_command.h @@ -20,10 +20,9 @@ #define __HU_COMMAND__ #include "doomtype.h" -#include "hu_lib.h" -struct hu_multiline_s; struct ticcmd_s; +struct sbe_widget_s; extern boolean hud_command_history; extern int hud_command_history_size; @@ -33,6 +32,6 @@ void HU_UpdateTurnFormat(void); void HU_InitCommandHistory(void); void HU_ResetCommandHistory(void); void HU_UpdateCommandHistory(const struct ticcmd_s *cmd); -void HU_BuildCommandHistory(struct hu_multiline_s *const multiline); +void HU_BuildCommandHistory(struct sbe_widget_s *widget); #endif diff --git a/src/hu_coordinates.c b/src/hu_coordinates.c index 092e31893..24bc05ab5 100644 --- a/src/hu_coordinates.c +++ b/src/hu_coordinates.c @@ -21,6 +21,8 @@ #include "hu_coordinates.h" #include "m_misc.h" #include "p_mobj.h" +#include "st_sbardef.h" +#include "st_widgets.h" #include "v_video.h" #define THRESH_M1 15.11 @@ -92,7 +94,7 @@ static split_angle_t SplitAngle(angle_t x) return result; } -static void BuildString(hu_multiline_t *const w_coord, char *buf, int len, +static void BuildString(sbe_widget_t *widget, char *buf, int len, int pos) { if (WIDGET_WIDTH > pos) @@ -100,10 +102,10 @@ static void BuildString(hu_multiline_t *const w_coord, char *buf, int len, M_snprintf(buf + pos, len - pos, "%-*s", WIDGET_WIDTH - pos, ""); } - HUlib_add_string_keep_space(w_coord, buf); + ST_AddLine(widget, buf); } -static void FixedToString(hu_multiline_t *const w_coord, const char *label, +static void FixedToString(sbe_widget_t *widget, const char *label, fixed_t x, char *buf, int len, int pos) { const split_fixed_t value = SplitFixed(x); @@ -120,10 +122,10 @@ static void FixedToString(hu_multiline_t *const w_coord, const char *label, pos += M_snprintf(buf + pos, len - pos, "%s: %d", label, value.base); } - BuildString(w_coord, buf, len, pos); + BuildString(widget, buf, len, pos); } -static void AngleToString(hu_multiline_t *const w_coord, const char *label, +static void AngleToString(sbe_widget_t *widget, const char *label, angle_t x, char *buf, int len, int pos) { const split_angle_t value = SplitAngle(x); @@ -138,10 +140,10 @@ static void AngleToString(hu_multiline_t *const w_coord, const char *label, pos += M_snprintf(buf + pos, len - pos, "%s: %d", label, value.base); } - BuildString(w_coord, buf, len, pos); + BuildString(widget, buf, len, pos); } -static void MagnitudeToString(hu_multiline_t *const w_coord, const char *label, +static void MagnitudeToString(sbe_widget_t *widget, const char *label, double x, char *buf, int len, int pos) { if (x) @@ -153,10 +155,10 @@ static void MagnitudeToString(hu_multiline_t *const w_coord, const char *label, pos += M_snprintf(buf + pos, len - pos, "%s: 0", label); } - BuildString(w_coord, buf, len, pos); + BuildString(widget, buf, len, pos); } -static void ComponentToString(hu_multiline_t *const w_coord, const char *label, +static void ComponentToString(sbe_widget_t *widget, const char *label, fixed_t x, char *buf, int len, int pos) { const split_fixed_t value = SplitFixed(x); @@ -173,41 +175,61 @@ static void ComponentToString(hu_multiline_t *const w_coord, const char *label, pos += M_snprintf(buf + pos, len - pos, "%s: %d", label, value.base); } - BuildString(w_coord, buf, len, pos); + BuildString(widget, buf, len, pos); } -void HU_BuildCoordinatesEx(hu_multiline_t *const w_coord, const mobj_t *mo, - char *buf, int len) +void HU_BuildCoordinatesEx(sbe_widget_t *widget, const mobj_t *mo) { int pos; double magnitude; crange_idx_e color; + ST_ClearLines(widget); + + #define LINE_SIZE 60 + // Coordinates. - pos = M_snprintf(buf, len, "\x1b%c", '0' + CR_GREEN); - FixedToString(w_coord, "X", mo->x, buf, len, pos); - FixedToString(w_coord, "Y", mo->y, buf, len, pos); - FixedToString(w_coord, "Z", mo->z, buf, len, pos); - AngleToString(w_coord, "A", mo->angle, buf, len, pos); - HUlib_add_string_keep_space(w_coord, " "); + static char line1[LINE_SIZE]; + pos = M_snprintf(line1, sizeof(line1), GREEN_S); + FixedToString(widget, "X", mo->x, line1, sizeof(line1), pos); + static char line2[LINE_SIZE]; + pos = M_snprintf(line2, sizeof(line2), GREEN_S); + FixedToString(widget, "Y", mo->y, line2, sizeof(line2), pos); + static char line3[LINE_SIZE]; + pos = M_snprintf(line3, sizeof(line3), GREEN_S); + FixedToString(widget, "Z", mo->z, line3, sizeof(line3), pos); + static char line4[LINE_SIZE]; + pos = M_snprintf(line4, sizeof(line4), GREEN_S); + AngleToString(widget, "A", mo->angle, line4, sizeof(line4), pos); + ST_AddLine(widget, " "); // "Momentum" per tic. magnitude = CalcMomentum(mo); color = BLOCK_COLOR(magnitude, THRESH_M1, THRESH_M2, THRESH_M3); - pos = M_snprintf(buf, len, "\x1b%c", '0' + color); - MagnitudeToString(w_coord, "M", magnitude, buf, len, pos); - ComponentToString(w_coord, "X", mo->momx, buf, len, pos); - ComponentToString(w_coord, "Y", mo->momy, buf, len, pos); - HUlib_add_string_keep_space(w_coord, " "); + static char line5[LINE_SIZE]; + pos = M_snprintf(line5, sizeof(line5), "\x1b%c", '0' + color); + MagnitudeToString(widget, "M", magnitude, line5, sizeof(line5), pos); + static char line6[LINE_SIZE]; + pos = M_snprintf(line6, sizeof(line6), "\x1b%c", '0' + color); + ComponentToString(widget, "X", mo->momx, line6, sizeof(line6), pos); + static char line7[LINE_SIZE]; + pos = M_snprintf(line7, sizeof(line7), "\x1b%c", '0' + color); + ComponentToString(widget, "Y", mo->momy, line7, sizeof(line7), pos); + ST_AddLine(widget, " "); // Distance per tic. magnitude = CalcDistance(mo); color = BLOCK_COLOR(magnitude, THRESH_D1, THRESH_D2, THRESH_D3); - pos = M_snprintf(buf, len, "\x1b%c", '0' + color); - MagnitudeToString(w_coord, "D", magnitude, buf, len, pos); - ComponentToString(w_coord, "X", mo->x - mo->oldx, buf, len, pos); - ComponentToString(w_coord, "Y", mo->y - mo->oldy, buf, len, pos); + static char line8[LINE_SIZE]; + pos = M_snprintf(line8, sizeof(line8), "\x1b%c", '0' + color); + MagnitudeToString(widget, "D", magnitude, line8, sizeof(line8), pos); + static char line9[LINE_SIZE]; + pos = M_snprintf(line9, sizeof(line9), "\x1b%c", '0' + color); + ComponentToString(widget, "X", mo->x - mo->oldx, line9, sizeof(line9), pos); + static char line10[LINE_SIZE]; + pos = M_snprintf(line10, sizeof(line10), "\x1b%c", '0' + color); + ComponentToString(widget, "Y", mo->y - mo->oldy, line10, sizeof(line10), pos); } diff --git a/src/hu_coordinates.h b/src/hu_coordinates.h index 80a88d9ec..822f7694e 100644 --- a/src/hu_coordinates.h +++ b/src/hu_coordinates.h @@ -19,13 +19,9 @@ #ifndef __HU_COORDINATES__ #define __HU_COORDINATES__ -#include "doomtype.h" -#include "hu_lib.h" - -struct hu_multiline_s; +struct sbe_widget_s; struct mobj_s; -void HU_BuildCoordinatesEx(struct hu_multiline_s *const w_coord, - const struct mobj_s *mo, char *buf, int len); +void HU_BuildCoordinatesEx(struct sbe_widget_s *widget, const struct mobj_s *mo); #endif diff --git a/src/hu_crosshair.c b/src/hu_crosshair.c index 71005c1e6..720ef087a 100644 --- a/src/hu_crosshair.c +++ b/src/hu_crosshair.c @@ -20,7 +20,6 @@ #include "hu_crosshair.h" #include "d_items.h" #include "doomstat.h" -#include "hu_stuff.h" #include "m_swap.h" #include "p_map.h" #include "p_mobj.h" @@ -101,6 +100,33 @@ void HU_StartCrosshair(void) mobj_t *crosshair_target; // [Alaux] Lock crosshair on target +static crange_idx_e CRByHealth(int health, int maxhealth, boolean invul) +{ + if (invul) + { + return CR_GRAY; + } + + health = 100 * health / maxhealth; + + if (health < health_red) + { + return CR_RED; + } + else if (health < health_yellow) + { + return CR_GOLD; + } + else if (health <= health_green) + { + return CR_GREEN; + } + else + { + return CR_BLUE1; + } +} + void HU_UpdateCrosshair(void) { plr = &players[displayplayer]; @@ -109,9 +135,11 @@ void HU_UpdateCrosshair(void) crosshair.y = (screenblocks <= 10) ? (SCREENHEIGHT - ST_HEIGHT) / 2 : SCREENHEIGHT / 2; + boolean invul = (plr->cheats & CF_GODMODE) || plr->powers[pw_invulnerability]; + if (hud_crosshair_health) { - crosshair.cr = HU_ColorByHealth(plr->health, 100, st_invul); + crosshair.cr = colrngs[CRByHealth(plr->health, 100, invul)]; } else { @@ -152,9 +180,9 @@ void HU_UpdateCrosshair(void) // [Alaux] Color crosshair by target health if (hud_crosshair_target == crosstarget_health) { - crosshair.cr = HU_ColorByHealth( + crosshair.cr = colrngs[CRByHealth( crosshair_target->health, - crosshair_target->info->spawnhealth, false); + crosshair_target->info->spawnhealth, false)]; } else { diff --git a/src/hu_lib.c b/src/hu_lib.c deleted file mode 100644 index f0c15ccc7..000000000 --- a/src/hu_lib.c +++ /dev/null @@ -1,604 +0,0 @@ -// -// Copyright (C) 1999 by -// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman -// Copyright (C) 2023 Fabian Greffrath -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// DESCRIPTION: heads-up text and input code -// -//----------------------------------------------------------------------------- - -#include -#include - -#include "doomdef.h" -#include "doomkeys.h" -#include "doomstat.h" -#include "hu_lib.h" -#include "hu_stuff.h" -#include "m_misc.h" -#include "m_swap.h" -#include "r_defs.h" -#include "r_draw.h" -#include "r_state.h" -#include "v_video.h" - -// [FG] horizontal alignment - -#define HU_GAPX 2 -static int left_margin, right_margin; -boolean hud_widescreen_widgets; - -void HUlib_set_margins (void) -{ - left_margin = HU_GAPX; - - if (hud_widescreen_widgets) - { - left_margin -= video.deltaw; - } - - right_margin = SCREENWIDTH - left_margin; -} - -// [FG] vertical alignment - -typedef enum { - offset_topleft, - offset_topright, - - offset_bottomleft, - offset_bottomright, - - num_offsets, -} offset_t; - -static int align_offset[num_offsets]; - -void HUlib_reset_align_offsets (void) -{ - int bottom = SCREENHEIGHT; - - if (scaledviewheight < SCREENHEIGHT || - draw_crispy_hud || - automap_on) - { - bottom -= 32; // ST_HEIGHT - } - - align_offset[offset_topleft] = 0; - align_offset[offset_topright] = 0; - align_offset[offset_bottomleft] = bottom; - align_offset[offset_bottomright] = bottom; -} - -// [FG] clear line - -void HUlib_clear_line (hu_line_t *const l) -{ - l->line[0] = '\0'; - l->len = 0; - l->width = 0; -} - -void HUlib_clear_cur_line (hu_multiline_t *const m) -{ - HUlib_clear_line(m->lines[m->curline]); -} - -void HUlib_clear_all_lines (hu_multiline_t *const m) -{ - int i; - - for (i = 0; i < m->numlines; i++) - { - HUlib_clear_line(m->lines[i]); - } -} - -// [FG] add single char to line, increasing its length but not its width - -static boolean add_char_to_line(hu_line_t *const t, const char ch) -{ - if (t->len == HU_MAXLINELENGTH - 1) - return false; - else - { - t->line[t->len++] = ch; - t->line[t->len] = '\0'; - return true; - } -} - -static boolean del_char_from_line(hu_line_t* l) -{ - return l->len ? l->line[--l->len] = '\0', true : false; -} - -// [FG] add printable char to line, handle Backspace and Enter (for w_chat) - -boolean HUlib_add_key_to_line(hu_line_t *const l, unsigned char ch) -{ - if (ch >= ' ' && ch <= '_') - add_char_to_line(l, (char) ch); - else if (ch == KEY_BACKSPACE) // phares - del_char_from_line(l); - else if (ch != KEY_ENTER) // phares - return false; // did not eat key - - return true; // ate the key -} - -boolean HUlib_add_key_to_cur_line(hu_multiline_t *const m, unsigned char ch) -{ - hu_line_t *const l = m->lines[m->curline]; - - return HUlib_add_key_to_line(l, ch); -} - -// [FG] point curline to the next line in a multiline if available - -static inline void inc_cur_line (hu_multiline_t *const m) -{ - if (m->numlines > 1) - { - if (++m->curline >= m->numlines) - { - m->curline = 0; - } - } -} - -// [FG] add string to line, increasing its (length and) width - -static void add_string_to_line(hu_line_t *const l, const hu_font_t *const f, - const char *s, boolean keep_space) -{ - int w = 0; - unsigned char c; - patch_t *const *const p = f->patches; - - if (!*s) - return; - - while (*s) - { - c = M_ToUpper(*s++); - - if (c == '\x1b') - { - add_char_to_line(l, c); - add_char_to_line(l, *s++); - continue; - } - else if (c == '\t') - w = (w + f->tab_width) & f->tab_mask; - else if (c >= HU_FONTSTART && c <= HU_FONTEND + 6) - w += SHORT(p[c - HU_FONTSTART]->width); - else - w += f->space_width; - - add_char_to_line(l, c); - } - - if (!keep_space) - { - while (*--s == ' ') - w -= f->space_width; - } - - l->width += w; -} - -// [FG] add string to current line, point to next line if available - -void HUlib_add_strings_to_cur_line (hu_multiline_t *const m, const char *prefix, const char *s) -{ - hu_line_t *const l = m->lines[m->curline]; - - HUlib_clear_line(l); - - if (prefix) - { - add_string_to_line(l, *m->font, prefix, false); - } - - add_string_to_line(l, *m->font, s, false); - - inc_cur_line(m); -} - -void HUlib_add_string_to_cur_line (hu_multiline_t *const m, const char *s) -{ - HUlib_add_strings_to_cur_line(m, NULL, s); -} - -void HUlib_add_string_keep_space(hu_multiline_t *const m, const char *s) -{ - hu_line_t *const l = m->lines[m->curline]; - - HUlib_clear_line(l); - add_string_to_line(l, *m->font, s, true); - inc_cur_line(m); -} - -// [FG] horizontal and vertical alignment - -static int horz_align_widget(const hu_widget_t *const w, const hu_line_t *const l, const align_t h_align) -{ - if (h_align == align_left) - { - return left_margin; - } - else if (h_align == align_right) - { - return right_margin - l->width; - } - else if (h_align == align_center) - { - return SCREENWIDTH/2 - l->width/2; - } - - // [FG] align_direct - if (hud_widescreen_widgets) - { - if (w->x < SCREENWIDTH/2) - { - return w->x - video.deltaw; - } - else - { - return w->x + video.deltaw; - } - } - - return w->x; -} - -static int vert_align_widget(const hu_widget_t *const w, const hu_multiline_t *const m, const hu_font_t *const f, const align_t h_align, const align_t v_align) -{ - const int font_height = f->line_height; - - int y = 0; - - if (v_align == align_direct) - { - return w->y; - } - else if (v_align == align_secret) - { - return MAX(SCREENHEIGHT - 32, scaledviewheight) / 2 - 32; - } - // [FG] centered and Vanilla widgets are always exclusive, - // i.e. they don't allow any other widget on the same line - else if (h_align == align_center || m->exclusive) - { - if (v_align == align_top) - { - y = MAX(align_offset[offset_topleft], - align_offset[offset_topright]); - - align_offset[offset_topleft] = - align_offset[offset_topright] = y + font_height; - } - else if (v_align == align_bottom) - { - y = MIN(align_offset[offset_bottomleft], - align_offset[offset_bottomright]) - font_height; - - align_offset[offset_bottomleft] = - align_offset[offset_bottomright] = y; - } - } - else if (v_align == align_top) - { - if (h_align == align_left) - { - y = align_offset[offset_topleft]; - align_offset[offset_topleft] += font_height; - } - else if (h_align == align_right) - { - y = align_offset[offset_topright]; - align_offset[offset_topright] += font_height; - } - } - else if (v_align == align_bottom) - { - if (h_align == align_left) - { - align_offset[offset_bottomleft] -= font_height; - y = align_offset[offset_bottomleft]; - } - else if (h_align == align_right) - { - align_offset[offset_bottomright] -= font_height; - y = align_offset[offset_bottomright]; - } - } - - return y; -} - -// [FG] draw a line to a given screen coordinates using the given font - -static void draw_line_aligned (const hu_multiline_t *m, const hu_line_t *l, const hu_font_t *const f, int x, int y) -{ - const int x0 = x; - int i; - unsigned char c; - byte *cr = m->cr; - patch_t *const *const p = f->patches; - - // draw the new stuff - for (i = 0; i < l->len; i++) - { - c = M_ToUpper(l->line[i]); - -#if 0 - if (c == '\n') - { - // [FG] TODO line breaks! - } - else -#endif - if (c == '\t') // killough 1/23/98 -- support tab stops - { - x = x0 + (((x - x0) + f->tab_width) & f->tab_mask); - } - else if (c == '\x1b') //jff 2/17/98 escape code for color change - { //jff 3/26/98 changed to actual escape char - if (++i < l->len) - { - if (l->line[i] >= '0' && l->line[i] <= '0'+CR_NONE) - cr = colrngs[l->line[i]-'0']; - else if (l->line[i] == '0'+CR_ORIG) // [FG] reset to original color - cr = m->cr; - } - } - else if (c >= HU_FONTSTART && c <= HU_FONTEND + 6) - { - int w = SHORT(p[c-HU_FONTSTART]->width); - - if (x+w > right_margin + HU_GAPX) - break; - - // killough 1/18/98 -- support multiple lines: - V_DrawPatchTranslated(x, y, p[c-HU_FONTSTART], cr); - x += w; - } - else if ((x += f->space_width) >= right_margin + HU_GAPX) - break; - } - - // draw the cursor if requested - // killough 1/18/98 -- support multiple lines - if (m->drawcursor && - x + SHORT(p['_'-HU_FONTSTART]->width) <= right_margin + HU_GAPX && - leveltime & 16) - { - cr = m->cr; //jff 2/17/98 restore original color - V_DrawPatchTranslated(x, y, p['_' - HU_FONTSTART], cr); - } -} - -// [FG] shortcut for single-lined wigets - -static void draw_widget_single (const hu_widget_t *const w, const hu_font_t *const f) -{ - const hu_multiline_t *const m = w->multiline; - const int h_align = w->h_align, v_align = w->v_align; - - const int cl = m->curline; - const hu_line_t *const l = m->lines[cl]; - - if (l->width || m->drawcursor) - { - int x, y; - - x = horz_align_widget(w, l, h_align); - y = vert_align_widget(w, m, f, h_align, v_align); - draw_line_aligned(m, l, f, x, y); - } -} - -// [FG] the w_messages widget is drawn bottom-up if v_align == align_top, -// i.e. the last message is drawn first, same for all other widgets -// if v_align == align_bottom - -static void draw_widget_bottomup (const hu_widget_t *const w, const hu_font_t *const f) -{ - const hu_multiline_t *const m = w->multiline; - const int h_align = w->h_align, v_align = w->v_align; - - const int nl = m->numlines; - int cl = m->curline - 1; - - int i, x, y; - - for (i = 0; i < nl; i++, cl--) - { - const hu_line_t *l; - - if (cl < 0) - cl = nl - 1; - - l = m->lines[cl]; - - if (l->width) - { - x = horz_align_widget(w, l, h_align); - y = vert_align_widget(w, m, f, h_align, v_align); - draw_line_aligned(m, l, f, x, y); - } - } -} - -// [FG] standard behavior, the first line is drawn first - -static void draw_widget_topdown (const hu_widget_t *const w, const hu_font_t *const f) -{ - const hu_multiline_t *const m = w->multiline; - const int h_align = w->h_align, v_align = w->v_align; - - const int nl = m->numlines; - int cl = m->curline; - - int i, x, y; - - for (i = 0; i < nl; i++, cl++) - { - const hu_line_t *l; - - if (cl >= nl) - cl = 0; - - l = m->lines[cl]; - - if (l->width) - { - x = horz_align_widget(w, l, h_align); - y = vert_align_widget(w, m, f, h_align, v_align); - draw_line_aligned(m, l, f, x, y); - } - } -} - -void HUlib_draw_widget (const hu_widget_t *const w) -{ - const hu_multiline_t *const m = w->multiline; - const hu_font_t *const f = *m->font; - - if (m->numlines == 1) - draw_widget_single(w, f); - // [FG] Vanilla widget with top alignment, - // or Boom widget with bottom alignment - else if (m->bottomup ^ (w->v_align == align_bottom)) - draw_widget_bottomup(w, f); - else - draw_widget_topdown(w, f); -} - -void HUlib_init_multiline(hu_multiline_t *m, - int nl, - hu_font_t **f, - byte *cr, - boolean *on, - void (*builder)(void)) -{ - int i; - - // [FG] dynamically allocate lines array - if (m->numlines != nl) - { - for (i = 0; i < m->numlines; i++) - { - free(m->lines[i]); - m->lines[i] = NULL; - } - } - - m->numlines = nl; - m->curline = 0; - - for (i = 0; i < m->numlines; i++) - { - if (m->lines[i] == NULL) - { - m->lines[i] = malloc(sizeof(hu_line_t)); - } - HUlib_clear_line(m->lines[i]); - } - - m->font = f; - m->cr = cr; - m->drawcursor = false; - - m->on = on; - - m->builder = builder; - m->built = false; - - m->exclusive = (on != NULL); - m->bottomup = (on != NULL); -} - -void HUlib_erase_widget (const hu_widget_t *const w) -{ - const hu_multiline_t *const m = w->multiline; - const hu_font_t *const f = *m->font; - - const int height = m->numlines * f->line_height; - - int y = 0; - for (int i = 0; i < m->numlines; ++i) - { - y = vert_align_widget(w, m, f, w->h_align, w->v_align); - } - - if (w->v_align == align_top) - y += f->line_height - height; - - if (y > scaledviewy && y < scaledviewy + scaledviewheight - height) - { - R_VideoErase(0, y, scaledviewx, height); - R_VideoErase(scaledviewx + scaledviewwidth, y, scaledviewx, height); - } - else - { - R_VideoErase(0, y, video.unscaledw, height); - } -} - -//---------------------------------------------------------------------------- -// -// $Log: hu_lib.c,v $ -// Revision 1.13 1998/05/11 10:13:26 jim -// formatted/documented hu_lib -// -// Revision 1.12 1998/05/03 22:24:13 killough -// Provide minimal headers at top; nothing else -// -// Revision 1.11 1998/04/29 09:24:33 jim -// Fix compiler warning -// -// Revision 1.10 1998/04/28 15:53:46 jim -// Fix message list bug in small screen mode -// -// Revision 1.9 1998/03/27 21:25:41 jim -// Commented change of \ to ESC -// -// Revision 1.8 1998/03/26 20:06:24 jim -// Fixed escape confusion in HU text drawer -// -// Revision 1.7 1998/02/26 22:58:33 jim -// Added message review display to HUD -// -// Revision 1.6 1998/02/19 16:55:15 jim -// Optimized HUD and made more configurable -// -// Revision 1.5 1998/02/18 00:59:01 jim -// Addition of HUD -// -// Revision 1.4 1998/02/15 02:47:44 phares -// User-defined keys -// -// Revision 1.3 1998/01/26 19:23:20 phares -// First rev with no ^Ms -// -// Revision 1.2 1998/01/26 05:50:22 killough -// Support more lines, and tab stops, in messages -// -// Revision 1.1.1.1 1998/01/19 14:02:55 rand -// Lee's Jan 19 sources -// -//---------------------------------------------------------------------------- diff --git a/src/hu_lib.h b/src/hu_lib.h deleted file mode 100644 index bd24e9142..000000000 --- a/src/hu_lib.h +++ /dev/null @@ -1,183 +0,0 @@ -// -// Copyright (C) 1999 by -// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman -// Copyright (C) 2023 Fabian Greffrath -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// DESCRIPTION: none -// -//----------------------------------------------------------------------------- - -#ifndef __HULIB__ -#define __HULIB__ - -#include "doomtype.h" - -struct patch_s; - -// [FG] font stuff - -#define HU_FONTSTART '!' /* the first font characters */ -#define HU_FONTEND (0x7f) /*jff 2/16/98 '_' the last font characters */ - -// Calculate # of glyphs in font. -#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) - -typedef struct -{ - struct patch_s *patches[HU_FONTSIZE+6]; - - int line_height; - - const int space_width; - - const int tab_width; - const int tab_mask; -} hu_font_t; - -extern struct patch_s **hu_font; - -// [FG] widget stuff - -#define CR_ORIG (-1) // [FG] reset to original color - -#define HU_MAXLINELENGTH 120 - -//jff 2/26/98 maximum number of messages allowed in refresh list -#define HU_MAXMESSAGES 20 - -typedef enum -{ - // [FG] h_align / v_align - align_direct, - - // [FG] h_align - align_left, - align_right, - align_center, - - // [FG] v_align - align_top, - align_bottom, - align_secret, - - num_aligns, -} align_t; - -// [FG] a single line of information - -typedef struct -{ - char line[HU_MAXLINELENGTH]; - - // [FG] length in chars - int len; - - // [FG] width in pixels - int width; - -} hu_line_t; - -// [FG] an array of lines with common properties - -typedef struct hu_multiline_s -{ - hu_line_t *lines[HU_MAXMESSAGES]; // text lines to draw - int numlines; // number of lines - int curline; // current line number - - hu_font_t **font; // font - byte *cr; //jff 2/16/52 output color range - boolean drawcursor; - - // pointer to boolean stating whether to update window - boolean *on; - - void (*builder)(void); - boolean built; - - boolean exclusive; - boolean bottomup; - -} hu_multiline_t; - -// [FG] configured alignment and coordinates for multilines - -typedef struct hu_widget_s -{ - hu_multiline_t *multiline; - - align_t h_align, v_align; - - // [FG] align_direct - int x, y; - - // [FG] back up for centered messages - align_t h_align_orig; - -} hu_widget_t; - -void HUlib_set_margins (void); -void HUlib_reset_align_offsets (void); - -void HUlib_clear_line (hu_line_t *const l); -void HUlib_clear_cur_line (hu_multiline_t *const m); -void HUlib_clear_all_lines (hu_multiline_t *const m); - -void HUlib_add_string_to_cur_line (hu_multiline_t *const m, const char *s); -void HUlib_add_strings_to_cur_line (hu_multiline_t *const m, const char *prefix, const char *s); -void HUlib_add_string_keep_space(hu_multiline_t *const m, const char *s); - -void HUlib_draw_widget (const hu_widget_t *const w); - -void HUlib_init_multiline (hu_multiline_t *const m, int nl, hu_font_t **f, byte *cr, boolean *on, void (*builder)(void)); - -boolean HUlib_add_key_to_line (hu_line_t *const l, unsigned char ch); -boolean HUlib_add_key_to_cur_line (hu_multiline_t *const m, unsigned char ch); - -void HUlib_erase_widget (const hu_widget_t *const w); - -#endif - -//---------------------------------------------------------------------------- -// -// $Log: hu_lib.h,v $ -// Revision 1.9 1998/05/11 10:13:31 jim -// formatted/documented hu_lib -// -// Revision 1.8 1998/04/28 15:53:53 jim -// Fix message list bug in small screen mode -// -// Revision 1.7 1998/02/26 22:58:44 jim -// Added message review display to HUD -// -// Revision 1.6 1998/02/19 16:55:19 jim -// Optimized HUD and made more configurable -// -// Revision 1.5 1998/02/18 00:58:58 jim -// Addition of HUD -// -// Revision 1.4 1998/02/15 02:48:09 phares -// User-defined keys -// -// Revision 1.3 1998/01/26 19:26:52 phares -// First rev with no ^Ms -// -// Revision 1.2 1998/01/26 05:50:24 killough -// Support more lines, and tab stops, in messages -// -// Revision 1.1.1.1 1998/01/19 14:02:55 rand -// Lee's Jan 19 sources -// -// -//---------------------------------------------------------------------------- - diff --git a/src/hu_obituary.c b/src/hu_obituary.c index 46bc6482c..e94d864a7 100644 --- a/src/hu_obituary.c +++ b/src/hu_obituary.c @@ -28,6 +28,7 @@ #include "m_misc.h" #include "net_client.h" #include "p_mobj.h" +#include "v_video.h" boolean show_obituary_messages; int hudcolor_obituary; @@ -215,7 +216,7 @@ void HU_Obituary(mobj_t *target, mobj_t *source, method_t mod) break; } - doomprintf(&players[i], MESSAGES_OBITUARY, "\x1b%c%s", + doomprintf(&players[i], MESSAGES_OBITUARY, "\x1b%c%s" ORIG_S, '0' + hudcolor_obituary, str); } diff --git a/src/hu_stuff.c b/src/hu_stuff.c deleted file mode 100644 index 94da286a1..000000000 --- a/src/hu_stuff.c +++ /dev/null @@ -1,2366 +0,0 @@ -// -// Copyright (C) 1999 by -// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman -// Copyright (C) 2023 Fabian Greffrath -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// DESCRIPTION: Heads-up displays -// -//----------------------------------------------------------------------------- - -// killough 5/3/98: remove unnecessary headers - -#include -#include - -#include "d_deh.h" /* Ty 03/27/98 - externalization of mapnamesx arrays */ -#include "d_event.h" -#include "d_items.h" -#include "doomkeys.h" -#include "doomstat.h" -#include "dstrings.h" -#include "hu_coordinates.h" -#include "hu_crosshair.h" -#include "hu_lib.h" -#include "hu_obituary.h" -#include "hu_stuff.h" -#include "i_timer.h" // time_scale -#include "i_video.h" // fps -#include "m_config.h" -#include "m_input.h" -#include "m_misc.h" -#include "m_swap.h" -#include "p_mobj.h" -#include "r_main.h" -#include "r_state.h" -#include "r_voxel.h" -#include "s_sound.h" -#include "sounds.h" -#include "st_stuff.h" /* jff 2/16/98 need loc of status bar */ -#include "u_mapinfo.h" -#include "u_scanner.h" -#include "v_fmt.h" -#include "v_video.h" - -// global heads up display controls - -int hud_active; //jff 2/17/98 controls heads-up display mode -boolean hud_displayed; //jff 2/23/98 turns heads-up display on/off -boolean hud_secret_message; // "A secret is revealed!" message -static int hud_widget_font; -static boolean hud_widget_layout; - -int hud_type; // Crispy HUD or Boom variants -boolean draw_crispy_hud; - -// -// Locally used constants, shortcuts. -// -// Ty 03/28/98 - -// These four shortcuts modifed to reflect char ** of mapnamesx[] -#define HU_TITLE (*mapnames[(gameepisode-1)*9+gamemap-1]) -#define HU_TITLE2 (*mapnames2[gamemap-1]) -#define HU_TITLEP (*mapnamesp[gamemap-1]) -#define HU_TITLET (*mapnamest[gamemap-1]) - -static const char *chat_macros[] = // Ty 03/27/98 - *not* externalized -{ - HUSTR_CHATMACRO0, - HUSTR_CHATMACRO1, - HUSTR_CHATMACRO2, - HUSTR_CHATMACRO3, - HUSTR_CHATMACRO4, - HUSTR_CHATMACRO5, - HUSTR_CHATMACRO6, - HUSTR_CHATMACRO7, - HUSTR_CHATMACRO8, - HUSTR_CHATMACRO9 -}; - -char **player_names[] = -{ - &s_HUSTR_PLRGREEN, - &s_HUSTR_PLRINDIGO, - &s_HUSTR_PLRBROWN, - &s_HUSTR_PLRRED -}; - -//jff 3/17/98 translate player colmap to text color ranges -int plyrcoltran[MAXPLAYERS]={CR_GREEN,CR_GRAY,CR_BROWN,CR_RED}; - -static player_t *plr; - -// font sets -static hu_font_t big_font = {.space_width = 4, .tab_width = 15, .tab_mask = ~15}, - sml_font = {.space_width = 5, .tab_width = 7, .tab_mask = ~7}; -static hu_font_t *doom_font = &big_font, *boom_font = &sml_font; -static hu_font_t *monospaced_font = &sml_font; -patch_t **hu_font = big_font.patches; - -static int CR_BLUE = CR_BLUE1; - -// widgets - -static char hud_stringbuffer[HU_MAXLINELENGTH]; - -static inline void InitStringBuffer(const char *const s) -{ - strncpy(hud_stringbuffer, s, sizeof(hud_stringbuffer)); -} - -// [FG] Vanilla widgets point to a boolean variable (*on) to determine -// if they are enabled, always big_font, mostly left-aligned -static hu_multiline_t w_title; -static hu_multiline_t w_message; -static hu_multiline_t w_chat; -static hu_multiline_t w_secret; // [crispy] secret message widget - -// [FG] special pony, per-player chat input buffer -static hu_line_t w_inputbuffer[MAXPLAYERS]; - -// [FG] Boom widgets are built using builder() functions -static hu_multiline_t w_ammo; //jff 2/16/98 new ammo widget for hud -static hu_multiline_t w_armor; //jff 2/16/98 new armor widget for hud -static hu_multiline_t w_health; //jff 2/16/98 new health widget for hud -static hu_multiline_t w_keys; //jff 2/16/98 new keys widget for hud -static hu_multiline_t w_weapon; //jff 2/16/98 new weapon widget for hud - -static hu_multiline_t w_compact; - -// [FG] extra Boom widgets, that need to be explicitly enabled -static hu_multiline_t w_monsec; //jff 2/16/98 new kill/secret widget for hud -static hu_multiline_t w_sttime; // time above status bar -static hu_multiline_t w_coord; -static hu_multiline_t w_fps; -static hu_multiline_t w_rate; -static hu_multiline_t w_cmd; -static hu_multiline_t w_speed; - -#define MAX_HUDS 3 -#define MAX_WIDGETS 20 - -static hu_widget_t widgets[MAX_HUDS][MAX_WIDGETS]; - -static void HU_ParseHUD (void); - -static char chat_dest[MAXPLAYERS]; -boolean chat_on; -static boolean message_on; -static boolean has_message; // killough 12/98 -boolean message_dontfuckwithme; -static boolean message_nottobefuckedwith; -static int message_counter; -static int message_count; // killough 11/98 -static int chat_count; // killough 11/98 -static boolean secret_on; -static int secret_counter; - -static boolean message_centered; -static boolean message_colorized; - -boolean show_messages; -boolean show_toggle_messages; -boolean show_pickup_messages; - -static boolean hud_map_announce; -static boolean title_on; -static int title_counter; - -static boolean headsupactive = false; - -//jff 2/16/98 hud supported automap colors added -int hudcolor_titl; // color range of automap level title -int hudcolor_xyco; // color range of new coords on automap -//jff 2/16/98 hud text colors, controls added -static int hudcolor_mesg; // color range of scrolling messages -static int hudcolor_chat; // color range of chat lines -static int hud_msg_lines; // number of message lines in window -static boolean message_list; // killough 11/98: made global - -static int message_timer = HU_MSGTIMEOUT * (1000/TICRATE); // killough 11/98 -static int chat_msg_timer = HU_MSGTIMEOUT * (1000/TICRATE); // killough 11/98 - -// -// Builtin map names. -// The actual names can be found in DStrings.h. -// -// Ty 03/27/98 - externalized map name arrays - now in d_deh.c -// and converted to arrays of pointers to char * -// See modified HUTITLEx macros - -// key tables -// jff 5/10/98 french support removed, -// as it was not being used and couldn't be easily tested -// -const char shiftxform[] = -{ - 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, - ' ', '!', '"', '#', '$', '%', '&', - '"', // shift-' - '(', ')', '*', '+', - '<', // shift-, - '_', // shift-- - '>', // shift-. - '?', // shift-/ - ')', // shift-0 - '!', // shift-1 - '@', // shift-2 - '#', // shift-3 - '$', // shift-4 - '%', // shift-5 - '^', // shift-6 - '&', // shift-7 - '*', // shift-8 - '(', // shift-9 - ':', - ':', // shift-; - '<', - '+', // shift-= - '>', '?', '@', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '[', // shift-[ - '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK - ']', // shift-] - '"', '_', - '\'', // shift-` - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '{', '|', '}', '~', 127 -}; - -static boolean VANILLAMAP(int e, int m) -{ - if (gamemode == commercial) - return (e == 1 && m > 0 && m <=32); - else - return (e > 0 && e <= 4 && m > 0 && m <= 9); -} - -struct { - char **str; - const int cr; - const char *col; -} static const colorize_strings[] = { - // [Woof!] colorize keycard and skull key messages - {&s_GOTBLUECARD, CR_BLUE2, " blue "}, - {&s_GOTBLUESKUL, CR_BLUE2, " blue "}, - {&s_GOTREDCARD, CR_RED, " red "}, - {&s_GOTREDSKULL, CR_RED, " red "}, - {&s_GOTYELWCARD, CR_GOLD, " yellow "}, - {&s_GOTYELWSKUL, CR_GOLD, " yellow "}, - {&s_PD_BLUEC, CR_BLUE2, " blue "}, - {&s_PD_BLUEK, CR_BLUE2, " blue "}, - {&s_PD_BLUEO, CR_BLUE2, " blue "}, - {&s_PD_BLUES, CR_BLUE2, " blue "}, - {&s_PD_REDC, CR_RED, " red "}, - {&s_PD_REDK, CR_RED, " red "}, - {&s_PD_REDO, CR_RED, " red "}, - {&s_PD_REDS, CR_RED, " red "}, - {&s_PD_YELLOWC, CR_GOLD, " yellow "}, - {&s_PD_YELLOWK, CR_GOLD, " yellow "}, - {&s_PD_YELLOWO, CR_GOLD, " yellow "}, - {&s_PD_YELLOWS, CR_GOLD, " yellow "}, - - // [Woof!] colorize multi-player messages - {&s_HUSTR_PLRGREEN, CR_GREEN, "Green: "}, - {&s_HUSTR_PLRINDIGO, CR_GRAY, "Indigo: "}, - {&s_HUSTR_PLRBROWN, CR_BROWN, "Brown: "}, - {&s_HUSTR_PLRRED, CR_RED, "Red: "}, -}; - -static char* PrepareColor(const char *str, const char *col) -{ - char *str_replace, col_replace[16]; - - M_snprintf(col_replace, sizeof(col_replace), - "\x1b%c%s\x1b%c", '0'+CR_ORIG, col, '0'+CR_ORIG); - str_replace = M_StringReplace(str, col, col_replace); - - return str_replace; -} - -static void UpdateColor(char *str, int cr) -{ - int i; - int len = strlen(str); - - if (!message_colorized) - { - cr = CR_ORIG; - } - - for (i = 0; i < len; ++i) - { - if (str[i] == '\x1b' && i + 1 < len) - { - str[i + 1] = '0'+cr; - break; - } - } -} - -void HU_ResetMessageColors(void) -{ - int i; - - for (i = 0; i < arrlen(colorize_strings); i++) - { - UpdateColor(*colorize_strings[i].str, colorize_strings[i].cr); - } -} - -static crange_idx_e CRByHealth(int health, int maxhealth, boolean invul) -{ - if (invul) - return CR_GRAY; - - health = 100 * health / maxhealth; - - if (health < health_red) - return CR_RED; - else if (health < health_yellow) - return CR_GOLD; - else if (health <= health_green) - return CR_GREEN; - else - return CR_BLUE; -} - -byte* HU_ColorByHealth(int health, int maxhealth, boolean invul) -{ - const crange_idx_e cr = CRByHealth(health, maxhealth, invul); - - return colrngs[cr]; -} - -// [FG] support centered player messages - -static void HU_set_centered_message(void) -{ - int i, j; - - for (i = 0; i < MAX_HUDS; i++) - { - hu_widget_t *const w = widgets[i]; - - for (j = 0; w[j].multiline; j++) - { - if (w[j].multiline == &w_message) - { - w[j].h_align = message_centered ? align_center : w[j].h_align_orig; - } - } - } -} - -// -// HU_Init() -// -// Initialize the heads-up display, text that overwrites the primary display -// -// Passed nothing, returns nothing -// -void HU_Init(void) -{ - int i, j; - char buffer[9]; - - // load the heads-up font - for (i = 0, j = HU_FONTSTART; i < HU_FONTSIZE; i++, j++) - { - M_snprintf(buffer, sizeof(buffer), "STCFN%.3d", j); - if (W_CheckNumForName(buffer) != -1) - big_font.patches[i] = V_CachePatchName(buffer, PU_STATIC); - - if ('0' <= j && j <= '9') - { - M_snprintf(buffer, sizeof(buffer), "DIG%.1d", j - 48); - sml_font.patches[i] = V_CachePatchName(buffer, PU_STATIC); - } - else if ('A' <= j && j <= 'Z') - { - M_snprintf(buffer, sizeof(buffer), "DIG%c", j); - sml_font.patches[i] = V_CachePatchName(buffer, PU_STATIC); - } - else if (j > 122) - { - M_snprintf(buffer, sizeof(buffer), "STBR%.3d", j); - sml_font.patches[i] = V_CachePatchName(buffer, PU_STATIC); - } - else - { - M_snprintf(buffer, sizeof(buffer), "DIG%.2d", j); - if (W_CheckNumForName(buffer) != -1) - sml_font.patches[i] = V_CachePatchName(buffer, PU_STATIC); - } - - // [FG] small font available, big font unavailable - if (big_font.patches[i] == NULL && sml_font.patches[i] != NULL) - { - big_font.patches[i] = sml_font.patches[i]; - } - // [FG] big font available, small font unavailable - else if (big_font.patches[i] != NULL && sml_font.patches[i] == NULL) - { - sml_font.patches[i] = big_font.patches[i]; - } - // [FG] both fonts unavailable, fall back to '!' - else if (big_font.patches[i] == NULL && sml_font.patches[i] == NULL) - { - sml_font.patches[i] = - big_font.patches[i] = big_font.patches[0]; - } - } - - //jff 2/26/98 load patches for keys and double keys - for (i = HU_FONTSIZE, j = 0; j < 6; i++, j++) - { - M_snprintf(buffer, sizeof(buffer), "STKEYS%.1d", j); - sml_font.patches[i] = - big_font.patches[i] = V_CachePatchName(buffer, PU_STATIC); - } - - // [FG] calculate font height once right here - sml_font.line_height = SHORT(sml_font.patches['A'-HU_FONTSTART]->height) + 1; - big_font.line_height = SHORT(big_font.patches['A'-HU_FONTSTART]->height) + 1; - - // [FG] support crosshair patches from extras.wad - HU_InitCrosshair(); - - HU_InitCommandHistory(); - - HU_InitObituaries(); - - HU_ParseHUD(); - HU_set_centered_message(); - - // [Woof!] prepare player messages for colorization - for (i = 0; i < arrlen(colorize_strings); i++) - { - *colorize_strings[i].str = PrepareColor(*colorize_strings[i].str, colorize_strings[i].col); - } - - HU_ResetMessageColors(); -} - -static inline void HU_cond_build_widget (hu_multiline_t *const multiline, boolean cond) -{ - if (cond && multiline->built == false) - { - multiline->builder(); - multiline->built = true; - } -} - -static boolean hud_pending; - -void HU_disable_all_widgets (void) -{ - hu_widget_t *w = widgets[hud_active]; - - while (w->multiline) - { - w->multiline->built = false; - w++; - } - - hud_pending = true; -} - -// -// HU_Stop() -// -// Make the heads-up displays inactive -// -// Passed nothing, returns nothing -// -void HU_Stop(void) -{ - headsupactive = false; -} - -// -// HU_Start(void) -// -// Create and initialize the heads-up widgets, software machines to -// maintain, update, and display information over the primary display -// -// This routine must be called after any change to the heads up configuration -// in order for the changes to take effect in the actual displays -// -// Passed nothing, returns nothing -// - -static void HU_widget_build_ammo (void); -static void HU_widget_build_armor (void); -static void HU_widget_build_coord (void); -static void HU_widget_build_fps (void); -static void HU_widget_build_rate (void); -static void HU_widget_build_cmd(void); -static void HU_widget_build_health (void); -static void HU_widget_build_keys (void); -static void HU_widget_build_frag (void); -static void HU_widget_build_monsec(void); -static void HU_widget_build_sttime(void); -static void HU_widget_build_title (void); -static void HU_widget_build_weapon (void); -static void HU_widget_build_compact (void); -static void HU_widget_build_speed(void); - -static hu_multiline_t *w_stats; - -void HU_Start(void) -{ - int i; - - if (headsupactive) // stop before starting - HU_Stop(); - - plr = &players[displayplayer]; // killough 3/7/98 - message_on = false; - message_dontfuckwithme = false; - message_nottobefuckedwith = false; - chat_on = false; - secret_on = false; - - // killough 11/98: - message_counter = 0; - message_count = (message_timer * TICRATE) / 1000 + 1; - chat_count = (chat_msg_timer * TICRATE) / 1000 + 1; - - // create the message widget - HUlib_init_multiline(&w_message, message_list ? hud_msg_lines : 1, - &doom_font, colrngs[hudcolor_mesg], - &message_on, NULL); - - // create the secret message widget - HUlib_init_multiline(&w_secret, 1, - &doom_font, colrngs[CR_GOLD], - &secret_on, NULL); - - // create the chat widget - HUlib_init_multiline(&w_chat, 1, - &doom_font, colrngs[hudcolor_chat], - &chat_on, NULL); - // [FG] only the chat widget draws a cursor - w_chat.drawcursor = true; - - // create the inputbuffer widgets, one per player - for (i = 0; i < MAXPLAYERS; i++) - { - HUlib_clear_line(&w_inputbuffer[i]); - } - - //jff 2/16/98 added some HUD widgets - // create the map title widget - HUlib_init_multiline(&w_title, 1, - &doom_font, colrngs[hudcolor_titl], - &title_on, HU_widget_build_title); - // [FG] built only once right here - w_title.builder(); - - // create the hud health widget - HUlib_init_multiline(&w_health, 1, - &boom_font, colrngs[CR_GREEN], - NULL, HU_widget_build_health); - - // create the hud armor widget - HUlib_init_multiline(&w_armor, 1, - &boom_font, colrngs[CR_GREEN], - NULL, HU_widget_build_armor); - - // create the hud ammo widget - HUlib_init_multiline(&w_ammo, 1, - &boom_font, colrngs[CR_GOLD], - NULL, HU_widget_build_ammo); - - // create the hud weapons widget - HUlib_init_multiline(&w_weapon, 1, - &boom_font, colrngs[CR_GRAY], - NULL, HU_widget_build_weapon); - - // create the hud keys widget - HUlib_init_multiline(&w_keys, 1, - &boom_font, colrngs[CR_GRAY], - NULL, deathmatch ? HU_widget_build_frag : HU_widget_build_keys); - - HUlib_init_multiline(&w_compact, hud_widget_layout ? 3 : 1, - &boom_font, colrngs[CR_GRAY], - NULL, HU_widget_build_compact); - - // create the hud monster/secret widget - HUlib_init_multiline(&w_monsec, hud_widget_layout ? 3 : 1, - &boom_font, colrngs[CR_GRAY], - NULL, HU_widget_build_monsec); - // [FG] in deathmatch: w_keys.builder = HU_widget_build_frag() - w_stats = deathmatch ? &w_keys : &w_monsec; - - HUlib_init_multiline(&w_sttime, 1, - &boom_font, colrngs[CR_GRAY], - NULL, HU_widget_build_sttime); - - // create the automaps coordinate widget - if (hud_player_coords == HUD_WIDGET_ADVANCED) - { - HUlib_init_multiline(&w_coord, 12, - &monospaced_font, colrngs[CR_GRAY], - NULL, HU_widget_build_coord); - } - else - { - HUlib_init_multiline(&w_coord, hud_widget_layout ? 3 : 1, - &boom_font, colrngs[hudcolor_xyco], - NULL, HU_widget_build_coord); - } - - HUlib_init_multiline(&w_fps, 1, - &boom_font, colrngs[hudcolor_xyco], - NULL, HU_widget_build_fps); - - HUlib_init_multiline(&w_rate, (voxels_rendering ? 2 : 1), - &boom_font, colrngs[hudcolor_xyco], - NULL, HU_widget_build_rate); - // [FG] draw the IDRATE widget exclusively - w_rate.exclusive = true; - - HUlib_init_multiline(&w_cmd, hud_command_history_size, - &monospaced_font, colrngs[hudcolor_xyco], - NULL, HU_widget_build_cmd); - // Draw command history bottom up. - w_cmd.bottomup = true; - - HUlib_init_multiline(&w_speed, 1, - &boom_font, colrngs[hudcolor_xyco], - NULL, HU_widget_build_speed); - - HU_set_centered_message(); - - HU_disable_all_widgets(); - HUlib_set_margins(); - - // init crosshair - if (hud_crosshair) - HU_StartCrosshair(); - - // now allow the heads-up display to run - headsupactive = true; -} - -static void HU_widget_build_title (void) -{ - InitStringBuffer(""); - - char *s, *n; - - if (gamemapinfo && gamemapinfo->levelname) - { - if (gamemapinfo->label) - s = gamemapinfo->label; - else - s = gamemapinfo->mapname; - - if (s == gamemapinfo->mapname || U_CheckField(s)) - { - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), "%s: ", s); - } - s = gamemapinfo->levelname; - } - else if (gamestate == GS_LEVEL) - { - if (VANILLAMAP(gameepisode, gamemap)) - { - s = (gamemode != commercial) ? HU_TITLE : - (gamemission == pack_tnt) ? HU_TITLET : - (gamemission == pack_plut) ? HU_TITLEP : - HU_TITLE2; - } - // WADs like pl2.wad have a MAP33, and rely on the layout in the - // Vanilla executable, where it is possible to overflow the end of one - // array into the next. - else if (gamemode == commercial && gamemap >= 33 && gamemap <= 35) - { - s = (gamemission == doom2) ? (*mapnamesp[gamemap-33]) : - (gamemission == pack_plut) ? (*mapnamest[gamemap-33]) : ""; - } - else - { - // initialize the map title widget with the generic map lump name - s = MAPNAME(gameepisode, gamemap); - } - } - else - { - s = ""; - } - - // [FG] cap at line break - if ((n = strchr(s, '\n'))) - { - *n = '\0'; - } - - if (hud_map_announce && leveltime == 0) - { - title_counter = HU_MSGTIMEOUT2; - } - - M_StringConcat(hud_stringbuffer, s, sizeof(hud_stringbuffer)); - - HUlib_add_string_to_cur_line(&w_title, hud_stringbuffer); -} - -// do the hud ammo display -static crange_idx_e CRByAmmo(const int ammo, const int fullammo, int ammopct) -{ - // backpack changes thresholds (ammo widget) - if (plr->backpack && !hud_backpack_thresholds && fullammo) - ammopct = (100 * ammo) / (fullammo / 2); - - // set the display color from the percentage of total ammo held - if (ammopct < ammo_red) - return CR_RED; - else if (ammopct < ammo_yellow) - return CR_GOLD; - else if (ammopct > 100) // more than max threshold w/o backpack - return CR_BLUE; - else - return CR_GREEN; -} - -static void HU_widget_build_ammo (void) -{ - InitStringBuffer("AMM "); - - int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo]; - int i = 4; - - // special case for weapon with no ammo selected - blank bargraph + N/A - if (weaponinfo[plr->readyweapon].ammo == am_noammo || fullammo == 0) - { - if (hud_type == HUD_TYPE_BOOM) - { - strcat(hud_stringbuffer, "\x7f\x7f\x7f\x7f\x7f\x7f\x7f"); - } - strcat(hud_stringbuffer, "N/A"); - w_ammo.cr = colrngs[CR_GRAY]; - } - else - { - int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo]; - int ammopct = (100 * ammo) / fullammo; - int ammobars = ammopct / 4; - - // build the bargraph string - if (hud_type == HUD_TYPE_BOOM) - { - // full bargraph chars - for (i = 4; i < 4 + ammobars / 4;) - hud_stringbuffer[i++] = 123; - - // plus one last character with 0, 1, 2, 3 bars - switch (ammobars % 4) - { - case 0: - break; - case 1: - hud_stringbuffer[i++] = 126; - break; - case 2: - hud_stringbuffer[i++] = 125; - break; - case 3: - hud_stringbuffer[i++] = 124; - break; - } - - // pad string with blank bar characters - while (i < 4 + 7) - hud_stringbuffer[i++] = 127; - hud_stringbuffer[i] = '\0'; - } - - // build the numeric amount init string - M_snprintf(hud_stringbuffer + i, sizeof(hud_stringbuffer) - i, - "%3d/%3d", ammo, fullammo); - - const crange_idx_e cr = CRByAmmo(ammo, fullammo, ammopct); - w_ammo.cr = colrngs[cr]; - } - - // transfer the init string to the widget - HUlib_add_string_to_cur_line(&w_ammo, hud_stringbuffer); -} - -// do the hud health display -static void HU_widget_build_health (void) -{ - InitStringBuffer("HEL "); - - int i = 4; - int healthbars = (st_health > 100) ? 25 : (st_health / 4); - - // build the bargraph string - if (hud_type == HUD_TYPE_BOOM) - { - // full bargraph chars - for (i = 4; i < 4 + healthbars / 4;) - hud_stringbuffer[i++] = 123; - - // plus one last character with 0, 1, 2, 3 bars - switch (healthbars % 4) - { - case 0: - break; - case 1: - hud_stringbuffer[i++] = 126; - break; - case 2: - hud_stringbuffer[i++] = 125; - break; - case 3: - hud_stringbuffer[i++] = 124; - break; - } - - // pad string with blank bar characters - while (i < 4 + 7) - hud_stringbuffer[i++] = 127; - hud_stringbuffer[i] = '\0'; - } - - // build the numeric amount init string - M_snprintf(hud_stringbuffer + i, sizeof(hud_stringbuffer) - i, - "%3d", st_health); - - // set the display color from the amount of health posessed - w_health.cr = HU_ColorByHealth(plr->health, 100, st_invul); - - // transfer the init string to the widget - HUlib_add_string_to_cur_line(&w_health, hud_stringbuffer); -} - -// do the hud armor display -static crange_idx_e CRByArmor(void) -{ - // color of armor depends on type - if (hud_armor_type) - { - return - st_invul ? CR_GRAY : - (plr->armortype == 0) ? CR_RED : - (plr->armortype == 1) ? CR_GREEN : - CR_BLUE; - } - else - { - const int armor = plr->armorpoints; - - // set the display color from the amount of armor posessed - return - st_invul ? CR_GRAY : - (armor < armor_red) ? CR_RED : - (armor < armor_yellow) ? CR_GOLD : - (armor <= armor_green) ? CR_GREEN : - CR_BLUE; - } -} - -static void HU_widget_build_armor (void) -{ - InitStringBuffer("ARM "); - - int i = 4; - int armorbars = (st_armor > 100) ? 25 : (st_armor / 4); - - // build the bargraph string - if (hud_type == HUD_TYPE_BOOM) - { - // full bargraph chars - for (i = 4; i < 4 + armorbars / 4;) - hud_stringbuffer[i++] = 123; - - // plus one last character with 0, 1, 2, 3 bars - switch (armorbars % 4) - { - case 0: - break; - case 1: - hud_stringbuffer[i++] = 126; - break; - case 2: - hud_stringbuffer[i++] = 125; - break; - case 3: - hud_stringbuffer[i++] = 124; - break; - } - - // pad string with blank bar characters - while (i < 4 + 7) - hud_stringbuffer[i++] = 127; - hud_stringbuffer[i] = '\0'; - } - - // build the numeric amount init string - M_snprintf(hud_stringbuffer + i, sizeof(hud_stringbuffer) - i, "%3d", st_armor); - - const crange_idx_e cr = CRByArmor(); - w_armor.cr = colrngs[cr]; - - // transfer the init string to the widget - HUlib_add_string_to_cur_line(&w_armor, hud_stringbuffer); -} - -static void HU_widget_build_compact (void) -{ - const crange_idx_e cr_health = CRByHealth(plr->health, 100, st_invul); - const crange_idx_e cr_armor = CRByArmor(); - - const ammotype_t ammotype = weaponinfo[plr->readyweapon].ammo; - const int ammo = plr->ammo[ammotype]; - const int fullammo = plr->maxammo[ammotype]; - const boolean noammo = (ammotype == am_noammo || fullammo == 0); - - if (hud_widget_layout) - { - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cHEL \x1b%c%3d", '0'+CR_GRAY, '0'+cr_health, st_health); - HUlib_add_string_to_cur_line(&w_compact, hud_stringbuffer); - - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cARM \x1b%c%3d", '0'+CR_GRAY, '0'+cr_armor, st_armor); - HUlib_add_string_to_cur_line(&w_compact, hud_stringbuffer); - - if (noammo) - { - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cAMM N/A", '0'+CR_GRAY); - } - else - { - const int ammopct = (100 * ammo) / fullammo; - const crange_idx_e cr_ammo = CRByAmmo(ammo, fullammo, ammopct); - - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cAMM \x1b%c%3d/%3d", '0'+CR_GRAY, '0'+cr_ammo, ammo, fullammo); - } - HUlib_add_string_to_cur_line(&w_compact, hud_stringbuffer); - } - else - { - if (noammo) - { - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cHEL \x1b%c%3d \x1b%cARM \x1b%c%3d \x1b%cAMM N/A", - '0'+CR_GRAY, '0'+cr_health, st_health, - '0'+CR_GRAY, '0'+cr_armor, st_armor, - '0'+CR_GRAY); - } - else - { - const int ammopct = (100 * ammo) / fullammo; - const crange_idx_e cr_ammo = CRByAmmo(ammo, fullammo, ammopct); - - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cHEL \x1b%c%3d \x1b%cARM \x1b%c%3d \x1b%cAMM \x1b%c%3d/%3d", - '0'+CR_GRAY, '0'+cr_health, st_health, - '0'+CR_GRAY, '0'+cr_armor, st_armor, - '0'+CR_GRAY, '0'+cr_ammo, ammo, fullammo); - } - HUlib_add_string_to_cur_line(&w_compact, hud_stringbuffer); - } -} - -// do the hud weapon display -static void HU_widget_build_weapon (void) -{ - InitStringBuffer("WEA "); - - int i = 4, w, ammo, fullammo, ammopct; - - // do each weapon that exists in current gamemode - for (w = 0; w <= wp_supershotgun; w++) //jff 3/4/98 show fists too, why not? - { - int ok = 1; - - //jff avoid executing for weapons that do not exist - switch (gamemode) - { - case shareware: - if (w >= wp_plasma && w != wp_chainsaw) - ok = 0; - break; - case retail: - case registered: - if (w >= wp_supershotgun && !ALLOW_SSG) - ok = 0; - break; - default: - case commercial: - break; - } - if (!ok) - continue; - - ammo = plr->ammo[weaponinfo[w].ammo]; - fullammo = plr->maxammo[weaponinfo[w].ammo]; - - // skip weapons not currently posessed - if (!plr->weaponowned[w]) - continue; - - // backpack changes thresholds (weapon widget) - if (plr->backpack && !hud_backpack_thresholds) - fullammo /= 2; - - ammopct = fullammo ? (100 * ammo) / fullammo : 100; - - // display each weapon number in a color related to the ammo for it - hud_stringbuffer[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths - if (weaponinfo[w].ammo == am_noammo) //jff 3/14/98 show berserk on HUD - hud_stringbuffer[i++] = (w == wp_fist && !plr->powers[pw_strength]) ? '0'+CR_GRAY : '0'+CR_GREEN; - else if (ammopct < ammo_red) - hud_stringbuffer[i++] = '0'+CR_RED; - else if (ammopct < ammo_yellow) - hud_stringbuffer[i++] = '0'+CR_GOLD; - else if (ammopct > 100) // more than max threshold w/o backpack - hud_stringbuffer[i++] = '0'+CR_BLUE; - else - hud_stringbuffer[i++] = '0'+CR_GREEN; - - hud_stringbuffer[i++] = '0'+w+1; - hud_stringbuffer[i++] = ' '; - hud_stringbuffer[i] = '\0'; - } - - // transfer the init string to the widget - HUlib_add_string_to_cur_line(&w_weapon, hud_stringbuffer); -} - -static void HU_widget_build_keys (void) -{ - const char hud_keysstr[] = { 'K', 'E', 'Y', '\x1b', '0'+CR_NONE, ' ', '\0' }; - InitStringBuffer(hud_keysstr); - - int i = 6, k; - - // build text string whose characters call out graphic keys - for (k = 0; k < 6; k++) - { - // skip keys not possessed - if (!plr->cards[k]) - continue; - - hud_stringbuffer[i++] = HU_FONTEND + k + 1; // key number plus HU_FONTEND is char for key - hud_stringbuffer[i++] = ' '; // spacing - hud_stringbuffer[i++] = ' '; - } - - // [Alaux] Blink missing keys *after* possessed keys - for (k = 0; k < 6; k++) - { - if (plr->cards[k]) - continue; - - switch (ST_BlinkKey(plr, k % 3)) - { - case KEYBLINK_CARD: - if (k >= 3) - continue; - break; - - case KEYBLINK_SKULL: - if (k < 3) - continue; - break; - - case KEYBLINK_BOTH: - break; - - default: - continue; - } - - hud_stringbuffer[i++] = HU_FONTEND + k + 1; - hud_stringbuffer[i++] = ' '; - hud_stringbuffer[i++] = ' '; - } - - hud_stringbuffer[i] = '\0'; - - // transfer the built string (frags or key title) to the widget - HUlib_add_string_to_cur_line(&w_keys, hud_stringbuffer); -} - -static inline int HU_top (int i, const int idx1, const int top1) -{ - if (idx1 > -1) - { - char numbuf[32], *s; - - M_snprintf(numbuf, sizeof(numbuf), "%5d", top1); - // make frag count in player's color via escape code - - hud_stringbuffer[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths - hud_stringbuffer[i++] = '0' + plyrcoltran[idx1 & 3]; - s = numbuf; - while (*s) - hud_stringbuffer[i++] = *s++; - } - return i; -} - -static void HU_widget_build_frag (void) -{ - const char hud_fragstr[] = { 'F', 'R', 'G', '\x1b', '0'+CR_ORIG, ' ', '\0' }; - InitStringBuffer(hud_fragstr); - - int i = 6, k; - - int top1 = -999, top2 = -999, top3 = -999, top4 = -999; - int idx1 = -1, idx2 = -1, idx3 = -1, idx4 = -1; - int fragcount, m; - - // scan thru players - for (k = 0; k < MAXPLAYERS; k++) - { - // skip players not in game - if (!playeringame[k]) - continue; - - fragcount = 0; - - // compute number of times they've fragged each player - // minus number of times they've been fragged by them - for (m = 0; m < MAXPLAYERS; m++) - { - if (!playeringame[m]) - continue; - fragcount += (m != k) ? players[k].frags[m] : -players[k].frags[m]; - } - - // very primitive sort of frags to find top four - if (fragcount > top1) - { - top4 = top3; top3 = top2; top2 = top1; top1 = fragcount; - idx4 = idx3; idx3 = idx2; idx2 = idx1; idx1 = k; - } - else if (fragcount > top2) - { - top4 = top3; top3 = top2; top2 = fragcount; - idx4 = idx3; idx3 = idx2; idx2 = k; - } - else if (fragcount > top3) - { - top4 = top3; top3 = fragcount; - idx4 = idx3; idx3 = k; - } - else if (fragcount > top4) - { - top4 = fragcount; - idx4 = k; - } - } - - // killough 11/98: replaced cut-and-pasted code with function - - // if the biggest number exists, - // put it in the init string - i = HU_top(i, idx1, top1); - - // if the second biggest number exists, - // put it in the init string - i = HU_top(i, idx2, top2); - - // if the third biggest number exists, - // put it in the init string - i = HU_top(i, idx3, top3); - - // if the fourth biggest number exists, - // put it in the init string - i = HU_top(i, idx4, top4); - - hud_stringbuffer[i] = '\0'; - - // transfer the built string (frags or key title) to the widget - HUlib_add_string_to_cur_line(&w_keys, hud_stringbuffer); -} - -static void HU_widget_build_monsec(void) -{ - int i; - int fullkillcount, fullitemcount, fullsecretcount; - int killcolor, itemcolor, secretcolor; - int kill_percent_count; - - fullkillcount = 0; - fullitemcount = 0; - fullsecretcount = 0; - kill_percent_count = 0; - - for (i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i]) - { - fullkillcount += players[i].killcount - players[i].maxkilldiscount; - fullitemcount += players[i].itemcount; - fullsecretcount += players[i].secretcount; - kill_percent_count += players[i].killcount; - } - } - - if (respawnmonsters) - { - fullkillcount = kill_percent_count; - max_kill_requirement = totalkills; - } - - killcolor = (fullkillcount >= max_kill_requirement) ? '0'+CR_BLUE : '0'+CR_GRAY; - secretcolor = (fullsecretcount >= totalsecret) ? '0'+CR_BLUE : '0'+CR_GRAY; - itemcolor = (fullitemcount >= totalitems) ? '0'+CR_BLUE : '0'+CR_GRAY; - - if (hud_widget_layout) - { - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cK\t\x1b%c%d/%d", ('0'+CR_RED), killcolor, fullkillcount, max_kill_requirement); - HUlib_add_string_to_cur_line(&w_monsec, hud_stringbuffer); - - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cI\t\x1b%c%d/%d", ('0'+CR_RED), itemcolor, fullitemcount, totalitems); - HUlib_add_string_to_cur_line(&w_monsec, hud_stringbuffer); - - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cS\t\x1b%c%d/%d", ('0'+CR_RED), secretcolor, fullsecretcount, totalsecret); - HUlib_add_string_to_cur_line(&w_monsec, hud_stringbuffer); - } - else - { - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "\x1b%cK \x1b%c%d/%d \x1b%cI \x1b%c%d/%d \x1b%cS \x1b%c%d/%d", - '0'+CR_RED, killcolor, fullkillcount, max_kill_requirement, - '0'+CR_RED, itemcolor, fullitemcount, totalitems, - '0'+CR_RED, secretcolor, fullsecretcount, totalsecret); - - HUlib_add_string_to_cur_line(&w_monsec, hud_stringbuffer); - } -} - -static void HU_widget_build_sttime(void) -{ - InitStringBuffer(""); - - int offset = 0; - - if ((hud_level_time & HUD_WIDGET_HUD && !automapactive) || - (hud_level_time & HUD_WIDGET_AUTOMAP && automapactive)) - { - if (time_scale != 100) - { - offset += M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), "\x1b%c%d%% ", - '0'+CR_BLUE, time_scale); - } - - if (totalleveltimes) - { - const int time = (totalleveltimes + leveltime) / TICRATE; - - offset += M_snprintf(hud_stringbuffer + offset, sizeof(hud_stringbuffer) - offset, - "\x1b%c%d:%02d ", - '0'+CR_GREEN, time/60, time%60); - } - - if (!plr->btuse_tics) - { - M_snprintf(hud_stringbuffer + offset, sizeof(hud_stringbuffer) - offset, - "\x1b%c%d:%05.2f\t", - '0'+CR_GRAY, leveltime / TICRATE / 60, - (float)(leveltime % (60 * TICRATE)) / TICRATE); - } - } - - if (plr->btuse_tics) - { - M_snprintf(hud_stringbuffer + offset, sizeof(hud_stringbuffer) - offset, - "\x1b%cU %d:%05.2f\t", - '0'+CR_GOLD, plr->btuse / TICRATE / 60, - (float)(plr->btuse % (60 * TICRATE)) / TICRATE); - } - - HUlib_add_string_to_cur_line(&w_sttime, hud_stringbuffer); -} - -void HU_widget_rebuild_sttime(void) -{ - HU_widget_build_sttime(); -} - -static void HU_widget_build_coord (void) -{ - fixed_t x,y,z; // killough 10/98: - void AM_Coordinates(const mobj_t *, fixed_t *, fixed_t *, fixed_t *); - - if (hud_player_coords == HUD_WIDGET_ADVANCED) - { - HU_BuildCoordinatesEx(&w_coord, plr->mo, hud_stringbuffer, - sizeof(hud_stringbuffer)); - return; - } - - // killough 10/98: allow coordinates to display non-following pointer - AM_Coordinates(plr->mo, &x, &y, &z); - - //jff 2/16/98 output new coord display - if (hud_widget_layout) - { - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), "X\t\x1b%c%d", '0'+CR_GRAY, x >> FRACBITS); - HUlib_add_string_to_cur_line(&w_coord, hud_stringbuffer); - - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), "Y\t\x1b%c%d", '0'+CR_GRAY, y >> FRACBITS); - HUlib_add_string_to_cur_line(&w_coord, hud_stringbuffer); - - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), "Z\t\x1b%c%d", '0'+CR_GRAY, z >> FRACBITS); - HUlib_add_string_to_cur_line(&w_coord, hud_stringbuffer); - } - else - { - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), "X \x1b%c%d \x1b%cY \x1b%c%d \x1b%cZ \x1b%c%d", - '0'+CR_GRAY, x >> FRACBITS, '0'+hudcolor_xyco, - '0'+CR_GRAY, y >> FRACBITS, '0'+hudcolor_xyco, - '0'+CR_GRAY, z >> FRACBITS); - - HUlib_add_string_to_cur_line(&w_coord, hud_stringbuffer); - } -} - -static void HU_widget_build_fps (void) -{ - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), "\x1b%c%d \x1b%cFPS", - '0'+CR_GRAY, fps, '0'+CR_ORIG); - HUlib_add_string_to_cur_line(&w_fps, hud_stringbuffer); -} - -static void HU_widget_build_rate (void) -{ - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), - "Sprites %4d Segs %4d Visplanes %4d \x1b%cFPS %3d %dx%d\x1b%c", - rendered_vissprites, rendered_segs, rendered_visplanes, - '0'+CR_GRAY, fps, video.width, video.height, '0'+CR_ORIG); - HUlib_add_string_to_cur_line(&w_rate, hud_stringbuffer); - - if (voxels_rendering) - { - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), " Voxels %4d", rendered_voxels); - HUlib_add_string_to_cur_line(&w_rate, hud_stringbuffer); - } -} - -static void HU_widget_build_cmd(void) -{ - HU_BuildCommandHistory(&w_cmd); -} - -int speedometer; - -static void HU_widget_build_speed(void) -{ - static const double factor[] = {TICRATE, 2.4003, 525.0 / 352.0}; - static const char *units[] = {"ups", "km/h", "mph"}; - const int type = speedometer - 1; - const double dx = FIXED2DOUBLE(plr->mo->x - plr->mo->oldx); - const double dy = FIXED2DOUBLE(plr->mo->y - plr->mo->oldy); - const double dz = FIXED2DOUBLE(plr->mo->z - plr->mo->oldz); - const double speed = sqrt(dx*dx + dy*dy + dz*dz) * factor[type]; - - M_snprintf(hud_stringbuffer, sizeof(hud_stringbuffer), "\x1b%c%.*f \x1b%c%s", - '0' + CR_GRAY, type && speed ? 1 : 0, speed, - '0' + CR_ORIG, units[type]); - HUlib_add_string_to_cur_line(&w_speed, hud_stringbuffer); -} - -// [crispy] print a bar indicating demo progress at the bottom of the screen -boolean HU_DemoProgressBar(boolean force) -{ - const int progress = video.unscaledw * playback_tic / playback_totaltics; - static int old_progress = 0; - - if (old_progress < progress) - { - old_progress = progress; - } - else if (!force) - { - return false; - } - - V_FillRect(0, SCREENHEIGHT - 2, progress, 1, v_darkest_color); - V_FillRect(0, SCREENHEIGHT - 1, progress, 1, v_lightest_color); - - return true; -} - -// [FG] level stats and level time widgets -int hud_player_coords, hud_level_stats, hud_level_time; - -boolean hud_time_use; - -// -// HU_Drawer() -// -// Draw all the pieces of the heads-up display -// -// Passed nothing, returns nothing -// -void HU_Drawer(void) -{ - hu_widget_t *w = widgets[hud_active]; - - if (hud_pending) - return; - - HUlib_reset_align_offsets(); - - while (w->multiline) - { - if ((w->multiline->on && *w->multiline->on) || w->multiline->built) - { - HUlib_draw_widget(w); - } - w++; - } - - if (draw_crispy_hud) - { - ST_Drawer (false, true); - } -} - -// [FG] draw Time widget on intermission screen -void WI_DrawWidgets(void) -{ - HUlib_reset_align_offsets(); - - if (hud_level_time & HUD_WIDGET_HUD) - { - const hu_widget_t w = {&w_sttime, align_left, align_top}; - // leveltime is already added to totalleveltimes before WI_Start() - //HU_widget_build_sttime(); - HUlib_draw_widget(&w); - } - - if (STRICTMODE(hud_command_history)) - { - hu_widget_t *w = widgets[hud_active]; - - while (w->multiline) - { - if (w->multiline == &w_cmd - && ((w->multiline->on && *w->multiline->on) || w->multiline->built)) - { - w_cmd.built = false; - HU_cond_build_widget(&w_cmd, true); - HUlib_draw_widget(w); - break; - } - w++; - } - } -} - -// -// HU_Erase() -// -// Erase hud display lines that can be trashed by small screen display -// -// Passed nothing, returns nothing -// - -void HU_Erase(void) -{ - hu_widget_t *w = widgets[hud_active]; - - if (automapactive || !scaledviewx) - return; - - HUlib_reset_align_offsets(); - - while (w->multiline) - { - if (w->multiline->on || w->multiline->built) - { - HUlib_erase_widget(w); - } - w++; - } -} - -// -// HU_Ticker() -// -// Update the hud displays once per frame -// -// Passed nothing, returns nothing -// - -static boolean bsdown; // Is backspace down? -static int bscounter; - -void HU_Ticker(void) -{ - plr = &players[displayplayer]; // killough 3/7/98 - - HU_disable_all_widgets(); - draw_crispy_hud = false; - - if ((automapactive && hud_widget_font == 1) || - (!automapactive && hud_widget_font == 2) || - hud_widget_font == 3) - { - boom_font = &big_font; - CR_BLUE = CR_BLUE2; - } - else - { - boom_font = &sml_font; - CR_BLUE = CR_BLUE1; - } - - // wait a few tics before sending a backspace character - if (bsdown && bscounter++ > 9) - { - HUlib_add_key_to_cur_line(&w_chat, KEY_BACKSPACE); - bscounter = 8; - } - - // tick down message counter if message is up - if (message_counter && !--message_counter) - message_on = message_nottobefuckedwith = false; - - if (secret_counter && !--secret_counter) - secret_on = false; - - // [Woof!] "A secret is revealed!" message - if (plr->secretmessage) - { - HUlib_add_string_to_cur_line(&w_secret, plr->secretmessage); - plr->secretmessage = NULL; - secret_on = true; - secret_counter = HU_MSGTIMEOUT2; - } - - // if messages on, or "Messages Off" is being displayed - // this allows the notification of turning messages off to be seen - // display message if necessary - - if ((show_messages || message_dontfuckwithme) && plr->message && - (!message_nottobefuckedwith || message_dontfuckwithme)) - { - //post the message to the message widget - HUlib_add_string_to_cur_line(&w_message, plr->message); - - // [FG] empty messages clear the whole widget - if (plr->message[0] == '\0') - HUlib_clear_all_lines(&w_message); - - // clear the message to avoid posting multiple times - plr->message = 0; - - message_on = true; // note a message is displayed - // start the message persistence counter - message_counter = message_count; - - has_message = true; // killough 12/98 - - // transfer "Messages Off" exception to the "being displayed" variable - message_nottobefuckedwith = message_dontfuckwithme; - - // clear the flag that "Messages Off" is being posted - message_dontfuckwithme = 0; - } - - // check for incoming chat characters - if (netgame) - { - int i, rc; - char c; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - if (i != consoleplayer && - (c = players[i].cmd.chatchar)) - { - if (c <= HU_BROADCAST) - chat_dest[i] = c; - else - { - if (c >= 'a' && c <= 'z') - c = (char) shiftxform[(unsigned char) c]; - - rc = HUlib_add_key_to_line(&w_inputbuffer[i], c); - if (rc && c == KEY_ENTER) - { - if (w_inputbuffer[i].len && - (chat_dest[i] == consoleplayer + 1 || - chat_dest[i] == HU_BROADCAST)) - { - HUlib_add_strings_to_cur_line(&w_message, - *player_names[i], - w_inputbuffer[i].line); - - has_message = true; // killough 12/98 - message_nottobefuckedwith = true; - message_on = true; - message_counter = chat_count; // killough 11/98 - S_StartSoundPitch(0, gamemode == commercial ? - sfx_radio : sfx_tink, PITCH_NONE); - } - HUlib_clear_line(&w_inputbuffer[i]); - } - } - players[i].cmd.chatchar = 0; - } - } - } - - // draw the automap widgets if automap is displayed - - if (title_counter) - { - title_counter--; - } - - if (automapactive) - { - HU_cond_build_widget(w_stats, hud_level_stats & HUD_WIDGET_AUTOMAP); - HU_cond_build_widget(&w_sttime, hud_level_time & HUD_WIDGET_AUTOMAP || plr->btuse_tics); - HU_cond_build_widget(&w_coord, STRICTMODE(hud_player_coords == HUD_WIDGET_AUTOMAP - || hud_player_coords >= HUD_WIDGET_ALWAYS)); - - title_on = true; - } - else - { - HU_cond_build_widget(w_stats, hud_level_stats & HUD_WIDGET_HUD); - HU_cond_build_widget(&w_sttime, hud_level_time & HUD_WIDGET_HUD || plr->btuse_tics); - HU_cond_build_widget(&w_coord, STRICTMODE(hud_player_coords >= HUD_WIDGET_HUD)); - - title_on = (title_counter > 0); - } - - HU_cond_build_widget(&w_fps, plr->cheats & CF_SHOWFPS); - HU_cond_build_widget(&w_rate, plr->cheats & CF_RENDERSTATS); - HU_cond_build_widget(&w_cmd, STRICTMODE(hud_command_history)); - HU_cond_build_widget(&w_speed, speedometer > 0); - - if (hud_displayed && - scaledviewheight == SCREENHEIGHT && - automap_off) - { - if (hud_type == HUD_TYPE_CRISPY) - { - if (hud_active > 0) - { - draw_crispy_hud = true; - } - } - else - { - HU_cond_build_widget(&w_weapon, true); - HU_cond_build_widget(&w_armor, true); - HU_cond_build_widget(&w_health, true); - HU_cond_build_widget(&w_ammo, true); - HU_cond_build_widget(&w_keys, true); - - HU_cond_build_widget(&w_compact, true); - } - } - - if (plr->btuse_tics) - plr->btuse_tics--; - - // update crosshair properties - if (hud_crosshair) - HU_UpdateCrosshair(); - - hud_pending = false; -} - -#define QUEUESIZE 128 - -static char chatchars[QUEUESIZE]; -static int head = 0; -static int tail = 0; - -// -// HU_queueChatChar() -// -// Add an incoming character to the circular chat queue -// -// Passed the character to queue, returns nothing -// -void HU_queueChatChar(char c) -{ - if (((head + 1) & (QUEUESIZE-1)) == tail) - displaymsg("%s", HUSTR_MSGU); - else - { - chatchars[head++] = c; - head &= QUEUESIZE-1; - } -} - -// -// HU_dequeueChatChar() -// -// Remove the earliest added character from the circular chat queue -// -// Passed nothing, returns the character dequeued -// -char HU_dequeueChatChar(void) -{ - char c; - - if (head != tail) - { - c = chatchars[tail++]; - tail &= QUEUESIZE-1; - } - else - c = 0; - return c; -} - -// -// HU_Responder() -// -// Responds to input events that affect the heads up displays -// -// Passed the event to respond to, returns true if the event was handled -// - -boolean HU_Responder(event_t *ev) -{ - static char lastmessage[HU_MAXLINELENGTH+1]; - const char *macromessage; - boolean eatkey = false; - static boolean shiftdown = false; - static boolean altdown = false; - int c; - int i; - int numplayers; - - static int num_nobrainers = 0; - - c = (ev->type == ev_keydown) ? ev->data1.i : 0; - - numplayers = 0; - for (i=0 ; idata1.i == KEY_RSHIFT) - { - shiftdown = ev->type == ev_keydown; - return false; - } - - if (ev->data1.i == KEY_RALT) - { - altdown = ev->type == ev_keydown; - return false; - } - - if (M_InputActivated(input_chat_backspace)) - { - bsdown = true; - bscounter = 0; - c = KEY_BACKSPACE; - } - else if (M_InputDeactivated(input_chat_backspace)) - { - bsdown = false; - bscounter = 0; - } - - if (ev->type == ev_keyup) - return false; - - if (!chat_on) - { - if (M_InputActivated(input_chat_enter)) // phares - { - //jff 2/26/98 toggle list of messages - - if (has_message) - { - message_counter = message_count; - message_on = true; - } - eatkey = true; - } //jff 2/26/98 no chat if message review is displayed - else // killough 10/02/98: no chat if demo playback - if (!demoplayback) - { - if (netgame && M_InputActivated(input_chat)) - { - eatkey = chat_on = true; - HUlib_clear_cur_line(&w_chat); - HU_queueChatChar(HU_BROADCAST); - }//jff 2/26/98 - else // killough 11/98: simplify - if (netgame && numplayers > 2) - for (i=0; i 9) - return false; - // fprintf(stderr, "got here\n"); - macromessage = chat_macros[c]; - - // kill last message with a '\n' - HU_queueChatChar(KEY_ENTER); // DEBUG!!! // phares - - // send the macro message - while (*macromessage) - HU_queueChatChar(*macromessage++); - HU_queueChatChar(KEY_ENTER); // phares - - // leave chat mode and notify that it was sent - chat_on = false; - strcpy(lastmessage, chat_macros[c]); - displaymsg("%s", lastmessage); - eatkey = true; - } - else - { - if (shiftdown || (c >= 'a' && c <= 'z')) - c = shiftxform[c]; - eatkey = HUlib_add_key_to_cur_line(&w_chat, c); - if (eatkey) - HU_queueChatChar(c); - - if (c == KEY_ENTER) // phares - { - chat_on = false; - if (w_chat.lines[0]->len) - { - strcpy(lastmessage, w_chat.lines[0]->line); - displaymsg("%s", lastmessage); - } - } - else - if (c == KEY_ESCAPE) // phares - chat_on = false; - } - } - return eatkey; -} - -// [FG] dynamic HUD alignment - -static const struct { - const char *name, *altname; - hu_multiline_t *const multiline; -} multiline_names[] = { - {"title", NULL, &w_title}, - {"message", NULL, &w_message}, -// [FG] TODO due to its variable width and the trailing cursor, -// the w_chat widget *must* currently remain left-aligned -// {"chat", NULL, &w_chat}, - {"secret", NULL, &w_secret}, - - {"ammo", NULL, &w_ammo}, - {"armor", NULL, &w_armor}, - {"health", NULL, &w_health}, - {"keys", NULL, &w_keys}, - {"weapon", "weapons", &w_weapon}, - - {"compact", NULL, &w_compact}, - - {"monsec", "stats", &w_monsec}, - {"sttime", "time", &w_sttime}, - {"coord", "coords", &w_coord}, - {"fps", NULL, &w_fps}, - {"rate", NULL, &w_rate}, - {"cmd", "commands", &w_cmd}, - {"speed", NULL, &w_speed}, - {NULL}, -}; - -static boolean HU_ReplaceInWidgets (hu_multiline_t *multiline, int hud, align_t h_align, align_t v_align, int x, int y) -{ - int i; - - if (hud < 0 || hud >= MAX_HUDS) - { - return false; - } - - for (i = 0; i < MAX_WIDGETS - 1; i++) - { - if (widgets[hud][i].multiline == NULL) - { - break; - } - - if (widgets[hud][i].multiline == multiline) - { - widgets[hud][i].h_align = h_align; - widgets[hud][i].v_align = v_align; - widgets[hud][i].x = x; - widgets[hud][i].y = y; - - // [FG] save original alignment - widgets[hud][i].h_align_orig = widgets[hud][i].h_align; - - return true; - } - } - - return false; -} - -static boolean HU_AppendToWidgets (hu_multiline_t *multiline, int hud, align_t h_align, align_t v_align, int x, int y) -{ - int i; - - if (hud < 0 || hud >= MAX_HUDS) - { - return false; - } - - for (i = 0; i < MAX_WIDGETS - 1; i++) - { - if (widgets[hud][i].multiline == NULL) - { - break; - } - } - - if (i + 1 >= MAX_WIDGETS) - { - return false; - } - - widgets[hud][i].multiline = multiline; - widgets[hud][i].h_align = h_align; - widgets[hud][i].v_align = v_align; - widgets[hud][i].x = x; - widgets[hud][i].y = y; - - // [FG] save original alignment - widgets[hud][i].h_align_orig = widgets[hud][i].h_align; - - widgets[hud][i + 1].multiline = NULL; - - return true; -} - -static boolean HU_AddToWidgets (hu_multiline_t *multiline, int hud, align_t h_align, align_t v_align, int x, int y) -{ - if (HU_ReplaceInWidgets(multiline, hud, h_align, v_align, x, y)) - { - return true; - } - else if (HU_AppendToWidgets(multiline, hud, h_align, v_align, x, y)) - { - return true; - } - - return false; -} - -static hu_multiline_t *HU_MultilineByName (const char *name) -{ - int i; - - for (i = 0; multiline_names[i].name; i++) - { - if (strcasecmp(name, multiline_names[i].name) == 0 || - (multiline_names[i].altname && strcasecmp(name, multiline_names[i].altname) == 0)) - { - return multiline_names[i].multiline; - } - } - - return NULL; -} - -static boolean HU_AddHUDCoords (char *name, int hud, int x, int y) -{ - hu_multiline_t *multiline = HU_MultilineByName(name); - - if (multiline == NULL) - { - return false; - } - - // [FG] relative alignment to the edges - if (x < 0) - { - x += SCREENWIDTH; - } - if (y < 0) - { - y += SCREENHEIGHT; - } - - if (x < 0 || x >= SCREENWIDTH || y < 0 || y >= SCREENHEIGHT) - { - return false; - } - - return HU_AddToWidgets(multiline, hud, align_direct, align_direct, x, y); -} - -static boolean HU_AddHUDAlignment (char *name, int hud, char *alignstr) -{ - hu_multiline_t *multiline = HU_MultilineByName(name); - - if (multiline == NULL) - { - return false; - } - - if (!strcasecmp(alignstr, "topleft") || !strcasecmp(alignstr, "upperleft")) - { - return HU_AddToWidgets(multiline, hud, align_left, align_top, 0, 0); - } - else if (!strcasecmp(alignstr, "topright") || !strcasecmp(alignstr, "upperright")) - { - return HU_AddToWidgets(multiline, hud, align_right, align_top, 0, 0); - } - else if (!strcasecmp(alignstr, "topcenter") || !strcasecmp(alignstr, "uppercenter")) - { - return HU_AddToWidgets(multiline, hud, align_center, align_top, 0, 0); - } - else if (!strcasecmp(alignstr, "bottomleft") || !strcasecmp(alignstr, "lowerleft")) - { - return HU_AddToWidgets(multiline, hud, align_left, align_bottom, 0, 0); - } - else if (!strcasecmp(alignstr, "bottomright") || !strcasecmp(alignstr, "lowerright")) - { - return HU_AddToWidgets(multiline, hud, align_right, align_bottom, 0, 0); - } - else if (!strcasecmp(alignstr, "bottomcenter")|| !strcasecmp(alignstr, "lowercenter")) - { - return HU_AddToWidgets(multiline, hud, align_center, align_bottom, 0, 0); - } - - return false; -} - -static void HU_ParseHUD (void) -{ - u_scanner_t *s; - int hud; - int lumpnum; - const char *data; - int length; - - // [FG] initialize HUDs with Vanilla Doom widgets - for (hud = 0; hud < MAX_HUDS; hud++) - { - HU_AddToWidgets(&w_title, hud, align_direct, align_bottom, 0, 0); - HU_AddToWidgets(&w_message, hud, align_direct, align_top, 0, 0); - HU_AddToWidgets(&w_chat, hud, align_direct, align_top, 0, 0); - HU_AddToWidgets(&w_secret , hud, align_center, align_secret, 0, 0); - } - - if ((lumpnum = W_CheckNumForName("WOOFHUD")) == -1) - { - return; - } - - data = W_CacheLumpNum(lumpnum, PU_CACHE); - length = W_LumpLength(lumpnum); - - s = U_ScanOpen(data, length, "WOOFHUD"); - - while (U_HasTokensLeft(s)) - { - char *name; - - if (!U_CheckToken(s, TK_Identifier)) - { - U_GetNextToken(s, true); - continue; - } - - if (!strcasecmp("HUD", s->string)) - { - U_MustGetInteger(s); - hud = s->number; - - if (hud < 0 || hud >= MAX_HUDS) - { - U_Error(s, "HUD (%d) must be between 0 and %d", hud, MAX_HUDS - 1); - } - - continue; - } - - name = M_StringDuplicate(s->string); - - if (U_CheckToken(s, TK_IntConst)) - { - int x, y; - - x = s->number; - U_MustGetInteger(s); - y = s->number; - - if (!HU_AddHUDCoords(name, hud, x, y)) - { - U_Error(s, "Cannot set coordinates for widget (%s)", name); - } - } - else - { - char *align; - - U_MustGetToken(s, TK_Identifier); - align = M_StringDuplicate(s->string); - - if (!HU_AddHUDAlignment(name, hud, align)) - { - U_Error(s, "Cannot set alignment for widget (%s)", name); - } - - free(align); - } - - free(name); - } - - U_ScanClose(s); -} - -void HU_BindHUDVariables(void) -{ - M_BindBool("hud_displayed", &hud_displayed, NULL, false, ss_none, wad_yes, - "Display HUD"); - M_BindNum("hud_active", &hud_active, NULL, 2, 0, 2, ss_stat, wad_yes, - "HUD layout (by default: 0 = Minimal; 1 = Compact; 2 = Distributed)"); - M_BindNum("hud_level_stats", &hud_level_stats, NULL, - HUD_WIDGET_OFF, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, - ss_stat, wad_no, - "Show level stats (kills, items, and secrets) widget (1 = On automap; " - "2 = On HUD; 3 = Always)"); - M_BindNum("hud_level_time", &hud_level_time, NULL, - HUD_WIDGET_OFF, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, - ss_stat, wad_no, - "Show level time widget (1 = On automap; 2 = On HUD; 3 = Always)"); - M_BindNum("hud_player_coords", &hud_player_coords, NULL, - HUD_WIDGET_AUTOMAP, HUD_WIDGET_OFF, HUD_WIDGET_ADVANCED, - ss_stat, wad_no, - "Show player coordinates widget (1 = On automap; 2 = On HUD; 3 = Always; 4 = Advanced)"); - M_BindBool("hud_command_history", &hud_command_history, NULL, false, ss_stat, - wad_no, "Show command history widget"); - BIND_NUM(hud_command_history_size, 10, 1, HU_MAXMESSAGES, - "Number of commands to display for command history widget"); - BIND_BOOL(hud_hide_empty_commands, true, - "Hide empty commands from command history widget"); - M_BindBool("hud_time_use", &hud_time_use, NULL, false, ss_stat, wad_no, - "Show split time when pressing the use-button"); - M_BindNum("hud_type", &hud_type, NULL, - HUD_TYPE_BOOM, HUD_TYPE_CRISPY, NUM_HUD_TYPES - 1, - ss_stat, wad_no, - "Fullscreen HUD type (0 = Crispy; 1 = Boom (No Bars); 2 = Boom)"); - M_BindBool("hud_backpack_thresholds", &hud_backpack_thresholds, NULL, - true, ss_stat, wad_no, "Backpack changes thresholds"); - M_BindBool("hud_armor_type", &hud_armor_type, NULL, false, ss_stat, wad_no, - "Armor count is colored based on armor type"); - M_BindBool("hud_widescreen_widgets", &hud_widescreen_widgets, NULL, - true, ss_stat, wad_no, "Arrange widgets on widescreen edges"); - M_BindNum("hud_widget_font", &hud_widget_font, NULL, - HUD_WIDGET_OFF, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, - ss_stat, wad_no, - "Use standard Doom font for widgets (1 = On automap; 2 = On HUD; 3 " - "= Always)"); - M_BindBool("hud_widget_layout", &hud_widget_layout, NULL, - false, ss_stat, wad_no, "Widget layout (0 = Horizontal; 1 = Vertical)"); - M_BindNum("hud_crosshair", &hud_crosshair, NULL, 0, 0, 10 - 1, ss_stat, wad_no, - "Crosshair"); - M_BindBool("hud_crosshair_health", &hud_crosshair_health, NULL, - false, ss_stat, wad_no, "Change crosshair color based on player health"); - M_BindNum("hud_crosshair_target", &hud_crosshair_target, NULL, - 0, 0, 2, ss_stat, wad_no, - "Change crosshair color when locking on target (1 = Highlight; 2 = Health)"); - M_BindBool("hud_crosshair_lockon", &hud_crosshair_lockon, NULL, - false, ss_stat, wad_no, "Lock crosshair on target"); - M_BindNum("hud_crosshair_color", &hud_crosshair_color, NULL, - CR_GRAY, CR_BRICK, CR_NONE, ss_stat, wad_no, - "Default crosshair color"); - M_BindNum("hud_crosshair_target_color", &hud_crosshair_target_color, NULL, - CR_YELLOW, CR_BRICK, CR_NONE, ss_stat, wad_no, - "Crosshair color when aiming at target"); - - M_BindNum("hudcolor_titl", &hudcolor_titl, NULL, - CR_GOLD, CR_BRICK, CR_NONE, ss_none, wad_yes, - "Color range used for automap level title"); - M_BindNum("hudcolor_xyco", &hudcolor_xyco, NULL, - CR_GREEN, CR_BRICK, CR_NONE, ss_none, wad_yes, - "Color range used for automap coordinates"); - - BIND_BOOL(show_messages, true, "Show messages"); - M_BindBool("hud_secret_message", &hud_secret_message, NULL, - true, ss_stat, wad_no, "Announce revealed secrets"); - M_BindBool("hud_map_announce", &hud_map_announce, NULL, - false, ss_stat, wad_no, "Announce map titles"); - M_BindBool("show_toggle_messages", &show_toggle_messages, NULL, - true, ss_stat, wad_no, "Show toggle messages"); - M_BindBool("show_pickup_messages", &show_pickup_messages, NULL, - true, ss_stat, wad_no, "Show pickup messages"); - M_BindBool("show_obituary_messages", &show_obituary_messages, NULL, - true, ss_stat, wad_no, "Show obituaries"); - - M_BindNum("hudcolor_mesg", &hudcolor_mesg, NULL, CR_NONE, CR_BRICK, CR_NONE, - ss_none, wad_yes, "Color range used for messages during play"); - M_BindNum("hudcolor_chat", &hudcolor_chat, NULL, CR_GOLD, CR_BRICK, CR_NONE, - ss_none, wad_yes, "Color range used for chat messages and entry"); - BIND_NUM(hudcolor_obituary, CR_GRAY, CR_BRICK, CR_NONE, - "Color range used for obituaries"); - - BIND_NUM(message_timer, 4000, 0, UL, "Duration of normal Doom messages (ms)"); - BIND_NUM(chat_msg_timer, 4000, 0, UL, "Duration of chat messages (ms)"); - BIND_NUM(hud_msg_lines, 4, 1, HU_MAXMESSAGES, "Number of message lines for message list"); - M_BindBool("message_colorized", &message_colorized, NULL, - false, ss_stat, wad_no, "Colorize player messages"); - M_BindBool("message_centered", &message_centered, NULL, - false, ss_stat, wad_no, "Center messages horizontally"); - BIND_BOOL(message_list, false, "Use message list"); - -#define BIND_CHAT(num) \ - M_BindStr("chatmacro" #num, &chat_macros[(num)], HUSTR_CHATMACRO##num, \ - wad_yes, "Chat string associated with " #num " key") - - BIND_CHAT(0); - BIND_CHAT(1); - BIND_CHAT(2); - BIND_CHAT(3); - BIND_CHAT(4); - BIND_CHAT(5); - BIND_CHAT(6); - BIND_CHAT(7); - BIND_CHAT(8); - BIND_CHAT(9); -} - -//---------------------------------------------------------------------------- -// -// $Log: hu_stuff.c,v $ -// Revision 1.27 1998/05/10 19:03:41 jim -// formatted/documented hu_stuff -// -// Revision 1.26 1998/05/03 22:25:24 killough -// Provide minimal headers at top; nothing else -// -// Revision 1.25 1998/04/28 15:53:58 jim -// Fix message list bug in small screen mode -// -// Revision 1.24 1998/04/22 12:50:14 jim -// Fix lockout from dynamic message change -// -// Revision 1.23 1998/04/05 10:09:51 jim -// added STCFN096 lump -// -// Revision 1.22 1998/03/28 05:32:12 jim -// Text enabling changes for DEH -// -// Revision 1.19 1998/03/17 20:45:23 jim -// added frags to HUD -// -// Revision 1.18 1998/03/15 14:42:16 jim -// added green fist/chainsaw in HUD when berserk -// -// Revision 1.17 1998/03/10 07:07:15 jim -// Fixed display glitch in HUD cycle -// -// Revision 1.16 1998/03/09 11:01:48 jim -// fixed string overflow for DEH, added graphic keys -// -// Revision 1.15 1998/03/09 07:10:09 killough -// Use displayplayer instead of consoleplayer -// -// Revision 1.14 1998/03/05 00:57:37 jim -// Scattered HUD -// -// Revision 1.13 1998/03/04 11:50:48 jim -// Change automap coord display -// -// Revision 1.12 1998/02/26 22:58:26 jim -// Added message review display to HUD -// -// Revision 1.11 1998/02/23 14:20:51 jim -// Merged HUD stuff, fixed p_plats.c to support elevators again -// -// Revision 1.10 1998/02/23 04:26:07 killough -// really allow new hud stuff to be turned off COMPLETELY -// -// Revision 1.9 1998/02/22 12:51:26 jim -// HUD control on F5, z coord, spacing change -// -// Revision 1.7 1998/02/20 18:46:51 jim -// cleanup of HUD control -// -// Revision 1.6 1998/02/19 16:54:53 jim -// Optimized HUD and made more configurable -// -// Revision 1.5 1998/02/18 11:55:55 jim -// Fixed issues with HUD and reduced screen size -// -// Revision 1.3 1998/02/15 02:47:47 phares -// User-defined keys -// -// Revision 1.2 1998/01/26 19:23:22 phares -// First rev with no ^Ms -// -// Revision 1.1.1.1 1998/01/19 14:02:55 rand -// Lee's Jan 19 sources -// -//---------------------------------------------------------------------------- diff --git a/src/hu_stuff.h b/src/hu_stuff.h deleted file mode 100644 index 4993285ff..000000000 --- a/src/hu_stuff.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (C) 1999 by -// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman -// Copyright (C) 2023 Fabian Greffrath -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// DESCRIPTION: Head up display -// -//----------------------------------------------------------------------------- - -#ifndef __HU_STUFF_H__ -#define __HU_STUFF_H__ - -#include "doomdef.h" -#include "doomtype.h" -#include "hu_command.h" - -struct event_s; -struct mobj_s; - -#define HU_BROADCAST 5 - -#define HU_MSGTIMEOUT (4*TICRATE) -#define HU_MSGTIMEOUT2 (5*TICRATE/2) // [crispy] 2.5 seconds - -// -// Heads up text -// -void HU_Init(void); -void HU_Start(void); -void HU_disable_all_widgets (void); -void HU_widget_rebuild_sttime(void); - -boolean HU_Responder(struct event_s *ev); - -void HU_Ticker(void); -void HU_Drawer(void); -char HU_dequeueChatChar(void); -void HU_Erase(void); - -boolean HU_DemoProgressBar(boolean force); - -void HU_ResetMessageColors(void); - -void WI_DrawWidgets(void); - -// killough 5/2/98: moved from m_misc.c: - -//jff 2/16/98 hud supported automap colors added -extern int hudcolor_titl; // color range of automap level title -extern int hudcolor_xyco; // color range of new coords on automap -//jff 2/23/98 hud is currently displayed -extern boolean hud_displayed; // hud is displayed -//jff 2/18/98 hud/status control -extern int hud_active; // hud mode 0=off, 1=small, 2=full -extern boolean hud_secret_message; // "A secret is revealed!" message -extern int hud_player_coords, hud_level_stats, hud_level_time; -extern boolean hud_widescreen_widgets; -extern boolean hud_time_use; -extern boolean show_messages; -extern boolean show_toggle_messages; -extern boolean show_pickup_messages; - -extern boolean chat_on; -extern boolean message_dontfuckwithme; - -extern int playback_tic, playback_totaltics; - -extern char **player_names[]; - -enum -{ - HUD_TYPE_CRISPY, - HUD_TYPE_BOOM_NO_BARS, - HUD_TYPE_BOOM, - - NUM_HUD_TYPES -}; - -extern int hud_type; -extern boolean draw_crispy_hud; - -enum -{ - HUD_WIDGET_OFF, - HUD_WIDGET_AUTOMAP, - HUD_WIDGET_HUD, - HUD_WIDGET_ALWAYS, - HUD_WIDGET_ADVANCED, -}; - -void HU_BindHUDVariables(void); - -byte* HU_ColorByHealth(int health, int maxhealth, boolean invul); - -extern int speedometer; - -#endif - -//---------------------------------------------------------------------------- -// -// $Log: hu_stuff.h,v $ -// Revision 1.6 1998/05/10 19:03:50 jim -// formatted/documented hu_stuff -// -// Revision 1.5 1998/05/03 22:25:03 killough -// add external declarations for hud options -// -// Revision 1.4 1998/02/18 00:59:04 jim -// Addition of HUD -// -// Revision 1.3 1998/02/15 02:48:12 phares -// User-defined keys -// -// Revision 1.2 1998/01/26 19:26:54 phares -// First rev with no ^Ms -// -// Revision 1.1.1.1 1998/01/19 14:02:56 rand -// Lee's Jan 19 sources -// -// -//---------------------------------------------------------------------------- diff --git a/src/m_cheat.c b/src/m_cheat.c index 66f95a78f..5a6da64d6 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -30,7 +30,6 @@ #include "doomdef.h" #include "doomstat.h" #include "g_game.h" -#include "hu_stuff.h" #include "info.h" #include "m_cheat.h" #include "m_fixed.h" @@ -49,6 +48,7 @@ #include "r_state.h" #include "s_sound.h" #include "sounds.h" +#include "st_widgets.h" #include "tables.h" #include "u_mapinfo.h" #include "w_wad.h" @@ -611,10 +611,10 @@ static void cheat_clev0() int epsd, map; char *cur, *next; - cur = M_StringDuplicate(MAPNAME(gameepisode, gamemap)); + cur = M_StringDuplicate(MapName(gameepisode, gamemap)); G_GotoNextLevel(&epsd, &map); - next = MAPNAME(epsd, map); + next = MapName(epsd, map); if (W_CheckNumForName(next) != -1) displaymsg("Current: %s, Next: %s", cur, next); @@ -657,7 +657,7 @@ static void cheat_clev(char *buf) epsd = 1; } - next = MAPNAME(epsd, map); + next = MapName(epsd, map); if (W_CheckNumForName(next) == -1) { diff --git a/src/m_config.c b/src/m_config.c index a37866e77..d847cb4cb 100644 --- a/src/m_config.c +++ b/src/m_config.c @@ -34,7 +34,6 @@ #include "doomstat.h" #include "doomtype.h" #include "g_game.h" -#include "hu_stuff.h" #include "i_flickstick.h" #include "i_gamepad.h" #include "i_gyro.h" @@ -54,6 +53,7 @@ #include "mn_internal.h" #include "r_main.h" #include "st_stuff.h" +#include "st_widgets.h" #include "w_wad.h" #include "ws_stuff.h" #include "z_zone.h" @@ -136,7 +136,7 @@ void M_InitConfig(void) G_BindWeapVariables(); WS_BindVariables(); - HU_BindHUDVariables(); + ST_BindHUDVariables(); ST_BindSTSVariables(); AM_BindAutomapVariables(); diff --git a/src/m_json.c b/src/m_json.c index 893765af2..4850a03ce 100644 --- a/src/m_json.c +++ b/src/m_json.c @@ -15,50 +15,79 @@ #include #include +#include "doomtype.h" #include "i_printf.h" +#include "m_misc.h" +#include "w_wad.h" +#include "z_zone.h" #include "cjson/cJSON.h" -json_t *JS_Open(const char *type, version_t version, const char *data) +boolean JS_GetVersion(json_t *json, version_t *version) { - const char *s; + json_t *js_version = JS_GetObject(json, "version"); + if (!JS_IsString(js_version)) + { + return false; + } - json_t *json = cJSON_Parse(data); + const char *string = JS_GetString(js_version); + if (sscanf(string, "%d.%d.%d", &version->major, &version->minor, + &version->revision) == 3) + { + return true; + } + + return false; +} + +json_t *JS_Open(const char *lump, const char *type, version_t maxversion) +{ + int lumpnum = W_CheckNumForName(lump); + if (lumpnum < 0) + { + return NULL; + } + + json_t *json = cJSON_Parse(W_CacheLumpNum(lumpnum, PU_CACHE)); if (json == NULL) { - I_Printf(VB_ERROR, "%s: error before %s", type, cJSON_GetErrorPtr()); + const char *error_ptr = cJSON_GetErrorPtr(); + if (error_ptr) + { + I_Printf(VB_ERROR, "%s: parsing error before %s", lump, error_ptr); + } return NULL; } json_t *js_type = JS_GetObject(json, "type"); if (!JS_IsString(js_type)) { - I_Printf(VB_ERROR, "%s: no type string", type); + I_Printf(VB_ERROR, "%s: no type string", lump); return NULL; } - s = JS_GetString(js_type); + const char *s = JS_GetString(js_type); if (strcmp(s, type)) { - I_Printf(VB_ERROR, "%s: wrong type %s", type, s); + I_Printf(VB_ERROR, "%s: wrong type %s", lump, s); return NULL; } - json_t *js_version = JS_GetObject(json, "version"); - if (!JS_IsString(js_version)) + version_t v = {0}; + if (!JS_GetVersion(json, &v)) { - I_Printf(VB_ERROR, "%s: no version string", type); + I_Printf(VB_ERROR, "%s: no version string", lump); return NULL; } - s = JS_GetString(js_version); - version_t v = {0}; - sscanf(s, "%d.%d.%d", &v.major, &v.minor, &v.revision); - if (!(v.major == version.major && v.minor == version.minor - && v.revision == version.revision)) + if ((maxversion.major < v.major + || (maxversion.major <= v.major && maxversion.minor < v.minor) + || (maxversion.major <= v.major && maxversion.minor <= v.minor + && maxversion.revision < v.revision))) { - I_Printf(VB_ERROR, "%s: unsupported version %d.%d.%d", type, v.major, - v.minor, v.revision); + I_Printf(VB_ERROR, "%s: max supported version %d.%d.%d", lump, + maxversion.major, maxversion.minor, maxversion.revision); return NULL; } @@ -70,11 +99,21 @@ void JS_Close(json_t *json) cJSON_Delete(json); } +boolean JS_IsObject(json_t *json) +{ + return cJSON_IsObject(json); +} + boolean JS_IsNull(json_t *json) { return cJSON_IsNull(json); } +boolean JS_IsBoolean(json_t *json) +{ + return cJSON_IsBool(json); +} + boolean JS_IsNumber(json_t *json) { return cJSON_IsNumber(json); @@ -105,11 +144,26 @@ json_t *JS_GetArrayItem(json_t *json, int index) return cJSON_GetArrayItem(json, index); } +boolean JS_GetBoolean(json_t *json) +{ + return !!json->valueint; +} + double JS_GetNumber(json_t *json) { return json->valuedouble; } +double JS_GetNumberValue(json_t *json, const char *string) +{ + json_t *obj = JS_GetObject(json, string); + if (JS_IsNumber(obj)) + { + return obj->valuedouble; + } + return 0; +} + int JS_GetInteger(json_t *json) { return json->valueint; @@ -119,3 +173,23 @@ const char *JS_GetString(json_t *json) { return json->valuestring; } + +const char *JS_GetStringRef(json_t *json, const char *string) +{ + json_t *obj = JS_GetObject(json, string); + if (JS_IsString(obj)) + { + return obj->valuestring; + } + return NULL; +} + +const char *JS_GetStringCopy(json_t *json, const char *string) +{ + json_t *obj = JS_GetObject(json, string); + if (JS_IsString(obj)) + { + return M_StringDuplicate(obj->valuestring); + } + return NULL; +} diff --git a/src/m_json.h b/src/m_json.h index e595f0c73..446182fd7 100644 --- a/src/m_json.h +++ b/src/m_json.h @@ -25,19 +25,27 @@ typedef struct int revision; } version_t; -json_t *JS_Open(const char *type, version_t version, const char *data); +boolean JS_GetVersion(json_t *json, version_t *version); + +json_t *JS_Open(const char *lump, const char *type, version_t maxversion); void JS_Close(json_t *json); json_t *JS_GetObject(json_t *json, const char *string); +boolean JS_IsObject(json_t *json); boolean JS_IsNull(json_t *json); +boolean JS_IsBoolean(json_t *json); boolean JS_IsNumber(json_t *json); boolean JS_IsString(json_t *json); boolean JS_IsArray(json_t *json); +boolean JS_GetBoolean(json_t *json); double JS_GetNumber(json_t *json); +double JS_GetNumberValue(json_t *json, const char *string); int JS_GetInteger(json_t *json); const char *JS_GetString(json_t *json); +const char *JS_GetStringRef(json_t *json, const char *string); +const char *JS_GetStringCopy(json_t *json, const char *string); int JS_GetArraySize(json_t *json); json_t *JS_GetArrayItem(json_t *json, int index); diff --git a/src/mn_internal.h b/src/mn_internal.h index 443be71af..fa411d32a 100644 --- a/src/mn_internal.h +++ b/src/mn_internal.h @@ -60,7 +60,6 @@ void MN_InitDefaults(void); extern const char *gamma_strings[]; void MN_ResetGamma(void); void MN_DrawDelVerify(void); -void MN_SizeDisplay(int choice); boolean MN_SetupCursorPostion(int x, int y); boolean MN_SetupMouseResponder(int x, int y); diff --git a/src/mn_menu.c b/src/mn_menu.c index 0d6358cc5..9fec50cb9 100644 --- a/src/mn_menu.c +++ b/src/mn_menu.c @@ -36,8 +36,6 @@ #include "doomtype.h" #include "dstrings.h" #include "g_game.h" -#include "hu_lib.h" -#include "hu_stuff.h" #include "i_input.h" #include "i_printf.h" #include "i_system.h" @@ -57,6 +55,9 @@ #include "r_main.h" #include "s_sound.h" #include "sounds.h" +#include "st_sbardef.h" +#include "st_stuff.h" +#include "st_widgets.h" #include "u_mapinfo.h" #include "v_fmt.h" #include "v_video.h" @@ -76,10 +77,6 @@ // int detailLevel; obsolete -- killough int screenblocks; // has default -int saved_screenblocks; - -static int screenSize; // temp for screenblocks (0-9) - static int quickSaveSlot; // -1 = no quicksave slot picked! static int messageToPrint; // 1 = message to be printed @@ -102,8 +99,6 @@ static int saveCharIndex; // which char we're editing // old save description before edit static char saveOldString[SAVESTRINGSIZE]; -boolean inhelpscreens; // indicates we are in or just left a help screen - boolean menuactive; // The menus are up static boolean options_active; @@ -314,9 +309,6 @@ static menu_t MainDef = { static void M_DrawMainMenu(void) { - // [crispy] force status bar refresh - inhelpscreens = true; - options_active = false; V_DrawPatch(94, 2, V_CachePatchName("M_DOOM", PU_CACHE)); @@ -422,8 +414,6 @@ static void M_FinishHelp(int choice) // killough 10/98 static void M_DrawReadThis1(void) { - inhelpscreens = true; - V_DrawPatchFullScreen(V_CachePatchName("HELP2", PU_CACHE)); } @@ -434,8 +424,6 @@ static void M_DrawReadThis1(void) static void M_DrawReadThis2(void) { - inhelpscreens = true; - // We only ever draw the second page if this is // gameversion == exe_doom_1_9 and gamemode == registered @@ -444,8 +432,6 @@ static void M_DrawReadThis2(void) static void M_DrawReadThisCommercial(void) { - inhelpscreens = true; - V_DrawPatchFullScreen(V_CachePatchName("HELP", PU_CACHE)); } @@ -563,9 +549,6 @@ void M_AddEpisode(const char *map, const char *gfx, const char *txt, static void M_DrawEpisode(void) { - // [crispy] force status bar refresh - inhelpscreens = true; - MN_DrawTitle(54, EpiDef.y - 25, "M_EPISOD", "Which Episode?"); } @@ -637,9 +620,6 @@ static menu_t NewDef = { static void M_DrawNewGame(void) { - // [crispy] force status bar refresh - inhelpscreens = true; - MN_DrawTitle(96, 14, "M_NEWG", "NEW GAME"); MN_DrawTitle(54, 38, "M_SKILL", "Choose Skill Level:"); } @@ -831,9 +811,6 @@ static void M_DrawSaveLoadBottomLine(void) char pagestr[16]; const int y = LoadDef.y + LINEHEIGHT * load_page; - // [crispy] force status bar refresh - inhelpscreens = true; - int index = (menu_input == mouse_mode ? highlight_item : itemOn); int flags = currentMenu->menuitems[index].flags; @@ -1135,7 +1112,7 @@ void MN_SetQuickSaveSlot(int slot) // [FG] generate a default save slot name when the user saves to an empty slot static void SetDefaultSaveName(int slot) { - char *maplump = MAPNAME(gameepisode, gamemap); + char *maplump = MapName(gameepisode, gamemap); int maplumpnum = W_CheckNumForName(maplump); if (gamemapinfo && U_CheckField(gamemapinfo->label)) @@ -1571,8 +1548,6 @@ static void M_ChangeMessages(int choice) { displaymsg("%s", s_MSGON); // Ty 03/27/98 - externalized } - - message_dontfuckwithme = true; } ///////////////////////////// @@ -1584,33 +1559,21 @@ static void M_ChangeMessages(int choice) // hud_displayed is toggled by + or = in fullscreen // hud_displayed is cleared by - -void MN_SizeDisplay(int choice) +static void M_SizeDisplay(int choice) { switch (choice) { case 0: - if (screenSize > 0) - { - screenblocks--; - screenSize--; - hud_displayed = 0; - } + screenblocks--; break; case 1: - if (screenSize < 8) - { - screenblocks++; - screenSize++; - } - else - { - hud_displayed = !hud_displayed; - HU_disable_all_widgets(); - } + screenblocks++; + break; + default: break; } + screenblocks = BETWEEN(3, 12, screenblocks); R_SetViewSize(screenblocks /*, detailLevel obsolete -- killough */); - saved_screenblocks = screenblocks; } ///////////////////////////////////////////////////////////////////////////// @@ -1709,8 +1672,6 @@ static void M_ExtHelp(int choice) static void M_DrawExtHelp(void) { char namebfr[] = "HELPnn"; // [FG] char array! - - inhelpscreens = true; // killough 5/1/98 namebfr[4] = extended_help_index / 10 + 0x30; namebfr[5] = extended_help_index % 10 + 0x30; V_DrawPatchFullScreen(V_CachePatchName(namebfr, PU_CACHE)); @@ -1734,7 +1695,6 @@ static void M_DrawHelp(void) helplump = W_CheckNumForName("HELP1"); } - inhelpscreens = true; // killough 10/98 V_DrawPatchFullScreen(V_CachePatchNum(helplump, PU_CACHE)); } @@ -1959,9 +1919,6 @@ static void M_Setup(int choice) void MN_ClearMenus(void) { - // force status bar refresh - inhelpscreens = true; - menuactive = 0; options_active = false; print_warning_about_changes = 0; // killough 8/15/98 @@ -2018,8 +1975,6 @@ void M_Init(void) highlight_item = 0; whichSkull = 0; skullAnimCounter = 10; - saved_screenblocks = screenblocks; - screenSize = screenblocks - 3; messageToPrint = 0; messageString = NULL; messageLastMenuActive = menuactive; @@ -2298,7 +2253,7 @@ boolean M_ShortcutResponder(const event_t *ev) { return false; } - MN_SizeDisplay(0); + M_SizeDisplay(0); M_StartSound(sfx_stnmov); return true; } @@ -2309,7 +2264,7 @@ boolean M_ShortcutResponder(const event_t *ev) { // key_hud==key_zoomin return false; } - MN_SizeDisplay(1); + M_SizeDisplay(1); M_StartSound(sfx_stnmov); return true; } @@ -2321,19 +2276,20 @@ boolean M_ShortcutResponder(const event_t *ev) return false; // HUD mode control } - if (screenSize < 8) // function on default F5 + if (screenblocks < 10) { - while (screenSize < 8 || !hud_displayed) // make hud visible - { - MN_SizeDisplay(1); // when configuring it - } + screenblocks = 10; } else { - hud_displayed = 1; // jff 3/3/98 turn hud on - hud_active = (hud_active + 1) % 3; // cycle hud_active - HU_disable_all_widgets(); + ++screenblocks; + if (screenblocks > 12) + { + screenblocks = 10; + } } + + R_SetViewSize(screenblocks); return true; } @@ -3177,7 +3133,6 @@ void M_Drawer(void) if (MN_MenuIsShaded()) { - inhelpscreens = true; V_ShadeScreen(); } diff --git a/src/mn_menu.h b/src/mn_menu.h index b425088ef..9adf8889a 100644 --- a/src/mn_menu.h +++ b/src/mn_menu.h @@ -93,8 +93,6 @@ void MN_InitMenuStrings(void); boolean MN_StartsWithMapIdentifier(char *str); -extern boolean inhelpscreens; - int MN_GetPixelWidth(const char *ch); void MN_DrawString(int cx, int cy, int color, const char *ch); diff --git a/src/mn_setup.c b/src/mn_setup.c index 7f3f9474b..3b7c7a815 100644 --- a/src/mn_setup.c +++ b/src/mn_setup.c @@ -13,6 +13,7 @@ // GNU General Public License for more details. // +#include "hu_command.h" #include "mn_internal.h" #include "am_map.h" @@ -23,8 +24,6 @@ #include "doomtype.h" #include "g_game.h" #include "hu_crosshair.h" -#include "hu_lib.h" -#include "hu_stuff.h" #include "i_gamepad.h" #include "i_gyro.h" #include "i_input.h" @@ -53,7 +52,10 @@ #include "r_sky.h" // [FG] R_InitSkyMap() #include "r_voxel.h" #include "s_sound.h" +#include "st_sbardef.h" +#include "st_stuff.h" #include "sounds.h" +#include "st_widgets.h" #include "v_fmt.h" #include "v_video.h" #include "w_wad.h" @@ -316,8 +318,7 @@ enum str_curve, str_center_weapon, str_screensize, - str_hudtype, - str_hudmode, + str_stlayout, str_show_widgets, str_show_adv_widgets, str_crosshair, @@ -1507,8 +1508,6 @@ void MN_KeyBindings(int choice) void MN_DrawKeybnd(void) { - inhelpscreens = true; // killough 4/6/98: Force status bar redraw - // Set up the Key Binding screen DrawBackground("FLOOR4_6"); // Draw background @@ -1768,8 +1767,6 @@ void MN_Weapons(int choice) void MN_DrawWeapons(void) { - inhelpscreens = true; // killough 4/6/98: Force status bar redraw - DrawBackground("FLOOR4_6"); // Draw background MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_WEAP", "Weapons"); DrawTabs(); @@ -1799,43 +1796,23 @@ static setup_tab_t stat_tabs[] = { static void SizeDisplayAlt(void) { - int choice = -1; - - if (screenblocks > saved_screenblocks) - { - choice = 1; - } - else if (screenblocks < saved_screenblocks) - { - choice = 0; - } - - screenblocks = saved_screenblocks; - - if (choice != -1) - { - MN_SizeDisplay(choice); - } + R_SetViewSize(screenblocks); +} - hud_displayed = (screenblocks == 11); +static void RefreshSolidBackground(void) +{ + st_refresh_background = true; } static const char *screensize_strings[] = { - "", "", "", "Status Bar", - "Status Bar", "Status Bar", "Status Bar", "Status Bar", - "Status Bar", "Status Bar", "Status Bar", "Fullscreen" + "", "", "", "Status Bar", "Status Bar", + "Status Bar", "Status Bar", "Status Bar", "Status Bar", "Status Bar", + "Status Bar", "Fullscreen", "Fullscreen" }; -static const char *hudtype_strings[] = {"Crispy", "Boom No Bars", "Boom"}; - -static const char **GetHUDModeStrings(void) -{ - static const char *crispy_strings[] = {"Off", "Original", "Widescreen"}; - static const char *boom_strings[] = {"Minimal", "Compact", "Distributed"}; - return hud_type ? boom_strings : crispy_strings; -} - -static void UpdateHUDModeStrings(void); +static const char *st_layout_strings[] = { + "Original", "Wide" +}; #define H_X_THRM8 (M_X_THRM8 - 14) #define H_X (M_X - 14) @@ -1847,27 +1824,19 @@ static setup_menu_t stat_settings1[] = { MI_GAP, - {"Status Bar", S_SKIP | S_TITLE, H_X, M_SPC}, - - {"Colored Numbers", S_ONOFF | S_COSMETIC, H_X, M_SPC, {"sts_colored_numbers"}}, - - {"Gray Percent Sign", S_ONOFF | S_COSMETIC, H_X, M_SPC, {"sts_pct_always_gray"}}, - - {"Solid Background Color", S_ONOFF, H_X, M_SPC, {"st_solidbackground"}}, + {"Layout", S_CHOICE, H_X, M_SPC, {"st_layout"}, + .strings_id = str_stlayout}, MI_GAP, - {"Fullscreen HUD", S_SKIP | S_TITLE, H_X, M_SPC}, - - {"HUD Type", S_CHOICE, H_X, M_SPC, {"hud_type"}, - .strings_id = str_hudtype, .action = UpdateHUDModeStrings}, + {"Status Bar", S_SKIP | S_TITLE, H_X, M_SPC}, - {"HUD Mode", S_CHOICE, H_X, M_SPC, {"hud_active"}, - .strings_id = str_hudmode}, + {"Colored Numbers", S_ONOFF | S_COSMETIC, H_X, M_SPC, {"sts_colored_numbers"}}, - MI_GAP, + {"Gray Percent Sign", S_ONOFF | S_COSMETIC, H_X, M_SPC, {"sts_pct_always_gray"}}, - {"Backpack Shifts Ammo Color", S_ONOFF, H_X, M_SPC, {"hud_backpack_thresholds"}}, + {"Solid Background Color", S_ONOFF, H_X, M_SPC, {"st_solidbackground"}, + .action = RefreshSolidBackground}, {"Armor Color Matches Type", S_ONOFF, H_X, M_SPC, {"hud_armor_type"}}, @@ -1895,27 +1864,13 @@ static setup_menu_t stat_settings2[] = { .strings_id = str_show_widgets}, {"Show Player Coords", S_CHOICE | S_STRICT, H_X, M_SPC, - {"hud_player_coords"}, .strings_id = str_show_adv_widgets, - .action = HU_Start}, + {"hud_player_coords"}, .strings_id = str_show_adv_widgets}, {"Show Command History", S_ONOFF | S_STRICT, H_X, M_SPC, {"hud_command_history"}, .action = HU_ResetCommandHistory}, {"Use-Button Timer", S_ONOFF, H_X, M_SPC, {"hud_time_use"}}, - MI_GAP, - - {"Widget Appearance", S_SKIP | S_TITLE, H_X, M_SPC}, - - {"Use Doom Font", S_CHOICE, H_X, M_SPC, {"hud_widget_font"}, - .strings_id = str_show_widgets}, - - {"Widescreen Alignment", S_ONOFF, H_X, M_SPC, {"hud_widescreen_widgets"}, - .action = HU_Start}, - - {"Vertical Layout", S_ONOFF, H_X, M_SPC, {"hud_widget_layout"}, - .action = HU_Start}, - MI_END }; @@ -1957,9 +1912,8 @@ static setup_menu_t stat_settings4[] = { {"Show Toggle Messages", S_ONOFF, H_X, M_SPC, {"show_toggle_messages"}}, {"Show Pickup Messages", S_ONOFF, H_X, M_SPC, {"show_pickup_messages"}}, {"Show Obituaries", S_ONOFF, H_X, M_SPC, {"show_obituary_messages"}}, - {"Center Messages", S_ONOFF, H_X, M_SPC, {"message_centered"}}, {"Colorize Messages", S_ONOFF, H_X, M_SPC, {"message_colorized"}, - .action = HU_ResetMessageColors}, + .action = ST_ResetMessageColors}, MI_END }; @@ -1975,6 +1929,8 @@ static void UpdateCrosshairItems(void) DisableItem( !(hud_crosshair && hud_crosshair_target == crosstarget_highlight), stat_settings3, "hud_crosshair_target_color"); + + HU_StartCrosshair(); } // Setting up for the Status Bar / HUD screen. Turn on flags, set pointers, @@ -1996,8 +1952,6 @@ void MN_StatusBar(int choice) void MN_DrawStatusHUD(void) { - inhelpscreens = true; // killough 4/6/98: Force status bar redraw - DrawBackground("FLOOR4_6"); // Draw background MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_STAT", "Status Bar/HUD"); DrawTabs(); @@ -2087,8 +2041,6 @@ void MN_Automap(int choice) void MN_DrawAutoMap(void) { - inhelpscreens = true; // killough 4/6/98: Force status bar redraw - DrawBackground("FLOOR4_6"); // Draw background MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_AUTO", "Automap"); DrawInstructions(); @@ -2167,8 +2119,6 @@ void MN_Enemy(int choice) void MN_DrawEnemy(void) { - inhelpscreens = true; - DrawBackground("FLOOR4_6"); // Draw background MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_ENEM", "Enemies"); DrawInstructions(); @@ -2268,8 +2218,6 @@ void MN_Compat(int choice) void MN_DrawCompat(void) { - inhelpscreens = true; - DrawBackground("FLOOR4_6"); // Draw background MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_COMPAT", "Compatibility"); DrawInstructions(); @@ -2660,10 +2608,9 @@ static void MN_Midi(void) current_tabs = midi_tabs; SetupMenuSecondary(); } + void MN_DrawMidi(void) { - inhelpscreens = true; - DrawBackground("FLOOR4_6"); MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_GENERL", "General"); DrawTabs(); @@ -2751,8 +2698,6 @@ static void MN_Equalizer(void) void MN_DrawEqualizer(void) { - inhelpscreens = true; - DrawBackground("FLOOR4_6"); MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_GENERL", "General"); DrawTabs(); @@ -2982,8 +2927,6 @@ static void MN_PadAdv(void) void MN_DrawPadAdv(void) { - inhelpscreens = true; - DrawBackground("FLOOR4_6"); MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_GENERL", "General"); DrawTabs(); @@ -3173,8 +3116,6 @@ static void MN_Gyro(void) void MN_DrawGyro(void) { - inhelpscreens = true; - DrawBackground("FLOOR4_6"); MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_GENERL", "General"); DrawTabs(); @@ -3371,8 +3312,6 @@ void MN_General(int choice) void MN_DrawGeneral(void) { - inhelpscreens = true; - DrawBackground("FLOOR4_6"); // Draw background MN_DrawTitle(M_X_CENTER, M_Y_TITLE, "M_GENERL", "General"); DrawTabs(); @@ -3665,21 +3604,18 @@ void MN_DrawStringCR(int cx, int cy, byte *cr1, byte *cr2, const char *ch) { c = *ch++; // get next char - if (c == '\x1b') + if (c == '\x1b' && *ch) { - if (ch) + c = *ch++; + if (c >= '0' && c <= '0' + CR_NONE) { - c = *ch++; - if (c >= '0' && c <= '0' + CR_NONE) - { - cr = colrngs[c - '0']; - } - else if (c == '0' + CR_ORIG) - { - cr = cr1; - } - continue; + cr = colrngs[c - '0']; + } + else if (c == '0' + CR_ORIG) + { + cr = cr1; } + continue; } c = M_ToUpper(c) - HU_FONTSTART; @@ -4459,7 +4395,6 @@ boolean MN_SetupResponder(menu_action_t action, int ch) set_weapon_active = false; default_verify = false; // phares 4/19/98 print_warning_about_changes = false; // [FG] reset - HU_Start(); // catch any message changes // phares 4/19/98 M_StartSound(sfx_swtchx); return true; } @@ -4769,8 +4704,7 @@ static const char **selectstrings[] = { curve_strings, center_weapon_strings, screensize_strings, - hudtype_strings, - NULL, // str_hudmode + st_layout_strings, show_widgets_strings, show_adv_widgets_strings, crosshair_strings, @@ -4815,11 +4749,6 @@ static const char **GetStrings(int id) return NULL; } -static void UpdateHUDModeStrings(void) -{ - selectstrings[str_hudmode] = GetHUDModeStrings(); -} - static void UpdateWeaponSlotStrings(void) { selectstrings[str_weapon_slots] = GetWeaponSlotStrings(); @@ -4832,7 +4761,6 @@ static const char **GetMidiPlayerStrings(void) void MN_InitMenuStrings(void) { - UpdateHUDModeStrings(); UpdateWeaponSlotLabels(); UpdateWeaponSlotStrings(); selectstrings[str_resolution_scale] = GetResolutionScaleStrings(); diff --git a/src/p_mobj.c b/src/p_mobj.c index 345295d9f..b3b7b6514 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -25,7 +25,6 @@ #include "doomstat.h" #include "dsdhacked.h" #include "g_game.h" -#include "hu_stuff.h" #include "i_printf.h" #include "info.h" #include "m_random.h" @@ -1143,7 +1142,6 @@ void P_SpawnPlayer (mapthing_t* mthing) if (mthing->type-1 == consoleplayer) { ST_Start(); // wake up the status bar - HU_Start(); // wake up the heads up text } } diff --git a/src/p_setup.c b/src/p_setup.c index 32210116b..1ad3873db 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1604,7 +1604,7 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill) // W_Reload (); killough 1/31/98: W_Reload obsolete // find map name - strcpy(lumpname, MAPNAME(episode, map)); + strcpy(lumpname, MapName(episode, map)); lumpnum = W_GetNumForName(lumpname); diff --git a/src/p_spec.c b/src/p_spec.c index 70f6317ec..4254b1ac4 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -35,7 +35,6 @@ #include "doomstat.h" #include "g_game.h" #include "hu_obituary.h" -#include "hu_stuff.h" #include "i_system.h" #include "info.h" #include "m_argv.h" @@ -61,6 +60,7 @@ #include "s_sound.h" #include "sounds.h" #include "st_stuff.h" +#include "st_widgets.h" #include "tables.h" #include "w_wad.h" #include "z_zone.h" diff --git a/src/p_user.c b/src/p_user.c index b841e821b..d26612384 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -28,7 +28,6 @@ #include "doomstat.h" #include "doomtype.h" #include "g_game.h" -#include "hu_stuff.h" #include "info.h" #include "m_cheat.h" #include "p_map.h" @@ -39,6 +38,7 @@ #include "r_defs.h" #include "r_main.h" #include "st_stuff.h" +#include "st_widgets.h" static fixed_t PlayerSlope(player_t *player) { @@ -584,6 +584,58 @@ void P_PlayerThink (player_t* player) player->powers[pw_infrared] > 4*32 || player->powers[pw_infrared] & 8; } +boolean P_EvaluateItemOwned(itemtype_t item, player_t *player) +{ + switch (item) + { + case item_bluecard: + case item_yellowcard: + case item_redcard: + case item_blueskull: + case item_yellowskull: + case item_redskull: + return player->cards[item - item_bluecard] != 0; + + case item_backpack: + return player->backpack; + + case item_greenarmor: + case item_bluearmor: + return player->armortype == (item - item_greenarmor + 1); + + case item_areamap: + return player->powers[pw_allmap] != 0; + + case item_lightamp: + return player->powers[pw_infrared] != 0; + + case item_berserk: + return player->powers[pw_strength] != 0; + + case item_invisibility: + return player->powers[pw_invisibility] != 0; + + case item_radsuit: + return player->powers[pw_ironfeet] != 0; + + case item_invulnerability: + return player->powers[pw_invulnerability] != 0; + + case item_healthbonus: + case item_stimpack: + case item_medikit: + case item_soulsphere: + case item_megasphere: + case item_armorbonus: + case item_noitem: + case item_messageonly: + default: + break; + } + + return false; +} + //---------------------------------------------------------------------------- // // $Log: p_user.c,v $ diff --git a/src/p_user.h b/src/p_user.h index ade8cdc27..ff75372d7 100644 --- a/src/p_user.h +++ b/src/p_user.h @@ -22,6 +22,7 @@ #ifndef __P_USER__ #define __P_USER__ +#include "doomdef.h" #include "m_fixed.h" #include "tables.h" @@ -43,6 +44,8 @@ typedef enum extern death_use_action_t death_use_action; extern boolean activate_death_use_reload; +boolean P_EvaluateItemOwned(itemtype_t item, struct player_s *player); + extern boolean onground; // whether player is on ground or in air #endif // __P_USER__ diff --git a/src/params.h b/src/params.h index 4831e2851..004c49c84 100644 --- a/src/params.h +++ b/src/params.h @@ -58,6 +58,7 @@ static const char *params[] = { static const char *params_with_args[] = { "-config", +"-dumptranmap", "-file", "-iwad", "-save", diff --git a/src/r_data.c b/src/r_data.c index f8dd72821..432baa573 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1044,6 +1044,25 @@ void R_InitTranMap(int progress) Z_ChangeTag(playpal, PU_CACHE); free(fname); } + + //! + // @category mod + // @arg + // + // Dump tranmap lump. + // + + int p = M_CheckParmWithArgs("-dumptranmap", 1); + if (p > 0) + { + char *path = malloc(strlen(myargv[p + 1]) + 5); + strcpy(path, myargv[p + 1]); + AddDefaultExtension(path, ".lmp"); + + M_WriteFile(path, main_tranmap, 256 * 256); + + free(path); + } } // diff --git a/src/r_main.c b/src/r_main.c index 1107f23ff..8b664c853 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -549,7 +549,7 @@ int setblocks; void R_SetViewSize(int blocks) { setsizeneeded = true; - setblocks = blocks; + setblocks = MIN(blocks, 11); } // @@ -673,8 +673,7 @@ void R_ExecuteSetViewSize (void) } } - // [crispy] forcefully initialize the status bar backing screen - ST_refreshBackground(); + st_refresh_background = true; pspr_interp = false; } @@ -1032,7 +1031,7 @@ void R_BindRenderVariables(void) BIND_NUM_GENERAL(invul_mode, INVUL_MBF, INVUL_VANILLA, INVUL_GRAY, "Invulnerability effect (0 = Vanilla; 1 = MBF; 2 = Gray)"); BIND_BOOL(flashing_hom, true, "Enable flashing of the HOM indicator"); - BIND_NUM(screenblocks, 10, 3, 11, "Size of game-world screen"); + BIND_NUM(screenblocks, 10, 3, 12, "Size of game-world screen"); M_BindBool("translucency", &translucency, NULL, true, ss_gen, wad_yes, "Translucency for some things"); diff --git a/src/r_skydefs.c b/src/r_skydefs.c index f7e87c131..cd0bc0ac1 100644 --- a/src/r_skydefs.c +++ b/src/r_skydefs.c @@ -20,7 +20,6 @@ #include "m_fixed.h" #include "m_json.h" #include "m_misc.h" -#include "w_wad.h" static boolean ParseFire(json_t *json, fire_t *out) { @@ -130,23 +129,16 @@ static boolean ParseFlatMap(json_t *json, flatmap_t *out) skydefs_t *R_ParseSkyDefs(void) { - int lumpnum = W_CheckNumForName("SKYDEFS"); - if (lumpnum < 0) - { - return NULL; - } - - json_t *json = JS_Open("skydefs", (version_t){1, 0, 0}, - W_CacheLumpNum(lumpnum, PU_CACHE)); + json_t *json = JS_Open("SKYDEFS", "skydefs", (version_t){1, 0, 0}); if (json == NULL) { - JS_Close(json); return NULL; } json_t *data = JS_GetObject(json, "data"); - if (JS_IsNull(data)) + if (JS_IsNull(data) || !JS_IsObject(data)) { + I_Printf(VB_ERROR, "SBARDEF: no data"); JS_Close(json); return NULL; } diff --git a/src/st_lib.c b/src/st_lib.c deleted file mode 100644 index f76f73854..000000000 --- a/src/st_lib.c +++ /dev/null @@ -1,295 +0,0 @@ -// -// Copyright (C) 1999 by -// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// DESCRIPTION: -// The status bar widget code. -// -//----------------------------------------------------------------------------- - -#include "st_lib.h" - -#include "m_swap.h" -#include "r_defs.h" -#include "v_video.h" -#include "v_fmt.h" -#include "w_wad.h" -#include "z_zone.h" - -boolean sts_colored_numbers; //jff 2/18/98 control to disable status color changes -boolean sts_pct_always_gray; // killough 2/21/98: always gray %'s? bug or feature? - -patch_t* sttminus; - -// -// STlib_init() -// -// Hack display negative frags. Loads and store the stminus lump. -// -// Passed nothing, returns nothing -// -void STlib_init(void) -{ - // [FG] allow playing with the Doom v1.2 IWAD which is missing the STTMINUS lump - if (W_CheckNumForName("STTMINUS") >= 0) - sttminus = V_CachePatchName("STTMINUS", PU_STATIC); - else - sttminus = NULL; -} - -// -// STlib_initNum() -// -// Initializes an st_number_t widget -// -// Passed the widget, its position, the patches for the digits, a pointer -// to the value displayed, a pointer to the on/off control, and the width -// Returns nothing -// -void STlib_initNum -( st_number_t* n, - int x, - int y, - patch_t** pl, - int* num, - boolean* on, - int width ) -{ - n->x = x; - n->y = y; - n->oldnum = 0; - n->width = width; - n->num = num; - n->on = on; - n->p = pl; -} - -// -// STlib_drawNum() -// -// A fairly efficient way to draw a number based on differences from the -// old number. -// -// Passed a st_number_t widget and a color range for output. -// Returns nothing -// -static void STlib_drawNum -( st_number_t* n, - byte *outrng ) //jff 2/16/98 add color translation to digit output -{ - int numdigits = n->width; - int num = *n->num; - - int w = SHORT(n->p[0]->width); - int x = n->x; - - int neg; - - n->oldnum = *n->num; - - neg = num < 0; - - if (neg) - { - if (numdigits == 2 && num < -9) - num = -9; - else if (numdigits == 3 && num < -99) - num = -99; - - num = -num; - } - - // if non-number, do not draw it - if (num == LARGENUMBER) - return; - - //jff 2/16/98 add color translation to digit output - // in the special case of 0, you draw 0 - if (!num) - { - if (outrng && sts_colored_numbers) - V_DrawPatchTranslated(x - w, n->y, n->p[ 0 ],outrng); - else //jff 2/18/98 allow use of faster draw routine from config - V_DrawPatch(x - w, n->y, n->p[ 0 ]); - } - - // draw the new number - //jff 2/16/98 add color translation to digit output - while (num && numdigits--) - { - x -= w; - if (outrng && sts_colored_numbers) - V_DrawPatchTranslated(x, n->y, n->p[ num % 10 ],outrng); - else //jff 2/18/98 allow use of faster draw routine from config - V_DrawPatch(x, n->y, n->p[ num % 10 ]); - num /= 10; - } - - // draw a minus sign if necessary - //jff 2/16/98 add color translation to digit output - if (neg && sttminus) - { - w = SHORT(sttminus->width); - if (outrng && sts_colored_numbers) - V_DrawPatchTranslated(x - w, n->y, sttminus,outrng); - else //jff 2/18/98 allow use of faster draw routine from config - V_DrawPatch(x - w, n->y, sttminus); - } -} - -// -// STlib_updateNum() -// -// Draws a number conditionally based on the widget's enable -// -// Passed a number widget and the output color range -// Returns nothing -// -void STlib_updateNum -( st_number_t* n, - byte *outrng ) //jff 2/16/98 add color translation to digit output -{ - if (*n->on) STlib_drawNum(n, outrng); -} - -// -// STlib_initPercent() -// -// Initialize a st_percent_t number with percent sign widget -// -// Passed a st_percent_t widget, the position, the digit patches, a pointer -// to the number to display, a pointer to the enable flag, and patch -// for the percent sign. -// Returns nothing. -// -void STlib_initPercent -( st_percent_t* p, - int x, - int y, - patch_t** pl, - int* num, - boolean* on, - patch_t* percent ) -{ - STlib_initNum(&p->n, x, y, pl, num, on, 3); - p->p = percent; -} - -// -// STlib_updatePercent() -// -// Draws a number/percent conditionally based on the widget's enable -// -// Passed a precent widget and the output color range -// Returns nothing -// -void STlib_updatePercent -( st_percent_t* per, - byte *outrng ) //jff 2/16/98 add color translation to digit output -{ - // Remove the check for 'refresh' because this causes percent symbols to always appear - // in automap overlay mode. - if (*per->n.on) // killough 2/21/98: fix percents not updated; - { - V_DrawPatchTranslated - ( - per->n.x, - per->n.y, - per->p, - // [FG] fix always gray percent / always red mismatch - sts_pct_always_gray ? cr_gray : - !sts_colored_numbers ? NULL : - outrng - ); - } - - STlib_updateNum(&per->n, outrng); -} - -// -// STlib_initMultIcon() -// -// Initialize a st_multicon_t widget, used for a multigraphic display -// like the status bar's keys. -// -// Passed a st_multicon_t widget, the position, the graphic patches, a pointer -// to the numbers representing what to display, and pointer to the enable flag -// Returns nothing. -// -void STlib_initMultIcon -( st_multicon_t* i, - int x, - int y, - patch_t** il, - int* inum, - boolean* on ) -{ - i->x = x; - i->y = y; - i->oldinum = -1; - i->inum = inum; - i->on = on; - i->p = il; -} - -// -// STlib_updateMultIcon() -// -// Draw a st_multicon_t widget, used for a multigraphic display -// like the status bar's keys. Displays each when the control -// numbers change -// -// Passed a st_multicon_t widget -// Returns nothing. -// -void STlib_updateMultIcon -( st_multicon_t* mi ) -{ - if (*mi->on) - { - if (*mi->inum != -1) // killough 2/16/98: redraw only if != -1 - V_DrawPatch(mi->x, mi->y, mi->p[*mi->inum]); - } -} - -//---------------------------------------------------------------------------- -// -// $Log: st_lib.c,v $ -// Revision 1.8 1998/05/11 10:44:42 jim -// formatted/documented st_lib -// -// Revision 1.7 1998/05/03 22:58:17 killough -// Fix header #includes at top, nothing else -// -// Revision 1.6 1998/02/23 04:56:34 killough -// Fix percent sign problems -// -// Revision 1.5 1998/02/19 16:55:09 jim -// Optimized HUD and made more configurable -// -// Revision 1.4 1998/02/18 00:59:13 jim -// Addition of HUD -// -// Revision 1.3 1998/02/17 06:17:03 killough -// Add support for erasing keys in status bar -// -// Revision 1.2 1998/01/26 19:24:56 phares -// First rev with no ^Ms -// -// Revision 1.1.1.1 1998/01/19 14:03:03 rand -// Lee's Jan 19 sources -// -// -//---------------------------------------------------------------------------- - diff --git a/src/st_lib.h b/src/st_lib.h deleted file mode 100644 index dedf01c91..000000000 --- a/src/st_lib.h +++ /dev/null @@ -1,179 +0,0 @@ -// -// Copyright (C) 1999 by -// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// DESCRIPTION: -// The status bar widget definitions and prototypes -// -//----------------------------------------------------------------------------- - -#ifndef __STLIB__ -#define __STLIB__ - -#include "doomtype.h" - -#define LARGENUMBER 1994 - -// We are referring to patches. -struct patch_s; - -extern boolean sts_colored_numbers;// status numbers do not change colors -extern boolean sts_pct_always_gray;// status percents do not change colors - -// -// Typedefs of widgets -// - -// Number widget - -typedef struct -{ - // upper right-hand corner - // of the number (right-justified) - int x; - int y; - - // max # of digits in number - int width; - - // last number value - int oldnum; - - // pointer to current value - int* num; - - // pointer to boolean stating - // whether to update number - boolean* on; - - // list of patches for 0-9 - struct patch_s** p; - - // user data - int data; -} st_number_t; - -// Percent widget ("child" of number widget, -// or, more precisely, contains a number widget.) -typedef struct -{ - // number information - st_number_t n; - - // percent sign graphic - struct patch_s* p; -} st_percent_t; - -// Multiple Icon widget -typedef struct -{ - // center-justified location of icons - int x; - int y; - - // last icon number - int oldinum; - - // pointer to current icon - int* inum; - - // pointer to boolean stating - // whether to update icon - boolean* on; - - // list of icons - struct patch_s** p; - - // user data - int data; - -} st_multicon_t; - -// -// Widget creation, access, and update routines -// - -// Initializes widget library. -// More precisely, initialize STMINUS, -// everything else is done somewhere else. -// -void STlib_init(void); - -// Number widget routines -void STlib_initNum -( st_number_t* n, - int x, - int y, - struct patch_s** pl, - int* num, - boolean* on, - int width ); - -void STlib_updateNum -( st_number_t* n, - byte *outrng ); //jff 1/16/98 add color translation to digit output - - -// Percent widget routines -void STlib_initPercent -( st_percent_t* p, - int x, - int y, - struct patch_s** pl, - int* num, - boolean* on, - struct patch_s* percent ); - - -void STlib_updatePercent -( st_percent_t* per, - byte *outrng ); //jff 1/16/98 add color translation to percent output - - -// Multiple Icon widget routines -void STlib_initMultIcon -( st_multicon_t* mi, - int x, - int y, - struct patch_s** il, - int* inum, - boolean* on ); - - -void STlib_updateMultIcon -( st_multicon_t* mi ); - -#endif - - -//---------------------------------------------------------------------------- -// -// $Log: st_lib.h,v $ -// Revision 1.5 1998/05/11 10:44:46 jim -// formatted/documented st_lib -// -// Revision 1.4 1998/02/19 16:55:12 jim -// Optimized HUD and made more configurable -// -// Revision 1.3 1998/02/18 00:59:16 jim -// Addition of HUD -// -// Revision 1.2 1998/01/26 19:27:55 phares -// First rev with no ^Ms -// -// Revision 1.1.1.1 1998/01/19 14:03:03 rand -// Lee's Jan 19 sources -// -// -//---------------------------------------------------------------------------- - diff --git a/src/st_sbardef.c b/src/st_sbardef.c new file mode 100644 index 000000000..0dfa5b057 --- /dev/null +++ b/src/st_sbardef.c @@ -0,0 +1,511 @@ +// +// Copyright(C) 2024 Roman Fomin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#include "st_sbardef.h" + +#include + +#include "doomdef.h" +#include "doomtype.h" +#include "i_printf.h" +#include "m_array.h" +#include "m_json.h" +#include "m_misc.h" +#include "m_swap.h" +#include "r_defs.h" +#include "v_fmt.h" +#include "v_video.h" +#include "w_wad.h" +#include "z_zone.h" + +static boolean ParseSbarCondition(json_t *json, sbarcondition_t *out) +{ + json_t *condition = JS_GetObject(json, "condition"); + json_t *param = JS_GetObject(json, "param"); + if (!JS_IsNumber(condition) || !JS_IsNumber(param)) + { + return false; + } + out->condition = JS_GetInteger(condition); + out->param = JS_GetInteger(param); + + return true; +} + +static boolean ParseSbarFrame(json_t *json, sbarframe_t *out) +{ + json_t *lump = JS_GetObject(json, "lump"); + if (!JS_IsString(lump)) + { + return false; + } + out->patch_name = M_StringDuplicate(JS_GetString(lump)); + + json_t *duration = JS_GetObject(json, "duration"); + if (!JS_IsNumber(duration)) + { + return false; + } + out->duration = JS_GetNumber(duration) * TICRATE; + return true; +} + +static boolean ParseSbarElem(json_t *json, sbarelem_t *out); + +static boolean ParseSbarElemType(json_t *json, sbarelementtype_t type, + sbarelem_t *out) +{ + out->type = type; + + json_t *x_pos = JS_GetObject(json, "x"); + json_t *y_pos = JS_GetObject(json, "y"); + json_t *alignment = JS_GetObject(json, "alignment"); + if (!JS_IsNumber(x_pos) || !JS_IsNumber(y_pos) || !JS_IsNumber(alignment)) + { + return false; + } + out->x_pos = JS_GetInteger(x_pos); + out->y_pos = JS_GetInteger(y_pos); + out->alignment = JS_GetInteger(alignment); + + const char *tranmap = JS_GetStringRef(json, "tranmap"); + if (tranmap) + { + out->tranmap = W_CacheLumpName(tranmap, PU_STATIC); + } + + const char *translation = JS_GetStringRef(json, "translation"); + out->cr = translation ? V_CRByName(translation) : CR_NONE; + out->crboom = CR_NONE; + + json_t *js_conditions = JS_GetObject(json, "conditions"); + json_t *js_condition = NULL; + JS_ArrayForEach(js_condition, js_conditions) + { + sbarcondition_t condition = {0}; + if (ParseSbarCondition(js_condition, &condition)) + { + array_push(out->conditions, condition); + } + } + + json_t *js_children = JS_GetObject(json, "children"); + json_t *js_child = NULL; + JS_ArrayForEach(js_child, js_children) + { + sbarelem_t elem = {0}; + if (ParseSbarElem(js_child, &elem)) + { + array_push(out->children, elem); + } + } + + switch (type) + { + case sbe_graphic: + { + sbe_graphic_t *graphic = calloc(1, sizeof(*graphic)); + json_t *patch = JS_GetObject(json, "patch"); + if (!JS_IsString(patch)) + { + return false; + } + graphic->patch_name = M_StringDuplicate(JS_GetString(patch)); + out->subtype.graphic = graphic; + } + break; + + case sbe_animation: + { + sbe_animation_t *animation = calloc(1, sizeof(*animation)); + json_t *js_frames = JS_GetObject(json, "frames"); + json_t *js_frame = NULL; + JS_ArrayForEach(js_frame, js_frames) + { + sbarframe_t frame = {0}; + if (ParseSbarFrame(js_frame, &frame)) + { + array_push(animation->frames, frame); + } + } + out->subtype.animation = animation; + } + break; + + case sbe_number: + case sbe_percent: + { + sbe_number_t *number = calloc(1, sizeof(*number)); + json_t *font = JS_GetObject(json, "font"); + if (!JS_IsString(font)) + { + return false; + } + number->font_name = M_StringDuplicate(JS_GetString(font)); + + json_t *type = JS_GetObject(json, "type"); + json_t *param = JS_GetObject(json, "param"); + json_t *maxlength = JS_GetObject(json, "maxlength"); + if (!JS_IsNumber(type) || !JS_IsNumber(param) + || !JS_IsNumber(maxlength)) + { + return false; + } + number->type = JS_GetInteger(type); + number->param = JS_GetInteger(param); + number->maxlength = JS_GetInteger(maxlength); + out->subtype.number = number; + } + break; + + case sbe_widget: + { + sbe_widget_t *widget = calloc(1, sizeof(*widget)); + + json_t *font = JS_GetObject(json, "font"); + if (!JS_IsString(font)) + { + return false; + } + widget->font_name = M_StringDuplicate(JS_GetString(font)); + + json_t *type = JS_GetObject(json, "type"); + if (!JS_IsNumber(type)) + { + return false; + } + widget->type = JS_GetInteger(type); + + switch (widget->type) + { + case sbw_message: + case sbw_secret: + widget->duration = + JS_GetNumberValue(json, "duration") * TICRATE; + break; + default: + break; + } + + out->subtype.widget = widget; + } + break; + + case sbe_face: + { + sbe_face_t *face = calloc(1, sizeof(*face)); + out->subtype.face = face; + } + break; + + default: + break; + } + return true; +} + +static const char *sbe_names[] = +{ + [sbe_canvas] = "canvas", + [sbe_graphic] = "graphic", + [sbe_animation] = "animation", + [sbe_face] = "face", + [sbe_facebackground] = "facebackground", + [sbe_number] = "number", + [sbe_percent] = "percent", + [sbe_widget] = "widget" +}; + +static boolean ParseSbarElem(json_t *json, sbarelem_t *out) +{ + for (sbarelementtype_t type = sbe_none + 1; type < sbe_max; ++type) + { + json_t *obj = JS_GetObject(json, sbe_names[type]); + if (obj && JS_IsObject(obj)) + { + return ParseSbarElemType(obj, type, out); + } + } + + return false; +} + +static boolean ParseNumberFont(json_t *json, numberfont_t *out) +{ + json_t *name = JS_GetObject(json, "name"); + if (!JS_IsString(name)) + { + return false; + } + out->name = M_StringDuplicate(JS_GetString(name)); + + const char *stem = JS_GetStringRef(json, "stem"); + if (!stem) + { + return false; + } + + json_t *type = JS_GetObject(json, "type"); + if (!JS_IsNumber(type)) + { + return false; + } + out->type = JS_GetInteger(type); + + char lump[9] = {0}; + int found; + int maxwidth = 0; + int maxheight = 0; + + for (int num = 0; num < 10; ++num) + { + M_snprintf(lump, sizeof(lump), "%sNUM%d", stem, num); + found = W_CheckNumForName(lump); + if (found < 0) + { + I_Printf(VB_ERROR, "SBARDEF: patch \"%s\" not found", lump); + continue; + } + out->numbers[num] = V_CachePatchNum(found, PU_STATIC); + maxwidth = MAX(maxwidth, SHORT(out->numbers[num]->width)); + maxheight = MAX(maxheight, SHORT(out->numbers[num]->height)); + } + + out->maxheight = maxheight; + + M_snprintf(lump, sizeof(lump), "%sMINUS", stem); + found = W_CheckNumForName(lump); + if (found >= 0) + { + out->minus = V_CachePatchNum(found, PU_STATIC); + maxwidth = MAX(maxwidth, SHORT(out->minus->width)); + } + + M_snprintf(lump, sizeof(lump), "%sPRCNT", stem); + found = W_CheckNumForName(lump); + if (found >= 0) + { + out->percent = V_CachePatchNum(found, PU_STATIC); + maxwidth = MAX(maxwidth, SHORT(out->percent->width)); + } + + switch (out->type) + { + case sbf_mono0: + out->monowidth = SHORT(out->numbers[0]->width); + break; + case sbf_monomax: + out->monowidth = maxwidth; + break; + default: + break; + } + + return true; +} + +static boolean ParseHUDFont(json_t *json, hudfont_t *out) +{ + json_t *name = JS_GetObject(json, "name"); + if (!JS_IsString(name)) + { + return false; + } + out->name = M_StringDuplicate(JS_GetString(name)); + + const char *stem = JS_GetStringRef(json, "stem"); + if (!stem) + { + return false; + } + + json_t *type = JS_GetObject(json, "type"); + if (!JS_IsNumber(type)) + { + return false; + } + out->type = JS_GetInteger(type); + + char lump[9] = {0}; + int found; + int maxwidth = 0; + int maxheight = 0; + + for (int i = 0; i < HU_FONTSIZE; ++i) + { + M_snprintf(lump, sizeof(lump), "%s%03d", stem, i + HU_FONTSTART); + found = W_CheckNumForName(lump); + if (found < 0) + { + out->characters[i] = NULL; + continue; + } + out->characters[i] = V_CachePatchNum(found, PU_STATIC); + maxwidth = MAX(maxwidth, SHORT(out->characters[i]->width)); + maxheight = MAX(maxheight, SHORT(out->characters[i]->height)); + } + + out->maxheight = maxheight; + + switch (out->type) + { + case sbf_mono0: + out->monowidth = SHORT(out->characters[0]->width); + break; + case sbf_monomax: + out->monowidth = maxwidth; + break; + default: + break; + } + + return true; +} + +static boolean ParseStatusBar(json_t *json, statusbar_t *out) +{ + json_t *height = JS_GetObject(json, "height"); + json_t *fullscreenrender = JS_GetObject(json, "fullscreenrender"); + if (!JS_IsNumber(height) || !JS_IsBoolean(fullscreenrender)) + { + return false; + } + out->height = JS_GetInteger(height); + out->fullscreenrender = JS_GetBoolean(fullscreenrender); + + out->fillflat = JS_GetStringCopy(json, "fillflat"); + + json_t *js_children = JS_GetObject(json, "children"); + json_t *js_child = NULL; + JS_ArrayForEach(js_child, js_children) + { + sbarelem_t elem = {0}; + if (ParseSbarElem(js_child, &elem)) + { + array_push(out->children, elem); + } + } + + return true; +} + +sbardef_t *ST_ParseSbarDef(void) +{ + json_t *json = JS_Open("SBARDEF", "statusbar", (version_t){1, 1, 0}); + if (json == NULL) + { + return NULL; + } + + boolean load_defaults = false; + version_t v = {0}; + JS_GetVersion(json, &v); + if (v.major == 1 && v.minor < 1) + { + load_defaults = true; + } + + json_t *data = JS_GetObject(json, "data"); + if (JS_IsNull(data) || !JS_IsObject(data)) + { + I_Printf(VB_ERROR, "SBARDEF: no data"); + JS_Close(json); + return NULL; + } + + sbardef_t *out = calloc(1, sizeof(*out)); + + json_t *js_numberfonts = JS_GetObject(data, "numberfonts"); + json_t *js_numberfont = NULL; + + JS_ArrayForEach(js_numberfont, js_numberfonts) + { + numberfont_t numberfont = {0}; + if (ParseNumberFont(js_numberfont, &numberfont)) + { + array_push(out->numberfonts, numberfont); + } + } + + json_t *js_hudfonts = JS_GetObject(data, "hudfonts"); + json_t *js_hudfont = NULL; + + JS_ArrayForEach(js_hudfont, js_hudfonts) + { + hudfont_t hudfont = {0}; + if (ParseHUDFont(js_hudfont, &hudfont)) + { + array_push(out->hudfonts, hudfont); + } + } + + json_t *js_statusbars = JS_GetObject(data, "statusbars"); + json_t *js_statusbar = NULL; + + JS_ArrayForEach(js_statusbar, js_statusbars) + { + statusbar_t statusbar = {0}; + if (ParseStatusBar(js_statusbar, &statusbar)) + { + array_push(out->statusbars, statusbar); + } + } + + JS_Close(json); + + if (!load_defaults) + { + return out; + } + + json = JS_Open("SBHUDDEF", "hud", (version_t){1, 0, 0}); + if (json == NULL) + { + return NULL; + } + + data = JS_GetObject(json, "data"); + + js_hudfonts = JS_GetObject(data, "hudfonts"); + js_hudfont = NULL; + + JS_ArrayForEach(js_hudfont, js_hudfonts) + { + hudfont_t hudfont = {0}; + if (ParseHUDFont(js_hudfont, &hudfont)) + { + array_push(out->hudfonts, hudfont); + } + } + + statusbar_t *statusbar; + array_foreach(statusbar, out->statusbars) + { + json_t *js_widgets = JS_GetObject(data, "widgets"); + json_t *js_widget = NULL; + + JS_ArrayForEach(js_widget, js_widgets) + { + sbarelem_t elem = {0}; + if (ParseSbarElem(js_widget, &elem)) + { + elem.y_pos += (statusbar->height - SCREENHEIGHT); + array_push(statusbar->children, elem); + } + } + } + + JS_Close(json); + + return out; +} diff --git a/src/st_sbardef.h b/src/st_sbardef.h new file mode 100644 index 000000000..353b98770 --- /dev/null +++ b/src/st_sbardef.h @@ -0,0 +1,272 @@ +// +// Copyright(C) 2024 Roman Fomin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#ifndef ST_SBARDEF_H +#define ST_SBARDEF_H + +#include "doomtype.h" +#include "r_defs.h" +#include "v_video.h" + +typedef enum +{ + sbf_none = -1, + sbf_mono0, + sbf_monomax, + sbf_proportional, +} fonttype_t; + +typedef enum +{ + sbc_none = -1, + sbc_weaponowned, + sbc_weaponselected, + sbc_weaponnotselected, + sbc_weaponhasammo, + sbc_selectedweaponhasammo, + sbc_selectedweaponammotype, + sbc_weaponslotowned, + sbc_weaponslotnotowned, + sbc_weaponslotselected, + sbc_weaponslotnotselected, + sbc_itemowned, + sbc_itemnotowned, + sbc_featurelevelgreaterequal, + sbc_featurelevelless, + sbc_sessiontypeeequal, + sbc_sessiontypenotequal, + sbc_modeeequal, + sbc_modenotequal, + sbc_hudmodeequal, + + // Woof! + sbc_widgetmode, + sbc_widgetenabled, + sbc_widgetdisabled, + + sbc_max, +} sbarconditiontype_t; + +typedef struct +{ + sbarconditiontype_t condition; + int param; +} sbarcondition_t; + +typedef enum +{ + sbc_mode_none, + sbc_mode_automap = 0x01, + sbc_mode_overlay = 0x02, + sbc_mode_hud = 0x04, +} sbc_mode_t; + +typedef enum +{ + sbn_none = -1, + sbn_health, + sbn_armor, + sbn_frags, + sbn_ammo, + sbn_ammoselected, + sbn_maxammo, + sbn_weaponammo, + sbn_weaponmaxammo, + + sbn_max, +} sbarnumbertype_t; + +typedef enum +{ + sbe_none = -1, + sbe_canvas, + sbe_graphic, + sbe_animation, + sbe_face, + sbe_facebackground, + sbe_number, + sbe_percent, + + // Woof! + sbe_widget, + + sbe_max, +} sbarelementtype_t; + +typedef enum +{ + sbw_monsec, + sbw_time, + sbw_coord, + sbw_fps, + sbw_rate, + sbw_cmd, + sbw_speed, + + sbw_message, + sbw_secret, + sbw_chat, + sbw_title, +} sbarwidgettype_t; + +typedef enum +{ + sbe_h_left = 0x00, + sbe_h_middle = 0x01, + sbe_h_right = 0x02, + + sbe_h_mask = 0x03, + + sbe_v_top = 0x00, + sbe_v_middle = 0x04, + sbe_v_bottom = 0x08, + + sbe_v_mask = 0x0C, + + // Woof! + sbe_wide_left = 0x10, + sbe_wide_right = 0x20, +} sbaralignment_t; + +typedef struct +{ + const char *patch_name; + patch_t *patch; + int duration; +} sbarframe_t; + +typedef struct sbarelem_s sbarelem_t; +typedef struct numberfont_s numberfont_t; +typedef struct hudfont_s hudfont_t; + +typedef struct +{ + const char *patch_name; + patch_t *patch; +} sbe_graphic_t; + +typedef struct +{ + sbarframe_t *frames; + int frame_index; + int duration_left; +} sbe_animation_t; + +typedef struct +{ + const char *font_name; + numberfont_t *font; + sbarnumbertype_t type; + int param; + int maxlength; + int value; + int numvalues; + int oldvalue; + int xoffset; +} sbe_number_t; + +typedef struct +{ + int faceindex; + int facecount; + int oldhealth; +} sbe_face_t; + +typedef struct +{ + const char *string; + int totalwidth; + int xoffset; +} widgetline_t; + +typedef struct sbe_widget_s +{ + sbarwidgettype_t type; + const char *font_name; + hudfont_t *font; + widgetline_t *lines; + + // message + int duration; +} sbe_widget_t; + +struct sbarelem_s +{ + sbarelementtype_t type; + int x_pos; + int y_pos; + sbaralignment_t alignment; + sbarcondition_t *conditions; + sbarelem_t *children; + + byte *tranmap; + crange_idx_e cr; + crange_idx_e crboom; + + union + { + sbe_graphic_t *graphic; + sbe_animation_t *animation; + sbe_number_t *number; + sbe_face_t *face; + + // Woof! + sbe_widget_t *widget; + } subtype; +}; + +typedef struct +{ + int height; + boolean fullscreenrender; + const char *fillflat; + sbarelem_t *children; +} statusbar_t; + +struct numberfont_s +{ + const char *name; + fonttype_t type; + int monowidth; + int maxheight; + patch_t *numbers[10]; + patch_t *percent; + patch_t *minus; +}; + +#define HU_FONTSTART '!' /* the first font characters */ +#define HU_FONTEND (0x7f) /*jff 2/16/98 '_' the last font characters */ + +// Calculate # of glyphs in font. +#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1) +#define SPACEWIDTH 4 + +struct hudfont_s +{ + const char *name; + fonttype_t type; + int monowidth; + int maxheight; + patch_t *characters[HU_FONTSIZE]; +}; + +typedef struct +{ + numberfont_t *numberfonts; + hudfont_t *hudfonts; + statusbar_t *statusbars; +} sbardef_t; + +sbardef_t *ST_ParseSbarDef(void); + +#endif diff --git a/src/st_stuff.c b/src/st_stuff.c index 8ad76fa67..ff89f317e 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -28,25 +28,30 @@ #include "d_player.h" #include "doomdef.h" #include "doomstat.h" -#include "hu_stuff.h" // [FG] hud_displayed -#include "i_printf.h" +#include "doomtype.h" +#include "hu_command.h" +#include "hu_obituary.h" +#include "i_system.h" #include "i_video.h" #include "info.h" +#include "m_array.h" #include "m_cheat.h" #include "m_config.h" #include "m_misc.h" #include "m_random.h" #include "m_swap.h" -#include "mn_menu.h" #include "p_mobj.h" +#include "p_user.h" +#include "hu_crosshair.h" #include "r_data.h" #include "r_defs.h" +#include "r_draw.h" #include "r_main.h" #include "r_state.h" #include "s_sound.h" -#include "sounds.h" -#include "st_lib.h" #include "st_stuff.h" +#include "st_sbardef.h" +#include "st_widgets.h" #include "tables.h" #include "v_fmt.h" #include "v_video.h" @@ -66,13 +71,6 @@ // Radiation suit, green shift. #define RADIATIONPAL 13 -// Location of status bar -#define ST_X 0 -#define ST_X2 104 - -#define ST_FX 143 -#define ST_FY 169 - // Number of status faces. #define ST_NUMPAINFACES 5 #define ST_NUMSTRAIGHTFACES 3 @@ -86,1400 +84,1747 @@ #define ST_NUMXDTHFACES 9 #define ST_NUMFACES \ - (ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES+ST_NUMXDTHFACES) - -#define ST_TURNOFFSET (ST_NUMSTRAIGHTFACES) -#define ST_OUCHOFFSET (ST_TURNOFFSET + ST_NUMTURNFACES) -#define ST_EVILGRINOFFSET (ST_OUCHOFFSET + 1) -#define ST_RAMPAGEOFFSET (ST_EVILGRINOFFSET + 1) -#define ST_GODFACE (ST_NUMPAINFACES*ST_FACESTRIDE) -#define ST_DEADFACE (ST_GODFACE+1) -#define ST_XDTHFACE (ST_DEADFACE+1) - -#define ST_FACESX 143 -#define ST_FACESY 168 - -#define ST_EVILGRINCOUNT (2*TICRATE) -#define ST_STRAIGHTFACECOUNT (TICRATE/2) -#define ST_TURNCOUNT (1*TICRATE) -#define ST_OUCHCOUNT (1*TICRATE) -#define ST_RAMPAGEDELAY (2*TICRATE) - -#define ST_MUCHPAIN 20 - -// Location and size of statistics, -// justified according to widget type. -// Problem is, within which space? STbar? Screen? -// Note: this could be read in by a lump. -// Problem is, is the stuff rendered -// into a buffer, -// or into the frame buffer? -// I dunno, why don't you go and find out!!! killough - -// AMMO number pos. -#define ST_AMMOWIDTH 3 -#define ST_AMMOX 44 -#define ST_AMMOY 171 - -// HEALTH number pos. -#define ST_HEALTHWIDTH 3 -#define ST_HEALTHX 90 -#define ST_HEALTHY 171 - -// Weapon pos. -#define ST_ARMSX 111 -#define ST_ARMSY 172 -#define ST_ARMSBGX 104 -#define ST_ARMSBGY 168 -#define ST_ARMSXSPACE 12 -#define ST_ARMSYSPACE 10 - -// Frags pos. -#define ST_FRAGSX 138 -#define ST_FRAGSY 171 -#define ST_FRAGSWIDTH 2 - -// ARMOR number pos. -#define ST_ARMORWIDTH 3 -#define ST_ARMORX 221 -#define ST_ARMORY 171 - -// Key icon positions. -#define ST_KEY0WIDTH 8 -#define ST_KEY0HEIGHT 5 -#define ST_KEY0X 239 -#define ST_KEY0Y 171 -#define ST_KEY1WIDTH ST_KEY0WIDTH -#define ST_KEY1X 239 -#define ST_KEY1Y 181 -#define ST_KEY2WIDTH ST_KEY0WIDTH -#define ST_KEY2X 239 -#define ST_KEY2Y 191 - -// Ammunition counter. -#define ST_AMMO0WIDTH 3 -#define ST_AMMO0HEIGHT 6 -#define ST_AMMO0X 288 -#define ST_AMMO0Y 173 -#define ST_AMMO1WIDTH ST_AMMO0WIDTH -#define ST_AMMO1X 288 -#define ST_AMMO1Y 179 -#define ST_AMMO2WIDTH ST_AMMO0WIDTH -#define ST_AMMO2X 288 -#define ST_AMMO2Y 191 -#define ST_AMMO3WIDTH ST_AMMO0WIDTH -#define ST_AMMO3X 288 -#define ST_AMMO3Y 185 - -// Indicate maximum ammunition. -// Only needed because backpack exists. -#define ST_MAXAMMO0WIDTH 3 -#define ST_MAXAMMO0HEIGHT 5 -#define ST_MAXAMMO0X 314 -#define ST_MAXAMMO0Y 173 -#define ST_MAXAMMO1WIDTH ST_MAXAMMO0WIDTH -#define ST_MAXAMMO1X 314 -#define ST_MAXAMMO1Y 179 -#define ST_MAXAMMO2WIDTH ST_MAXAMMO0WIDTH -#define ST_MAXAMMO2X 314 -#define ST_MAXAMMO2Y 191 -#define ST_MAXAMMO3WIDTH ST_MAXAMMO0WIDTH -#define ST_MAXAMMO3X 314 -#define ST_MAXAMMO3Y 185 - -// killough 2/8/98: weapon info position macros UNUSED, removed here + (ST_FACESTRIDE * ST_NUMPAINFACES + ST_NUMEXTRAFACES + ST_NUMXDTHFACES) + +#define ST_TURNOFFSET (ST_NUMSTRAIGHTFACES) +#define ST_OUCHOFFSET (ST_TURNOFFSET + ST_NUMTURNFACES) +#define ST_EVILGRINOFFSET (ST_OUCHOFFSET + 1) +#define ST_RAMPAGEOFFSET (ST_EVILGRINOFFSET + 1) +#define ST_GODFACE (ST_NUMPAINFACES * ST_FACESTRIDE) +#define ST_DEADFACE (ST_GODFACE + 1) +#define ST_XDTHFACE (ST_DEADFACE + 1) + +#define ST_EVILGRINCOUNT (2 * TICRATE) +#define ST_STRAIGHTFACECOUNT (TICRATE / 2) +#define ST_TURNCOUNT (1 * TICRATE) +#define ST_OUCHCOUNT (1 * TICRATE) +#define ST_RAMPAGEDELAY (2 * TICRATE) + +#define ST_MUCHPAIN 20 // graphics are drawn to a backing screen and blitted to the real screen static pixel_t *st_backing_screen = NULL; -// main player in game -static player_t *plyr; +// [Alaux] +static boolean hud_animated_counts; -// ST_Start() has just been called -static boolean st_firsttime; +static boolean sts_colored_numbers; -// lump number for PLAYPAL -static int lu_palette; +static boolean sts_pct_always_gray; -// whether left-side main status bar is active -static boolean st_statusbaron; +//jff 2/16/98 status color change levels +static int ammo_red; // ammo percent less than which status is red +static int ammo_yellow; // ammo percent less is yellow more green +int health_red; // health amount less than which status is red +int health_yellow; // health amount less than which status is yellow +int health_green; // health amount above is blue, below is green +static int armor_red; // armor amount less than which status is red +static int armor_yellow; // armor amount less than which status is yellow +static int armor_green; // armor amount above is blue, below is green -// [crispy] distinguish classic status bar with background and player face -// from Crispy HUD -static boolean st_crispyhud; -static boolean st_classicstatusbar; +static boolean hud_armor_type; // color of armor depends on type -// !deathmatch -static boolean st_notdeathmatch; +// used for evil grin +static boolean oldweaponsowned[NUMWEAPONS]; -// !deathmatch && st_statusbaron -static boolean st_armson; +// [crispy] blinking key or skull in the status bar +int st_keyorskull[3]; -// !deathmatch -static boolean st_fragson; +static sbardef_t *sbardef; -// main bar left -static patch_t *sbar; +static statusbar_t *statusbar; -// main bar right, for doom 1.0 -static patch_t *sbarr; +typedef enum +{ + st_original, + st_wide +} st_layout_t; -// 0-9, tall numbers -static patch_t *tallnum[10]; +static st_layout_t st_layout; -// tall % sign -static patch_t *tallpercent; +static patch_t **facepatches = NULL; -// 0-9, short, yellow (,different!) numbers -static patch_t *shortnum[10]; +static int have_xdthfaces; -// 3 key-cards, 3 skulls, 3 card/skull combos -// jff 2/24/98 extend number of patches by three skull/card combos -static patch_t *keys[NUMCARDS+3]; +// +// STATUS BAR CODE +// -// face status patches -static patch_t *faces[ST_NUMFACES]; -static int have_xdthfaces; +static patch_t *CachePatchName(const char *name) +{ + int lumpnum = W_CheckNumForName(name); + if (lumpnum < 0) + { + lumpnum = (W_CheckNumForName)(name, ns_sprites); + if (lumpnum < 0) + { + return NULL; + } + } + return V_CachePatchNum(lumpnum, PU_STATIC); +} -// face background -static patch_t *faceback[MAXPLAYERS]; // killough 3/7/98: make array +static void LoadFacePatches(void) +{ + char lump[9] = {0}; - // main bar right -static patch_t *armsbg; + int painface; -// weapon ownership patches -static patch_t *arms[6][2]; + for (painface = 0; painface < ST_NUMPAINFACES; ++painface) + { + for (int straightface = 0; straightface < ST_NUMSTRAIGHTFACES; + ++straightface) + { + M_snprintf(lump, sizeof(lump), "STFST%d%d", painface, straightface); + array_push(facepatches, V_CachePatchName(lump, PU_STATIC)); + } -// ready-weapon widget -static st_number_t w_ready; + M_snprintf(lump, sizeof(lump), "STFTR%d0", painface); // turn right + array_push(facepatches, V_CachePatchName(lump, PU_STATIC)); -// [Alaux] -static boolean hud_animated_counts; -int st_health = 100; -int st_armor = 0; + M_snprintf(lump, sizeof(lump), "STFTL%d0", painface); // turn left + array_push(facepatches, V_CachePatchName(lump, PU_STATIC)); -//jff 2/16/98 status color change levels -int ammo_red; // ammo percent less than which status is red -int ammo_yellow; // ammo percent less is yellow more green -int health_red; // health amount less than which status is red -int health_yellow; // health amount less than which status is yellow -int health_green; // health amount above is blue, below is green -int armor_red; // armor amount less than which status is red -int armor_yellow; // armor amount less than which status is yellow -int armor_green; // armor amount above is blue, below is green + M_snprintf(lump, sizeof(lump), "STFOUCH%d", painface); // ouch! + array_push(facepatches, V_CachePatchName(lump, PU_STATIC)); -boolean hud_backpack_thresholds; // backpack changes thresholds -boolean hud_armor_type; // color of armor depends on type + M_snprintf(lump, sizeof(lump), "STFEVL%d", painface); // evil grin ;) + array_push(facepatches, V_CachePatchName(lump, PU_STATIC)); - // in deathmatch only, summary of frags stats -static st_number_t w_frags; + M_snprintf(lump, sizeof(lump), "STFKILL%d", painface); // pissed off + array_push(facepatches, V_CachePatchName(lump, PU_STATIC)); + } -// health widget -static st_percent_t w_health; + M_snprintf(lump, sizeof(lump), "STFGOD0"); + array_push(facepatches, V_CachePatchName(lump, PU_STATIC)); -// weapon ownership widgets -static st_multicon_t w_arms[6]; + M_snprintf(lump, sizeof(lump), "STFDEAD0"); + array_push(facepatches, V_CachePatchName(lump, PU_STATIC)); -// face status widget -static st_multicon_t w_faces; + // [FG] support face gib animations as in the 3DO/Jaguar/PSX ports + for (painface = 0; painface < ST_NUMXDTHFACES; ++painface) + { + M_snprintf(lump, sizeof(lump), "STFXDTH%d", painface); -// keycard widgets -static st_multicon_t w_keyboxes[3]; + if (W_CheckNumForName(lump) != -1) + { + array_push(facepatches, V_CachePatchName(lump, PU_STATIC)); + } + else + { + break; + } + } + have_xdthfaces = painface; +} -// armor widget -static st_percent_t w_armor; +static boolean CheckWidgetState(widgetstate_t state) +{ + if ((state == HUD_WIDGET_AUTOMAP && automapactive) + || (state == HUD_WIDGET_HUD && !automapactive) + || (state == HUD_WIDGET_ALWAYS)) + { + return true; + } -// ammo widgets -static st_number_t w_ammo[4]; + return false; +} -// max ammo widgets -static st_number_t w_maxammo[4]; +static boolean CheckConditions(sbarcondition_t *conditions, player_t *player) +{ + boolean result = true; + int currsessiontype = netgame ? MIN(deathmatch + 1, 2) : 0; + // TODO + // boolean compacthud = frame_width < frame_adjusted_width; - // number of frags so far in deathmatch -static int st_fragscount; + sbarcondition_t *cond; + array_foreach(cond, conditions) + { + switch (cond->condition) + { + case sbc_weaponowned: + if (cond->param >= 0 && cond->param < NUMWEAPONS) + { + result &= !!player->weaponowned[cond->param]; + } + break; -// used to use appopriately pained face -static int st_oldhealth = -1; + case sbc_weaponselected: + result &= player->readyweapon == cond->param; + break; -// used for evil grin -static boolean oldweaponsowned[NUMWEAPONS]; + case sbc_weaponnotselected: + result &= player->readyweapon != cond->param; + break; - // count until face changes -static int st_facecount = 0; + case sbc_weaponhasammo: + if (cond->param >= 0 && cond->param < NUMWEAPONS) + { + result &= weaponinfo[cond->param].ammo != am_noammo; + } + break; -// current face index, used by w_faces -static int st_faceindex = 0; + case sbc_selectedweaponhasammo: + result &= weaponinfo[player->readyweapon].ammo != am_noammo; + break; -// holds key-type for each key box on bar -static int keyboxes[3]; -// [crispy] blinking key or skull in the status bar -int st_keyorskull[3]; + case sbc_selectedweaponammotype: + result &= + weaponinfo[player->readyweapon].ammo == cond->param; + break; -// a random number per tick -static int st_randomnumber; + case sbc_weaponslotowned: + { + boolean owned = false; + for (int i = 0; i < NUMWEAPONS; ++i) + { + if (weaponinfo[i].slot == cond->param + && player->weaponowned[i]) + { + owned = true; + break; + } + } + result &= owned; + } + break; -// -// STATUS BAR CODE -// + case sbc_weaponslotnotowned: + { + boolean notowned = true; + for (int i = 0; i < NUMWEAPONS; ++i) + { + if (weaponinfo[i].slot == cond->param + && player->weaponowned[i]) + { + notowned = false; + break; + } + } + result &= notowned; + } + break; -void ST_Stop(void); + case sbc_weaponslotselected: + result &= weaponinfo[player->readyweapon].slot == cond->param; + break; -static boolean st_solidbackground; + case sbc_weaponslotnotselected: + result &= weaponinfo[player->readyweapon].slot != cond->param; + break; -static void ST_DrawSolidBackground(int st_x) -{ - // [FG] calculate average color of the 16px left and right of the status bar - const int vstep[][2] = {{0, 1}, {1, 2}, {2, ST_HEIGHT}}; + case sbc_itemowned: + result &= + !!P_EvaluateItemOwned((itemtype_t)cond->param, player); + break; - byte *pal = W_CacheLumpName("PLAYPAL", PU_STATIC); + case sbc_itemnotowned: + result &= + !P_EvaluateItemOwned((itemtype_t)cond->param, player); + break; - // [FG] temporarily draw status bar to background buffer - V_DrawPatch(st_x, 0, sbar); + case sbc_featurelevelgreaterequal: + // ignore + break; - const int offset = MAX(st_x + video.deltaw - SHORT(sbar->leftoffset), 0); - const int width = MIN(SHORT(sbar->width), video.unscaledw); - const int depth = 16; - int v; + case sbc_featurelevelless: + // ignore + break; - // [FG] separate colors for the top rows - for (v = 0; v < arrlen(vstep); v++) - { - int x, y; - const int v0 = vstep[v][0], v1 = vstep[v][1]; - unsigned r = 0, g = 0, b = 0; - byte col; + case sbc_sessiontypeeequal: + result &= currsessiontype == cond->param; + break; - for (y = v0; y < v1; y++) - { - for (x = 0; x < depth; x++) - { - byte *c = st_backing_screen + V_ScaleY(y) * video.pitch + V_ScaleX(x + offset); - r += pal[3 * c[0] + 0]; - g += pal[3 * c[0] + 1]; - b += pal[3 * c[0] + 2]; + case sbc_sessiontypenotequal: + result &= currsessiontype != cond->param; + break; - c += V_ScaleX(width - 2 * x - 1); - r += pal[3 * c[0] + 0]; - g += pal[3 * c[0] + 1]; - b += pal[3 * c[0] + 2]; - } - } + case sbc_modeeequal: + result &= gamemode == (cond->param + 1); + break; - r /= 2 * depth * (v1 - v0); - g /= 2 * depth * (v1 - v0); - b /= 2 * depth * (v1 - v0); + case sbc_modenotequal: + result &= gamemode != (cond->param + 1); + break; - // [FG] tune down to half saturation (for empiric reasons) - col = I_GetNearestColor(pal, r/2, g/2, b/2); + case sbc_hudmodeequal: + // TODO + // result &= ( !!cond->param == compacthud ); + result &= (!!cond->param == false); + break; - V_FillRect(0, v0, video.unscaledw, v1 - v0, col); - } + case sbc_widgetmode: + { + int enabled = 0; + if (cond->param & sbc_mode_overlay) + { + enabled |= (automapactive && automapoverlay); + } + else if (cond->param & sbc_mode_automap) + { + enabled |= (automapactive && !automapoverlay); + } + if (cond->param & sbc_mode_hud) + { + enabled |= !automapactive; + } + result &= (enabled > 0); + } + break; - Z_ChangeTag (pal, PU_CACHE); -} + case sbc_widgetenabled: + { + widgetstate_t state = HUD_WIDGET_OFF; + switch ((sbarwidgettype_t)cond->param) + { + case sbw_monsec: + state = hud_level_stats; + break; + case sbw_time: + state = hud_level_time; + break; + case sbw_coord: + state = hud_player_coords; + break; + default: + break; + } + result &= CheckWidgetState(state); + } + break; -void ST_refreshBackground(void) -{ - int st_x; + case sbc_widgetdisabled: + { + widgetstate_t state = HUD_WIDGET_OFF; + switch ((sbarwidgettype_t)cond->param) + { + case sbw_monsec: + state = hud_level_stats; + break; + case sbw_time: + state = hud_level_time; + break; + case sbw_coord: + state = hud_player_coords; + break; + default: + break; + } + result &= !CheckWidgetState(state); + } + break; - if (!st_classicstatusbar) - { - return; + case sbc_none: + default: + result = false; + break; + } } - st_x = ST_X + (SCREENWIDTH - SHORT(sbar->width)) / 2 + SHORT(sbar->leftoffset); + return result; +} - V_UseBuffer(st_backing_screen); +// [Alaux] +static int SmoothCount(int shownval, int realval) +{ + int step = realval - shownval; - if (video.unscaledw != ST_WIDTH) + if (!hud_animated_counts || !step) { - if (st_solidbackground) + return realval; + } + else + { + int sign = step / abs(step); + step = BETWEEN(1, 7, abs(step) / 20); + shownval += (step + 1) * sign; + + if ((sign > 0 && shownval > realval) + || (sign < 0 && shownval < realval)) { - ST_DrawSolidBackground(st_x); + shownval = realval; } - else - { - // [crispy] this is our own local copy of R_FillBackScreen() to fill - // the entire background of st_backing_screen with the bezel - // pattern, so it appears to the left and right of the status bar - // in widescreen mode - const char *name = (gamemode == commercial) ? "GRNROCK" : "FLOOR7_2"; - const byte *src = V_CacheFlatNum(firstflat + R_FlatNumForName(name), PU_CACHE); + return shownval; + } +} - V_TileBlock64(SCREENHEIGHT - ST_HEIGHT, video.unscaledw, ST_HEIGHT, src); +static int ResolveNumber(sbe_number_t *number, player_t *player) +{ + int result = 0; + int param = number->param; - // [crispy] preserve bezel bottom edge - if (scaledviewwidth == video.unscaledw) + switch (number->type) + { + case sbn_health: + if (number->oldvalue == -1) { - int x; - patch_t *patch = V_CachePatchName("brdr_b", PU_CACHE); + number->oldvalue = player->health; + } + result = SmoothCount(number->oldvalue, player->health); + number->oldvalue = result; + break; - for (x = 0; x < video.deltaw; x += 8) - { - V_DrawPatch(x - video.deltaw, 0, patch); - V_DrawPatch(video.unscaledw - video.deltaw - x - 8, 0, patch); - } + case sbn_armor: + if (number->oldvalue == -1) + { + number->oldvalue = player->armorpoints; } - } - } + result = SmoothCount(number->oldvalue, player->armorpoints); + number->oldvalue = result; + break; - // [crispy] center unity rerelease wide status bar - V_DrawPatch(st_x, 0, sbar); + case sbn_frags: + for (int p = 0; p < MAXPLAYERS; ++p) + { + result += player->frags[p]; + } + break; - // draw right side of bar if needed (Doom 1.0) - if (sbarr) - V_DrawPatch(ST_ARMSBGX, 0, sbarr); + case sbn_ammo: + if (param >= 0 && param < NUMAMMO) + { + result = player->ammo[param]; + } + break; - if (st_notdeathmatch) - V_DrawPatch(ST_ARMSBGX, 0, armsbg); + case sbn_ammoselected: + result = player->ammo[weaponinfo[player->readyweapon].ammo]; + break; - // killough 3/7/98: make face background change with displayplayer - if (netgame) - V_DrawPatch(ST_FX, 0, faceback[displayplayer]); + case sbn_maxammo: + if (param >= 0 && param < NUMAMMO) + { + result = player->maxammo[param]; + } + break; - V_RestoreBuffer(); + case sbn_weaponammo: + if (param >= 0 && param < NUMWEAPONS) + { + result = player->ammo[weaponinfo[param].ammo]; + } + break; - // [crispy] copy entire video.unscaledw, to preserve the pattern to the left - // and right of the status bar in widescren mode - V_CopyRect(0, 0, st_backing_screen, video.unscaledw, ST_HEIGHT, 0, ST_Y); -} + case sbn_weaponmaxammo: + if (param >= 0 && param < NUMWEAPONS) + { + result = player->maxammo[weaponinfo[param].ammo]; + } + break; -// Respond to keyboard input events, -// intercept cheats. -boolean ST_Responder(event_t *ev) -{ - // Filter automap on/off. - if (ev->type == ev_keyup && (ev->data1.i & 0xffff0000) == AM_MSGHEADER) - { - if (ev->data1.i == AM_MSGENTERED) - { - st_firsttime = true; - } + case sbn_none: + default: + break; } - else // if a user keypress... - return M_CheatResponder(ev); // Try cheat responder in m_cheat.c - return false; + + return result; } -int ST_calcPainOffset(void) +static int CalcPainOffset(sbe_face_t *face, player_t *player) { - static int lastcalc; - static int oldhealth = -1; - int health = plyr->health > 100 ? 100 : plyr->health; - - if (health != oldhealth) - { - lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101); - oldhealth = health; - } - return lastcalc; + int health = player->health > 100 ? 100 : player->health; + int lasthealthcalc = + ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101); + face->oldhealth = health; + return lasthealthcalc; } -// -// This is a not-very-pretty routine which handles -// the face states and their timing. -// the precedence of expressions is: -// dead > evil grin > turned head > straight ahead -// - -static int ST_DeadFace(void) +static int DeadFace(player_t *player) { - const int state = (plyr->mo->state - states) - mobjinfo[plyr->mo->type].xdeathstate; + const int state = + (player->mo->state - states) - mobjinfo[player->mo->type].xdeathstate; - // [FG] support face gib animations as in the 3DO/Jaguar/PSX ports - if (have_xdthfaces && state >= 0) - { - return ST_XDTHFACE + MIN(state, have_xdthfaces - 1); - } + // [FG] support face gib animations as in the 3DO/Jaguar/PSX ports + if (have_xdthfaces && state >= 0) + { + return ST_XDTHFACE + MIN(state, have_xdthfaces - 1); + } - return ST_DEADFACE; + return ST_DEADFACE; } -void ST_updateFaceWidget(void) +static void UpdateFace(sbe_face_t *face, player_t *player) { - int i; - angle_t badguyangle; - angle_t diffang; - static int lastattackdown = -1; - static int priority = 0; - boolean doevilgrin; + static int priority; + static int lastattackdown = -1; - if (priority < 10) + if (priority < 10) { - // dead - if (!plyr->health) + // dead + if (!player->health) { - priority = 9; - st_faceindex = ST_DeadFace(); - st_facecount = 1; + priority = 9; + face->faceindex = DeadFace(player); + face->facecount = 1; } } - if (priority < 9) + if (priority < 9) { - if (plyr->bonuscount) + if (player->bonuscount) { - // picking up bonus - doevilgrin = false; + // picking up bonus + boolean doevilgrin = false; - for (i=0;iweaponowned[i]) + if (oldweaponsowned[i] != player->weaponowned[i]) { - doevilgrin = true; - oldweaponsowned[i] = plyr->weaponowned[i]; + doevilgrin = true; + oldweaponsowned[i] = player->weaponowned[i]; } } - if (doevilgrin) + + if (doevilgrin) { - // evil grin if just picked up weapon - priority = 8; - st_facecount = ST_EVILGRINCOUNT; - st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET; + // evil grin if just picked up weapon + priority = 8; + face->facecount = ST_EVILGRINCOUNT; + face->faceindex = CalcPainOffset(face, player) + ST_EVILGRINOFFSET; } } - } - if (priority < 8) + if (priority < 8) { - if (plyr->damagecount && plyr->attacker && plyr->attacker != plyr->mo) + if (player->damagecount && player->attacker + && player->attacker != player->mo) { - // being attacked - priority = 7; + // being attacked + priority = 7; + + angle_t diffangle = 0; + boolean right = false; - // [FG] show "Ouch Face" as intended - if (st_oldhealth - plyr->health > ST_MUCHPAIN) + // [FG] show "Ouch Face" as intended + if (player->health - face->oldhealth > ST_MUCHPAIN) { - // [FG] raise "Ouch Face" priority - priority = 8; - st_facecount = ST_TURNCOUNT; - st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; + // [FG] raise "Ouch Face" priority + priority = 8; + face->facecount = ST_TURNCOUNT; + face->faceindex = CalcPainOffset(face, player) + ST_OUCHOFFSET; } - else + else { - badguyangle = R_PointToAngle2(plyr->mo->x, - plyr->mo->y, - plyr->attacker->x, - plyr->attacker->y); + angle_t badguyangle = + R_PointToAngle2(player->mo->x, player->mo->y, + player->attacker->x, player->attacker->y); - if (badguyangle > plyr->mo->angle) + if (badguyangle > player->mo->angle) { - // whether right or left - diffang = badguyangle - plyr->mo->angle; - i = diffang > ANG180; + // whether right or left + diffangle = badguyangle - player->mo->angle; + right = diffangle > ANG180; } - else + else { - // whether left or right - diffang = plyr->mo->angle - badguyangle; - i = diffang <= ANG180; + // whether left or right + diffangle = player->mo->angle - badguyangle; + right = diffangle <= ANG180; } // confusing, aint it? + face->facecount = ST_TURNCOUNT; + face->faceindex = CalcPainOffset(face, player); - st_facecount = ST_TURNCOUNT; - st_faceindex = ST_calcPainOffset(); - - if (diffang < ANG45) + if (diffangle < ANG45) { - // head-on - st_faceindex += ST_RAMPAGEOFFSET; + // head-on + face->faceindex += ST_RAMPAGEOFFSET; } - else if (i) + else if (right) { - // turn face right - st_faceindex += ST_TURNOFFSET; + // turn face right + face->faceindex += ST_TURNOFFSET; } - else + else { - // turn face left - st_faceindex += ST_TURNOFFSET+1; + // turn face left + face->faceindex += ST_TURNOFFSET + 1; } } } } - if (priority < 7) + if (priority < 7) { - // getting hurt because of your own damn stupidity - if (plyr->damagecount) + // getting hurt because of your own damn stupidity + if (player->damagecount) { - // [FG] show "Ouch Face" as intended - if (st_oldhealth - plyr->health > ST_MUCHPAIN) + if (player->health - face->oldhealth > ST_MUCHPAIN) { - priority = 7; - st_facecount = ST_TURNCOUNT; - st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET; + priority = 7; + face->facecount = ST_TURNCOUNT; + face->faceindex = CalcPainOffset(face, player) + ST_OUCHOFFSET; } - else + else { - priority = 6; - st_facecount = ST_TURNCOUNT; - st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; + priority = 6; + face->facecount = ST_TURNCOUNT; + face->faceindex = CalcPainOffset(face, player) + ST_RAMPAGEOFFSET; } - } - } - if (priority < 6) + if (priority < 6) { - // rapid firing - if (plyr->attackdown) + // rapid firing + if (player->attackdown) { - if (lastattackdown==-1) - lastattackdown = ST_RAMPAGEDELAY; - else if (!--lastattackdown) + if (lastattackdown == -1) + { + lastattackdown = ST_RAMPAGEDELAY; + } + else if (!--lastattackdown) { - priority = 5; - st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET; - st_facecount = 1; - lastattackdown = 1; + priority = 5; + face->faceindex = CalcPainOffset(face, player) + ST_RAMPAGEOFFSET; + face->facecount = 1; + lastattackdown = 1; } } - else - lastattackdown = -1; - + else + { + lastattackdown = -1; + } } - if (priority < 5) + if (priority < 5) { - // invulnerability - if ((plyr->cheats & CF_GODMODE) - || plyr->powers[pw_invulnerability]) + // invulnerability + if ((player->cheats & CF_GODMODE) || player->powers[pw_invulnerability]) { - priority = 4; - - st_faceindex = ST_GODFACE; - st_facecount = 1; - + priority = 4; + face->faceindex = ST_GODFACE; + face->facecount = 1; } - } - // look left or look right if the facecount has timed out - if (!st_facecount) + // look left or look right if the facecount has timed out + if (!face->facecount) { - st_faceindex = ST_calcPainOffset() + (st_randomnumber % 3); - st_facecount = ST_STRAIGHTFACECOUNT; - priority = 0; + face->faceindex = CalcPainOffset(face, player) + (M_Random() % 3); + face->facecount = ST_STRAIGHTFACECOUNT; + priority = 0; } - st_facecount--; - + --face->facecount; } -static boolean sts_traditional_keys; // killough 2/28/98: traditional status bar keys -static boolean hud_blink_keys; // [crispy] blinking key or skull in the status bar - -void ST_SetKeyBlink(player_t* player, int blue, int yellow, int red) +static void UpdateNumber(sbarelem_t *elem, player_t *player) { - int i; - // Init array with args to iterate through - const int keys[3] = { blue, yellow, red }; + sbe_number_t *number = elem->subtype.number; - player->keyblinktics = KEYBLINKTICS; + int value = ResolveNumber(number, player); + int power = (value < 0 ? number->maxlength - 1 : number->maxlength); + int max = (int)pow(10.0, power) - 1; + int valglyphs = 0; + int numvalues = 0; - for (i = 0; i < 3; i++) - { - if ( ((keys[i] == KEYBLINK_EITHER) && !(player->cards[i] || player->cards[i+3])) - || ((keys[i] == KEYBLINK_CARD) && !(player->cards[i])) - || ((keys[i] == KEYBLINK_SKULL) && !(player->cards[i+3])) - || ((keys[i] == KEYBLINK_BOTH) && !(player->cards[i] && player->cards[i+3]))) - { - player->keyblinkkeys[i] = keys[i]; - } - else + numberfont_t *font = number->font; + if (font == NULL) { - player->keyblinkkeys[i] = KEYBLINK_NONE; + array_foreach(font, sbardef->numberfonts) + { + if (!strcmp(font->name, number->font_name)) + { + break; + } + } } - } -} -int ST_BlinkKey(player_t* player, int index) -{ - const keyblink_t keyblink = player->keyblinkkeys[index]; - - if (!keyblink) - return KEYBLINK_NONE; - - if (player->keyblinktics & KEYBLINKMASK) - { - if (keyblink == KEYBLINK_EITHER) - { - if (st_keyorskull[index] && st_keyorskull[index] != KEYBLINK_BOTH) - { - return st_keyorskull[index]; - } - else if ( (player->keyblinktics & (2*KEYBLINKMASK)) && - !(player->keyblinktics & (4*KEYBLINKMASK))) - { - return KEYBLINK_SKULL; - } - else - { - return KEYBLINK_CARD; - } + if (value < 0 && font->minus != NULL) + { + value = MAX(-max, value); + numvalues = (int)log10(-value) + 1; + valglyphs = numvalues + 1; } else { - return keyblink; + value = BETWEEN(0, max, value); + numvalues = valglyphs = value != 0 ? ((int)log10(value) + 1) : 1; } - } - - return -1; -} - -static int largeammo = LARGENUMBER; // means "n/a" -void ST_updateWidgets(void) -{ - int i; - - // must redirect the pointer if the ready weapon has changed. - // if (w_ready.data != plyr->readyweapon) - // { - if (weaponinfo[plyr->readyweapon].ammo == am_noammo) - w_ready.num = &largeammo; - else - w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo]; - //{ - // static int tic=0; - // static int dir=-1; - // if (!(tic&15)) - // plyr->ammo[weaponinfo[plyr->readyweapon].ammo]+=dir; - // if (plyr->ammo[weaponinfo[plyr->readyweapon].ammo] == -100) - // dir = 1; - // tic++; - // } - w_ready.data = plyr->readyweapon; - - // if (*w_ready.on) - // STlib_updateNum(&w_ready, true); - // refresh weapon change - // } - - // update keycard multiple widgets - for (i=0;i<3;i++) - { - keyboxes[i] = plyr->cards[i] ? i : -1; - - //jff 2/24/98 select double key - //killough 2/28/98: preserve traditional keys by config option - - if (plyr->cards[i+3]) - keyboxes[i] = keyboxes[i]==-1 || sts_traditional_keys ? i+3 : i+6; - } - - // [crispy] blinking key or skull in the status bar - if (plyr->keyblinktics) - { - if (!hud_blink_keys || - !(st_classicstatusbar || (hud_displayed && hud_active > 0))) - { - plyr->keyblinktics = 0; - } - else + if (elem->type == sbe_percent && font->percent != NULL) { - if (!(plyr->keyblinktics & (2*KEYBLINKMASK - 1))) - S_StartSoundPitch(NULL, sfx_itemup, PITCH_NONE); - - plyr->keyblinktics--; + ++valglyphs; + } - for (i = 0; i < 3; i++) - { - switch (ST_BlinkKey(plyr, i)) + int totalwidth = font->monowidth * valglyphs; + if (font->type == sbf_proportional) + { + totalwidth = 0; + if (value < 0 && font->minus != NULL) { - case KEYBLINK_NONE: - continue; - - case KEYBLINK_CARD: - keyboxes[i] = i; - break; - - case KEYBLINK_SKULL: - keyboxes[i] = i + 3; - break; - - case KEYBLINK_BOTH: - keyboxes[i] = i + 6; - break; - - default: - keyboxes[i] = -1; - break; + totalwidth += SHORT(font->minus->width); + } + int tempnum = value; + while (tempnum > 0) + { + int workingnum = tempnum % 10; + totalwidth = SHORT(font->numbers[workingnum]->width); + tempnum /= 10; + } + if (elem->type == sbe_percent && font->percent != NULL) + { + totalwidth += SHORT(font->percent->width); } - } } - } - // refresh everything if this is him coming back to life - ST_updateFaceWidget(); - - // used for armbg patch - st_notdeathmatch = !deathmatch; - - // used by w_arms[] widgets - st_armson = st_statusbaron && !deathmatch; - - // used by w_frags widget - st_fragson = deathmatch && st_statusbaron; - st_fragscount = 0; - - for (i=0 ; ixoffset = 0; + if (elem->alignment & sbe_h_middle) { - if (i != displayplayer) // killough 3/7/98 - st_fragscount += plyr->frags[i]; - else - st_fragscount -= plyr->frags[i]; + number->xoffset -= (totalwidth >> 1); + } + else if (elem->alignment & sbe_h_right) + { + number->xoffset -= totalwidth; } + number->font = font; + number->value = value; + number->numvalues = numvalues; } -// [Alaux] -static int SmoothCount(int shownval, int realval) -{ - int step = realval - shownval; - - if (!hud_animated_counts || !step) - { - return realval; - } - else - { - int sign = step / abs(step); - step = BETWEEN(1, 7, abs(step) / 20); - shownval += (step+1)*sign; - - if ( (sign > 0 && shownval > realval) - ||(sign < 0 && shownval < realval)) - { - shownval = realval; - } - - return shownval; - } -} - -boolean st_invul; -static void ST_doPaletteStuff(void); - -void ST_Ticker(void) -{ - st_health = SmoothCount(st_health, plyr->health); - st_armor = SmoothCount(st_armor, plyr->armorpoints); - - st_randomnumber = M_Random(); - ST_updateWidgets(); - st_oldhealth = plyr->health; - - st_invul = (plyr->powers[pw_invulnerability] > 4*32 || - plyr->powers[pw_invulnerability] & 8) || - plyr->cheats & CF_GODMODE; - - if (!nodrawers) - ST_doPaletteStuff(); // Do red-/gold-shifts from damage/items -} - -static int st_palette = 0; -boolean palette_changes = true; - -static void ST_doPaletteStuff(void) +static void UpdateLines(sbarelem_t *elem) { - int palette; - byte* pal; - int cnt = plyr->damagecount; - - // killough 7/14/98: beta version did not cause red berserk palette - if (!beta_emulation) - - if (plyr->powers[pw_strength]) - { - // slowly fade the berzerk out - int bzc = 12 - (plyr->powers[pw_strength]>>6); - if (bzc > cnt) - cnt = bzc; - } + sbe_widget_t *widget = elem->subtype.widget; - if (STRICTMODE(!palette_changes)) - { - palette = 0; - } - else - if (cnt) - { - // In Chex Quest, the player never sees red. Instead, the radiation suit - // palette is used to tint the screen green, as though the player is being - // covered in goo by an attacking flemoid. - if (gameversion == exe_chex) + hudfont_t *font = widget->font; + if (font == NULL) { - palette = RADIATIONPAL; + array_foreach(font, sbardef->hudfonts) + { + if (!strcmp(font->name, widget->font_name)) + { + break; + } + } } - else - { - palette = (cnt+7)>>3; - if (palette >= NUMREDPALS) - palette = NUMREDPALS-1; - // [crispy] tune down a bit so the menu remains legible - if (menuactive || paused) - palette >>= 1; - palette += STARTREDPALS; - } - } - else - if (plyr->bonuscount) - { - palette = (plyr->bonuscount+7)>>3; - if (palette >= NUMBONUSPALS) - palette = NUMBONUSPALS-1; - palette += STARTBONUSPALS; - } - else - // killough 7/14/98: beta version did not cause green palette - if (beta_emulation) - palette = 0; - else - if (plyr->powers[pw_ironfeet] > 4*32 || plyr->powers[pw_ironfeet] & 8) - palette = RADIATIONPAL; - else - palette = 0; - if (palette != st_palette) + widgetline_t *line; + array_foreach(line, widget->lines) { - st_palette = palette; - // haleyjd: must cast to byte *, arith. on void pointer is - // a GNU C extension - pal = (byte *)W_CacheLumpNum(lu_palette, PU_CACHE) + palette*768; - I_SetPalette (pal); - } -} - -void ST_drawWidgets(void) -{ - int i; - int maxammo = plyr->maxammo[weaponinfo[w_ready.data].ammo]; - - // [Alaux] Used to color health and armor counts based on - // the real values, only ever relevant when using smooth counts - const int health = plyr->health, armor = plyr->armorpoints; - - // clear area - if (!st_crispyhud && st_statusbaron) - { - V_CopyRect(video.deltaw, 0, st_backing_screen, ST_WIDTH, ST_HEIGHT, - video.deltaw, ST_Y); - } - - // used by w_arms[] widgets - st_armson = st_statusbaron && !deathmatch; - - // used by w_frags widget - st_fragson = deathmatch && st_statusbaron; - - // backpack changes thresholds - if (plyr->backpack && !hud_backpack_thresholds) - maxammo /= 2; - - //jff 2/16/98 make color of ammo depend on amount - if (*w_ready.num*100 < ammo_red*maxammo) - STlib_updateNum(&w_ready, cr_red); - else - if (*w_ready.num*100 < - ammo_yellow*maxammo) - STlib_updateNum(&w_ready, cr_gold); - else if (*w_ready.num > maxammo) - STlib_updateNum(&w_ready, cr_blue2); - else - STlib_updateNum(&w_ready, cr_green); - - for (i=0;i<4;i++) - { - STlib_updateNum(&w_ammo[i], NULL); //jff 2/16/98 no xlation - STlib_updateNum(&w_maxammo[i], NULL); - } - - // [Alaux] Make color of health gray when invulnerable - if (st_invul) - STlib_updatePercent(&w_health, cr_gray); - else - //jff 2/16/98 make color of health depend on amount - if (healtharmortype) - STlib_updatePercent(&w_armor, cr_red); - else if (plyr->armortype == 1) - STlib_updatePercent(&w_armor, cr_green); - else - STlib_updatePercent(&w_armor, cr_blue2); - } - else - { - if (st_invul) - STlib_updatePercent(&w_armor, cr_gray); - else - //jff 2/16/98 make color of armor depend on amount - if (armorstring; + while (*str) + { + int ch = *str++; + if (ch == '\x1b' && *str) + { + ++str; + continue; + } - ST_MoveHud(); + if (font->type == sbf_proportional) + { + ch = M_ToUpper(ch) - HU_FONTSTART; + if (ch < 0 || ch > HU_FONTSIZE) + { + totalwidth += SPACEWIDTH; + continue; + } + patch_t *patch = font->characters[ch]; + if (patch == NULL) + { + totalwidth += SPACEWIDTH; + continue; + } + totalwidth += SHORT(patch->width); + } + else + { + totalwidth += font->monowidth; + } + } - if (st_firsttime) // If just after ST_Start(), refresh all - { - st_firsttime = false; + line->xoffset = 0; + if (elem->alignment & sbe_h_middle) + { + line->xoffset -= (totalwidth >> 1); + } + else if (elem->alignment & sbe_h_right) + { + line->xoffset -= totalwidth; + } + line->totalwidth = totalwidth; + } - // draw status bar background to off-screen buff - ST_refreshBackground(); - } - - ST_drawWidgets(); + widget->font = font; } -void ST_loadGraphics(void) +static void UpdateAnimation(sbarelem_t *elem) { - int i, facenum; - char namebuf[32]; + sbe_animation_t *animation = elem->subtype.animation; - // Load the numbers, tall and short - for (i=0;i<10;i++) + if (animation->duration_left == 0) { - M_snprintf(namebuf, sizeof(namebuf), "STTNUM%d", i); - tallnum[i] = V_CachePatchName(namebuf, PU_STATIC); - M_snprintf(namebuf, sizeof(namebuf), "STYSNUM%d", i); - shortnum[i] = V_CachePatchName(namebuf, PU_STATIC); + ++animation->frame_index; + if (animation->frame_index == array_size(animation->frames)) + { + animation->frame_index = 0; + } + animation->duration_left = animation->frames[animation->frame_index].duration; } - // Load percent key. - //Note: why not load STMINUS here, too? - tallpercent = V_CachePatchName("STTPRCNT", PU_STATIC); + --animation->duration_left; +} - // key cards - for (i=0;icrboom = CR_NONE; + return; } - // arms background - armsbg = V_CachePatchName("STARMS", PU_STATIC); - - // arms ownership widgets - for (i=0;i<6;i++) - { - M_snprintf(namebuf, sizeof(namebuf), "STGNUM%d", i+2); + sbe_number_t *number = elem->subtype.number; - // gray # - arms[i][0] = V_CachePatchName(namebuf, PU_STATIC); + boolean invul = (player->powers[pw_invulnerability] + || player->cheats & CF_GODMODE); - // yellow # - arms[i][1] = shortnum[i+2]; - } + crange_idx_e cr; - // face backgrounds for different color players - // killough 3/7/98: add better support for spy mode by loading all - // player face backgrounds and using displayplayer to choose them: - for (i=0; itype) { - M_snprintf(namebuf, sizeof(namebuf), "STFB%d", i); - faceback[i] = V_CachePatchName(namebuf, PU_STATIC); - } - - // status bar background bits - if (W_CheckNumForName("STBAR") >= 0) - { - sbar = V_CachePatchName("STBAR", PU_STATIC); - sbarr = NULL; - } - else - { - sbar = V_CachePatchName("STMBARL", PU_STATIC); - sbarr = V_CachePatchName("STMBARR", PU_STATIC); - } + case sbn_health: + { + int health = player->health; + if (invul) + cr = CR_GRAY; + else if (health < health_red) + cr = CR_RED; + else if (health < health_yellow) + cr = CR_GOLD; + else if (health <= health_green) + cr = CR_GREEN; + else + cr = CR_BLUE2; + } + break; + case sbn_armor: + if (hud_armor_type) + { + if (invul) + cr = CR_GRAY; + else if (!player->armortype) + cr = CR_RED; + else if (player->armortype == 1) + cr = CR_GREEN; + else + cr = CR_BLUE2; + } + else + { + int armor = player->armorpoints; + if (invul) + cr = CR_GRAY; + else if (armor < armor_red) + cr = CR_RED; + else if (armor < armor_yellow) + cr = CR_GOLD; + else if (armor <= armor_green) + cr = CR_GREEN; + else + cr = CR_BLUE2; + } + break; + case sbn_ammoselected: + { + ammotype_t type = weaponinfo[player->readyweapon].ammo; + if (type == am_noammo) + { + return; + } + + int maxammo = player->maxammo[type]; + if (maxammo == 0) + { + return; + } - // face states - facenum = 0; - for (i=0;iammo[type]; + + // backpack changes thresholds + if (player->backpack) + { + maxammo /= 2; + } + + if (ammo * 100 < ammo_red * maxammo) + cr = CR_RED; + else if (ammo * 100 < ammo_yellow * maxammo) + cr = CR_GOLD; + else if (ammo > maxammo) + cr = CR_BLUE2; + else + cr = CR_GREEN; + } + break; + default: + cr = CR_NONE; + break; + } + + elem->crboom = cr; +} + +static void UpdateElem(sbarelem_t *elem, player_t *player) +{ + if (!CheckConditions(elem->conditions, player)) { - int j; - for (j=0;jtype) + { + case sbe_face: + UpdateFace(elem->subtype.face, player); + break; + + case sbe_animation: + UpdateAnimation(elem); + break; + + case sbe_number: + case sbe_percent: + UpdateBoomColors(elem, player); + UpdateNumber(elem, player); + break; + + case sbe_widget: + ST_UpdateWidget(elem, player); + UpdateLines(elem); + break; + + default: + break; + } + + sbarelem_t *child; + array_foreach(child, elem->children) + { + UpdateElem(child, player); + } +} + +static void UpdateStatusBar(player_t *player) +{ + int barindex = MAX(screenblocks - 10, 0); + + if (automapactive && automapoverlay == AM_OVERLAY_OFF) + { + barindex = 0; + } + + statusbar = &sbardef->statusbars[barindex]; + + sbarelem_t *child; + array_foreach(child, statusbar->children) + { + UpdateElem(child, player); + } +} + +static void ResetElem(sbarelem_t *elem) +{ + switch (elem->type) + { + case sbe_graphic: + { + sbe_graphic_t *graphic = elem->subtype.graphic; + graphic->patch = CachePatchName(graphic->patch_name); + } + break; + + case sbe_face: + { + sbe_face_t *face = elem->subtype.face; + face->faceindex = 0; + face->facecount = 0; + face->oldhealth = -1; + } + break; + + case sbe_animation: + { + sbe_animation_t *animation = elem->subtype.animation; + sbarframe_t *frame; + array_foreach(frame, animation->frames) + { + frame->patch = CachePatchName(frame->patch_name); + } + animation->frame_index = 0; + animation->duration_left = 0; + } + break; + + case sbe_number: + case sbe_percent: + elem->subtype.number->oldvalue = -1; + break; + + default: + break; + } + + sbarelem_t *child; + array_foreach(child, elem->children) + { + ResetElem(child); + } +} + +static void ResetStatusBar(void) +{ + statusbar_t *local_statusbar; + array_foreach(local_statusbar, sbardef->statusbars) + { + sbarelem_t *child; + array_foreach(child, local_statusbar->children) { - M_snprintf(namebuf, sizeof(namebuf), "STFST%d%d", i, j); - faces[facenum++] = V_CachePatchName(namebuf, PU_STATIC); + ResetElem(child); } - M_snprintf(namebuf, sizeof(namebuf), "STFTR%d0", i); // turn right - faces[facenum++] = V_CachePatchName(namebuf, PU_STATIC); - M_snprintf(namebuf, sizeof(namebuf), "STFTL%d0", i); // turn left - faces[facenum++] = V_CachePatchName(namebuf, PU_STATIC); - M_snprintf(namebuf, sizeof(namebuf), "STFOUCH%d", i); // ouch! - faces[facenum++] = V_CachePatchName(namebuf, PU_STATIC); - M_snprintf(namebuf, sizeof(namebuf), "STFEVL%d", i); // evil grin ;) - faces[facenum++] = V_CachePatchName(namebuf, PU_STATIC); - M_snprintf(namebuf, sizeof(namebuf), "STFKILL%d", i); // pissed off - faces[facenum++] = V_CachePatchName(namebuf, PU_STATIC); - } - faces[facenum++] = V_CachePatchName("STFGOD0", PU_STATIC); - faces[facenum++] = V_CachePatchName("STFDEAD0", PU_STATIC); - - // [FG] support face gib animations as in the 3DO/Jaguar/PSX ports - for (i = 0; i < ST_NUMXDTHFACES; i++) - { - M_snprintf(namebuf, sizeof(namebuf), "STFXDTH%d", i); - - if (W_CheckNumForName(namebuf) != -1) - faces[facenum++] = V_CachePatchName(namebuf, PU_STATIC); + } + + ST_ResetTitle(); +} + +static void DrawPatch(int x, int y, int maxheight, sbaralignment_t alignment, + patch_t *patch, crange_idx_e cr, byte *tl) +{ + if (!patch) + { + return; + } + + int width = SHORT(patch->width); + int height = maxheight ? maxheight : SHORT(patch->height); + + if (alignment & sbe_h_middle) + { + x -= (width >> 1); + } + else if (alignment & sbe_h_right) + { + x -= width; + } + + if (alignment & sbe_v_middle) + { + y -= (height >> 1); + } + else if (alignment & sbe_v_bottom) + { + y -= height; + } + + if (st_layout == st_wide) + { + if (alignment & sbe_wide_left) + { + x -= video.deltaw; + } + if (alignment & sbe_wide_right) + { + x += video.deltaw; + } + } + + byte *outr = colrngs[cr]; + + if (outr && tl) + { + V_DrawPatchTRTL(x, y, patch, outr, tl); + } + else if (tl) + { + V_DrawPatchTL(x, y, patch, tl); + } else - break; - } - have_xdthfaces = i; + { + V_DrawPatchTranslated(x, y, patch, outr); + } } -void ST_loadData(void) +static void DrawGlyphNumber(int x, int y, sbarelem_t *elem, patch_t *glyph) { - lu_palette = W_GetNumForName ("PLAYPAL"); - ST_loadGraphics(); + sbe_number_t *number = elem->subtype.number; + numberfont_t *font = number->font; + + int width, widthdiff; + + if (font->type == sbf_proportional) + { + width = glyph ? SHORT(glyph->width) : SPACEWIDTH; + widthdiff = 0; + } + else + { + width = font->monowidth; + widthdiff = glyph ? SHORT(glyph->width) - width : SPACEWIDTH - width; + } + + if (elem->alignment & sbe_h_middle) + { + number->xoffset += ((width + widthdiff) >> 1); + } + else if (elem->alignment & sbe_h_right) + { + number->xoffset += (width + widthdiff); + } + + if (glyph) + { + DrawPatch(x + number->xoffset, y, font->maxheight, elem->alignment, + glyph, elem->crboom == CR_NONE ? elem->cr : elem->crboom, + elem->tranmap); + } + + if (elem->alignment & sbe_h_middle) + { + number->xoffset += (width - ((width - widthdiff) >> 1)); + } + else if (elem->alignment & sbe_h_right) + { + number->xoffset += -widthdiff; + } + else + { + number->xoffset += width; + } } -void ST_initData(void) +static void DrawGlyphLine(int x, int y, sbarelem_t *elem, widgetline_t *line, + patch_t *glyph) { - int i; + sbe_widget_t *widget = elem->subtype.widget; + hudfont_t *font = widget->font; - st_firsttime = true; - plyr = &players[displayplayer]; // killough 3/7/98 + int width, widthdiff; - st_statusbaron = true; + if (font->type == sbf_proportional) + { + width = glyph ? SHORT(glyph->width) : SPACEWIDTH; + widthdiff = 0; + } + else + { + width = font->monowidth; + widthdiff = glyph ? SHORT(glyph->width) - width : 0; + } - st_faceindex = 0; - st_palette = -1; + if (elem->alignment & sbe_h_middle) + { + line->xoffset += ((width + widthdiff) >> 1); + } + else if (elem->alignment & sbe_h_right) + { + line->xoffset += (width + widthdiff); + } - st_oldhealth = -1; + if (glyph) + { + DrawPatch(x + line->xoffset, y, font->maxheight, elem->alignment, glyph, + elem->cr, elem->tranmap); + } - for (i=0;iweaponowned[i]; + if (elem->alignment & sbe_h_middle) + { + line->xoffset += (width - ((width - widthdiff) >> 1)); + } + else if (elem->alignment & sbe_h_right) + { + line->xoffset += -widthdiff; + } + else + { + line->xoffset += width; + } +} - for (i=0;i<3;i++) - keyboxes[i] = -1; +static void DrawNumber(int x, int y, sbarelem_t *elem) +{ + sbe_number_t *number = elem->subtype.number; + + int value = number->value; + int base_xoffset = number->xoffset; + numberfont_t *font = number->font; + + if (value < 0 && font->minus != NULL) + { + DrawGlyphNumber(x, y, elem, font->minus); + value = -value; + } - STlib_init(); + int glyphindex = number->numvalues; + while (glyphindex > 0) + { + int glyphbase = (int)pow(10.0, --glyphindex); + int workingnum = value / glyphbase; + DrawGlyphNumber(x, y, elem, font->numbers[workingnum]); + value -= (workingnum * glyphbase); + } + + if (elem->type == sbe_percent && font->percent != NULL) + { + crange_idx_e oldcr = elem->crboom; + if (sts_pct_always_gray) + { + elem->crboom = CR_GRAY; + } + DrawGlyphNumber(x, y, elem, font->percent); + elem->crboom = oldcr; + } + + number->xoffset = base_xoffset; } -static int distributed_delta = 0; +static void DrawLines(int x, int y, sbarelem_t *elem) +{ + sbe_widget_t *widget = elem->subtype.widget; + + int cr = elem->cr; + + widgetline_t *line; + array_foreach(line, widget->lines) + { + int base_xoffset = line->xoffset; + hudfont_t *font = widget->font; + + const char *str = line->string; + while (*str) + { + int ch = *str++; + + if (ch == '\x1b' && *str) + { + ch = *str++; + if (ch >= '0' && ch <= '0' + CR_NONE) + { + elem->cr = ch - '0'; + } + else if (ch == '0' + CR_ORIG) + { + elem->cr = cr; + } + continue; + } + + ch = M_ToUpper(ch) - HU_FONTSTART; + + patch_t *glyph; + if (ch < 0 || ch > HU_FONTSIZE) + { + glyph = NULL; + } + else + { + glyph = font->characters[ch]; + } + DrawGlyphLine(x, y, elem, line, glyph); + } + + if (elem->alignment & sbe_v_bottom) + { + y -= font->maxheight; + } + else + { + y += font->maxheight; + } + + line->xoffset = base_xoffset; + } +} -void ST_createWidgets(void) +static void DrawElem(int x, int y, sbarelem_t *elem, player_t *player) { - int i; - - // ready weapon ammo - STlib_initNum(&w_ready, - ST_AMMOX - distributed_delta, - ST_AMMOY, - tallnum, - weaponinfo[plyr->readyweapon].ammo != am_noammo ? - &plyr->ammo[weaponinfo[plyr->readyweapon].ammo] : - &largeammo, - &st_statusbaron, - ST_AMMOWIDTH ); - - // the last weapon type - w_ready.data = plyr->readyweapon; - - // health percentage - STlib_initPercent(&w_health, - ST_HEALTHX - distributed_delta, - ST_HEALTHY, - tallnum, - &st_health, - &st_statusbaron, - tallpercent); - - // weapons owned - for(i=0;i<6;i++) - { - STlib_initMultIcon(&w_arms[i], - ST_ARMSX+(i%3)*ST_ARMSXSPACE - distributed_delta, - ST_ARMSY+(i/3)*ST_ARMSYSPACE, - arms[i], (int *) &plyr->weaponowned[i+1], - &st_armson); - } - - // frags sum - STlib_initNum(&w_frags, - ST_FRAGSX - distributed_delta, - ST_FRAGSY, - tallnum, - &st_fragscount, - &st_fragson, - ST_FRAGSWIDTH); - - // faces - STlib_initMultIcon(&w_faces, - ST_FACESX, - ST_FACESY, - faces, - &st_faceindex, - &st_classicstatusbar); - - // armor percentage - should be colored later - STlib_initPercent(&w_armor, - ST_ARMORX + distributed_delta, - ST_ARMORY, - tallnum, - &st_armor, - &st_statusbaron, tallpercent); - - // keyboxes 0-2 - STlib_initMultIcon(&w_keyboxes[0], - ST_KEY0X + distributed_delta, - ST_KEY0Y, - keys, - &keyboxes[0], - &st_statusbaron); - - STlib_initMultIcon(&w_keyboxes[1], - ST_KEY1X + distributed_delta, - ST_KEY1Y, - keys, - &keyboxes[1], - &st_statusbaron); - - STlib_initMultIcon(&w_keyboxes[2], - ST_KEY2X + distributed_delta, - ST_KEY2Y, - keys, - &keyboxes[2], - &st_statusbaron); - - // ammo count (all four kinds) - STlib_initNum(&w_ammo[0], - ST_AMMO0X + distributed_delta, - ST_AMMO0Y, - shortnum, - &plyr->ammo[0], - &st_statusbaron, - ST_AMMO0WIDTH); - - STlib_initNum(&w_ammo[1], - ST_AMMO1X + distributed_delta, - ST_AMMO1Y, - shortnum, - &plyr->ammo[1], - &st_statusbaron, - ST_AMMO1WIDTH); - - STlib_initNum(&w_ammo[2], - ST_AMMO2X + distributed_delta, - ST_AMMO2Y, - shortnum, - &plyr->ammo[2], - &st_statusbaron, - ST_AMMO2WIDTH); - - STlib_initNum(&w_ammo[3], - ST_AMMO3X + distributed_delta, - ST_AMMO3Y, - shortnum, - &plyr->ammo[3], - &st_statusbaron, - ST_AMMO3WIDTH); - - // max ammo count (all four kinds) - STlib_initNum(&w_maxammo[0], - ST_MAXAMMO0X + distributed_delta, - ST_MAXAMMO0Y, - shortnum, - &plyr->maxammo[0], - &st_statusbaron, - ST_MAXAMMO0WIDTH); - - STlib_initNum(&w_maxammo[1], - ST_MAXAMMO1X + distributed_delta, - ST_MAXAMMO1Y, - shortnum, - &plyr->maxammo[1], - &st_statusbaron, - ST_MAXAMMO1WIDTH); - - STlib_initNum(&w_maxammo[2], - ST_MAXAMMO2X + distributed_delta, - ST_MAXAMMO2Y, - shortnum, - &plyr->maxammo[2], - &st_statusbaron, - ST_MAXAMMO2WIDTH); - - STlib_initNum(&w_maxammo[3], - ST_MAXAMMO3X + distributed_delta, - ST_MAXAMMO3Y, - shortnum, - &plyr->maxammo[3], - &st_statusbaron, - ST_MAXAMMO3WIDTH); + if (!CheckConditions(elem->conditions, player)) + { + return; + } + + x += elem->x_pos; + y += elem->y_pos; + + switch (elem->type) + { + case sbe_graphic: + { + sbe_graphic_t *graphic = elem->subtype.graphic; + DrawPatch(x, y, 0, elem->alignment, graphic->patch, elem->cr, + elem->tranmap); + } + break; + + case sbe_face: + { + sbe_face_t *face = elem->subtype.face; + DrawPatch(x, y, 0, elem->alignment, + facepatches[face->faceindex], elem->cr, + elem->tranmap); + } + break; + + case sbe_animation: + { + sbe_animation_t *animation = elem->subtype.animation; + patch_t *patch = + animation->frames[animation->frame_index].patch; + DrawPatch(x, y, 0, elem->alignment, patch, elem->cr, + elem->tranmap); + } + break; + + case sbe_number: + case sbe_percent: + DrawNumber(x, y, elem); + break; + + case sbe_widget: + DrawLines(x, y, elem); + break; + + default: + break; + } + + sbarelem_t *child; + array_foreach(child, elem->children) + { + DrawElem(x, y, child, player); + } } -static void ST_MoveHud (void) +static boolean st_solidbackground; + +static void DrawSolidBackground(void) { - static int odelta = 0; + // [FG] calculate average color of the 16px left and right of the status bar + const int vstep[][2] = { {0, 1}, {1, 2}, {2, ST_HEIGHT} }; - if (st_crispyhud && hud_active == 2) - distributed_delta = video.deltaw; - else - distributed_delta = 0; + patch_t *sbar = V_CachePatchName("STBAR", PU_CACHE); + // [FG] temporarily draw status bar to background buffer + V_DrawPatch(-video.deltaw, 0, sbar); + + byte *pal = W_CacheLumpName("PLAYPAL", PU_CACHE); + + const int width = MIN(SHORT(sbar->width), video.unscaledw); + const int depth = 16; + int v; - if (distributed_delta != odelta) + // [FG] separate colors for the top rows + for (v = 0; v < arrlen(vstep); v++) { - ST_createWidgets(); - odelta = distributed_delta; + int x, y; + const int v0 = vstep[v][0], v1 = vstep[v][1]; + unsigned r = 0, g = 0, b = 0; + byte col; + + for (y = v0; y < v1; y++) + { + for (x = 0; x < depth; x++) + { + byte *c = st_backing_screen + V_ScaleY(y) * video.pitch + + V_ScaleX(x); + r += pal[3 * c[0] + 0]; + g += pal[3 * c[0] + 1]; + b += pal[3 * c[0] + 2]; + + c += V_ScaleX(width - 2 * x - 1); + r += pal[3 * c[0] + 0]; + g += pal[3 * c[0] + 1]; + b += pal[3 * c[0] + 2]; + } + } + + r /= 2 * depth * (v1 - v0); + g /= 2 * depth * (v1 - v0); + b /= 2 * depth * (v1 - v0); + + // [FG] tune down to half saturation (for empiric reasons) + col = I_GetNearestColor(pal, r / 2, g / 2, b / 2); + + V_FillRect(0, v0, video.unscaledw, v1 - v0, col); } } -static boolean st_stopped = true; +boolean st_refresh_background = true; -void ST_Start(void) +static void DrawBackground(const char *name) { - if (!st_stopped) - ST_Stop(); - ST_initData(); - ST_createWidgets(); - st_stopped = false; + if (st_refresh_background) + { + V_UseBuffer(st_backing_screen); + + if (st_solidbackground) + { + DrawSolidBackground(); + } + else + { + if (!name) + { + name = (gamemode == commercial) ? "GRNROCK" : "FLOOR7_2"; + } + + byte *flat = + V_CacheFlatNum(firstflat + R_FlatNumForName(name), PU_CACHE); + + V_TileBlock64(ST_Y, video.unscaledw, ST_HEIGHT, flat); + + if (screenblocks == 10) + { + patch_t *patch = V_CachePatchName("brdr_b", PU_CACHE); + for (int x = 0; x < video.unscaledw; x += 8) + { + V_DrawPatch(x - video.deltaw, 0, patch); + } + } + } + + V_RestoreBuffer(); + + st_refresh_background = false; + } + + V_CopyRect(0, 0, st_backing_screen, video.unscaledw, ST_HEIGHT, 0, ST_Y); } -void ST_Stop(void) +static void DrawStatusBar(void) { - if (st_stopped) - return; - if (!nodrawers) - I_SetPalette (W_CacheLumpNum (lu_palette, PU_CACHE)); - st_stopped = true; + player_t *player = &players[displayplayer]; + + if (!statusbar->fullscreenrender) + { + DrawBackground(statusbar->fillflat); + } + + sbarelem_t *child; + array_foreach(child, statusbar->children) + { + DrawElem(0, SCREENHEIGHT - statusbar->height, child, player); + } } -static int StatusBarBufferHeight(void) +static void EraseElem(int x, int y, sbarelem_t *elem, player_t *player) { - int i; - int st_height = ST_HEIGHT; - patch_t *const patch = W_CacheLumpName("brdr_b", PU_CACHE); + if (!CheckConditions(elem->conditions, player)) + { + return; + } - if (patch && SHORT(patch->height) > st_height) - st_height = SHORT(patch->height); + x += elem->x_pos; + y += elem->y_pos; - if (sbar && SHORT(sbar->height) > st_height) - st_height = SHORT(sbar->height); + if (elem->type == sbe_widget) + { + sbe_widget_t *widget = elem->subtype.widget; + hudfont_t *font = widget->font; - if (armsbg && SHORT(armsbg->height) > st_height) - st_height = SHORT(armsbg->height); + int height = 0; + widgetline_t *line; + array_foreach(line, widget->lines) + { + if (elem->alignment & sbe_v_bottom) + { + y -= font->maxheight; + } + height += font->maxheight; + } - for (i = 0; i < MAXPLAYERS; i++) - { - if (faceback[i] && SHORT(faceback[i]->height) > st_height) - st_height = SHORT(faceback[i]->height); - } + if (y > scaledviewy && y < scaledviewy + scaledviewheight - height) + { + R_VideoErase(0, y, scaledviewx, height); + R_VideoErase(scaledviewx + scaledviewwidth, y, scaledviewx, height); + } + else + { + R_VideoErase(0, y, video.unscaledw, height); + } + } - return st_height; + sbarelem_t *child; + array_foreach(child, elem->children) + { + EraseElem(x, y, child, player); + } } -void ST_Init(void) +void ST_Erase(void) { - ST_loadData(); + if (!sbardef) + { + return; + } + + player_t *player = &players[displayplayer]; + + sbarelem_t *child; + array_foreach(child, statusbar->children) + { + EraseElem(0, SCREENHEIGHT - statusbar->height, child, player); + } } -void ST_InitRes(void) +// Respond to keyboard input events, +// intercept cheats. +boolean ST_Responder(event_t *ev) +{ + // Filter automap on/off. + if (ev->type == ev_keyup && (ev->data1.i & 0xffff0000) == AM_MSGHEADER) + { + return false; + } + else if (ST_MessagesResponder(ev)) + { + return true; + } + else // if a user keypress... + { + return M_CheatResponder(ev); // Try cheat responder in m_cheat.c + } +} + +static boolean hud_blink_keys; // [crispy] blinking key or skull in the status bar + +void ST_SetKeyBlink(player_t *player, int blue, int yellow, int red) { - int height = V_ScaleY(StatusBarBufferHeight()); + // Init array with args to iterate through + const int keys[3] = {blue, yellow, red}; + + player->keyblinktics = KEYBLINKTICS; - // killough 11/98: allocate enough for hires - st_backing_screen = Z_Malloc(video.pitch * height * sizeof(*st_backing_screen), PU_RENDERER, 0); + for (int i = 0; i < 3; i++) + { + if (((keys[i] == KEYBLINK_EITHER) && !(player->cards[i] || player->cards[i + 3])) + || ((keys[i] == KEYBLINK_CARD) && !(player->cards[i])) + || ((keys[i] == KEYBLINK_SKULL) && !(player->cards[i + 3])) + || ((keys[i] == KEYBLINK_BOTH) && !(player->cards[i] && player->cards[i + 3]))) + { + player->keyblinkkeys[i] = keys[i]; + } + else + { + player->keyblinkkeys[i] = KEYBLINK_NONE; + } + } } -void ST_Warnings(void) +boolean palette_changes = true; + +static void DoPaletteStuff(player_t *player) { - int i; - patch_t *const patch = V_CachePatchName("brdr_b", PU_CACHE); - - if (patch && SHORT(patch->height) > ST_HEIGHT) - { - I_Printf(VB_WARNING, "ST_Init: Non-standard BRDR_B height of %d. " - "Expected <= %d.", SHORT(patch->height), ST_HEIGHT); - } - - if (sbar && SHORT(sbar->height) != ST_HEIGHT) - { - I_Printf(VB_WARNING, "ST_Init: Non-standard STBAR height of %d. " - "Expected %d.", SHORT(sbar->height), ST_HEIGHT); - } - - if (armsbg && SHORT(armsbg->height) > ST_HEIGHT) - { - I_Printf(VB_WARNING, "ST_Init: Non-standard STARMS height of %d. " - "Expected <= %d.", SHORT(armsbg->height), ST_HEIGHT); - } - - for (i = 0; i < MAXPLAYERS; i++) - { - if (faceback[i] && SHORT(faceback[i]->height) > ST_HEIGHT) - { - I_Printf(VB_WARNING, "ST_Init: Non-standard STFB%d height of %d. " - "Expected <= %d.", i, SHORT(faceback[i]->height), ST_HEIGHT); - } - } + static int oldpalette = 0; + int palette; + + int damagecount = player->damagecount; + + // killough 7/14/98: beta version did not cause red berserk palette + if (!beta_emulation) + { + + if (player->powers[pw_strength]) + { + // slowly fade the berzerk out + int berzerkcount = 12 - (player->powers[pw_strength] >> 6); + if (berzerkcount > damagecount) + { + damagecount = berzerkcount; + } + } + } + + if (STRICTMODE(!palette_changes)) + { + palette = 0; + } + else if (damagecount) + { + // In Chex Quest, the player never sees red. Instead, the radiation suit + // palette is used to tint the screen green, as though the player is + // being covered in goo by an attacking flemoid. + if (gameversion == exe_chex) + { + palette = RADIATIONPAL; + } + else + { + palette = (damagecount + 7) >> 3; + if (palette >= NUMREDPALS) + { + palette = NUMREDPALS - 1; + } + // [crispy] tune down a bit so the menu remains legible + if (menuactive || paused) + { + palette >>= 1; + } + palette += STARTREDPALS; + } + } + else if (player->bonuscount) + { + palette = (player->bonuscount + 7) >> 3; + if (palette >= NUMBONUSPALS) + { + palette = NUMBONUSPALS - 1; + } + palette += STARTBONUSPALS; + } + // killough 7/14/98: beta version did not cause green palette + else if (beta_emulation) + { + palette = 0; + } + else if (player->powers[pw_ironfeet] > 4 * 32 + || player->powers[pw_ironfeet] & 8) + { + palette = RADIATIONPAL; + } + else + { + palette = 0; + } + + if (palette != oldpalette) + { + oldpalette = palette; + // haleyjd: must cast to byte *, arith. on void pointer is + // a GNU C extension + I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE) + + palette * 768); + } +} + +void ST_Ticker(void) +{ + if (!sbardef) + { + return; + } + + // check for incoming chat characters + if (netgame) + { + ST_UpdateChatMessage(); + } + + player_t *player = &players[displayplayer]; + + UpdateStatusBar(player); + + if (hud_crosshair) + { + HU_UpdateCrosshair(); + } + + if (!nodrawers) + { + DoPaletteStuff(player); // Do red-/gold-shifts from damage/items + } +} + +void ST_Drawer(void) +{ + if (!sbardef) + { + return; + } + + DrawStatusBar(); + + if (hud_crosshair) + { + HU_DrawCrosshair(); + } +} + +void ST_Start(void) +{ + if (!sbardef) + { + return; + } + + ResetStatusBar(); + + HU_StartCrosshair(); +} + +patch_t **hu_font = NULL; + +void ST_Init(void) +{ + sbardef = ST_ParseSbarDef(); + + if (!sbardef) + { + return; + } + + LoadFacePatches(); + + hudfont_t *hudfont; + array_foreach(hudfont, sbardef->hudfonts) + { + if (!strcmp(hudfont->name, "Console")) + { + hu_font = hudfont->characters; + break; + } + } + + if (!hu_font) + { + I_Error("ST_Init: \"Console\" font not found"); + } + + HU_InitCrosshair(); + HU_InitCommandHistory(); + HU_InitObituaries(); + + ST_InitWidgets(); +} + +void ST_InitRes(void) +{ + // killough 11/98: allocate enough for hires + st_backing_screen = + Z_Malloc(video.pitch * V_ScaleY(ST_HEIGHT) * sizeof(*st_backing_screen), + PU_RENDERER, 0); } void ST_ResetPalette(void) { - st_palette = -1; - I_SetPalette(W_CacheLumpNum(lu_palette, PU_CACHE)); + I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); +} + +// [FG] draw Time widget on intermission screen +void WI_DrawWidgets(void) +{ + if (!st_time_elem || !(hud_level_time & HUD_WIDGET_HUD)) + { + return; + } + + sbarelem_t time = *st_time_elem; + time.alignment = sbe_wide_left; + // leveltime is already added to totalleveltimes before WI_Start() + DrawLines(0, 0, &time); } void ST_BindSTSVariables(void) { + M_BindNum("st_layout", &st_layout, NULL, st_wide, st_original, st_wide, + ss_stat, wad_no, "HUD layout"); M_BindBool("sts_colored_numbers", &sts_colored_numbers, NULL, false, ss_stat, wad_yes, "Colored numbers on the status bar"); M_BindBool("sts_pct_always_gray", &sts_pct_always_gray, NULL, false, ss_stat, wad_yes, "Percent signs on the status bar are always gray"); - M_BindBool("sts_traditional_keys", &sts_traditional_keys, NULL, - false, ss_stat, wad_yes, - "Show last picked-up key on each key slot on the status bar"); M_BindBool("hud_blink_keys", &hud_blink_keys, NULL, false, ss_stat, wad_no, "Make missing keys blink when trying to trigger linedef actions"); @@ -1488,6 +1833,8 @@ void ST_BindSTSVariables(void) "Use solid-color borders for the status bar in widescreen mode"); M_BindBool("hud_animated_counts", &hud_animated_counts, NULL, false, ss_stat, wad_no, "Animated health/armor counts"); + M_BindBool("hud_armor_type", &hud_armor_type, NULL, false, ss_stat, wad_no, + "Armor count is colored based on armor type"); M_BindNum("health_red", &health_red, NULL, 25, 0, 200, ss_none, wad_yes, "Amount of health for red-to-yellow transition"); M_BindNum("health_yellow", &health_yellow, NULL, 50, 0, 200, ss_none, wad_yes, @@ -1504,6 +1851,22 @@ void ST_BindSTSVariables(void) "Percent of ammo for red-to-yellow transition"); M_BindNum("ammo_yellow", &ammo_yellow, NULL, 50, 0, 100, ss_none, wad_yes, "Percent of ammo for yellow-to-green transition"); + + M_BindNum("hud_crosshair", &hud_crosshair, NULL, 0, 0, 10 - 1, ss_stat, wad_no, + "Crosshair"); + M_BindBool("hud_crosshair_health", &hud_crosshair_health, NULL, + false, ss_stat, wad_no, "Change crosshair color based on player health"); + M_BindNum("hud_crosshair_target", &hud_crosshair_target, NULL, + 0, 0, 2, ss_stat, wad_no, + "Change crosshair color when locking on target (1 = Highlight; 2 = Health)"); + M_BindBool("hud_crosshair_lockon", &hud_crosshair_lockon, NULL, + false, ss_stat, wad_no, "Lock crosshair on target"); + M_BindNum("hud_crosshair_color", &hud_crosshair_color, NULL, + CR_GRAY, CR_BRICK, CR_NONE, ss_stat, wad_no, + "Default crosshair color"); + M_BindNum("hud_crosshair_target_color", &hud_crosshair_target_color, NULL, + CR_YELLOW, CR_BRICK, CR_NONE, ss_stat, wad_no, + "Crosshair color when aiming at target"); } //---------------------------------------------------------------------------- diff --git a/src/st_stuff.h b/src/st_stuff.h index 807a9039d..1c7db6ae0 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -27,6 +27,7 @@ struct event_s; struct player_s; +struct patch_s; // Size of statusbar. // Now sensitive for scaling. @@ -46,49 +47,36 @@ boolean ST_Responder(struct event_s *ev); void ST_Ticker(void); // Called by main loop. -void ST_Drawer(boolean fullscreen, boolean refresh); +void ST_Drawer(void); + +void ST_Erase(void); // Called when the console player is spawned on each level. void ST_Start(void); // Called by startup code. void ST_Init(void); -void ST_Warnings(void); void ST_ResetPalette(void); -// [crispy] forcefully initialize the status bar backing screen -void ST_refreshBackground(void); +extern boolean st_refresh_background; void ST_InitRes(void); -// killough 5/2/98: moved from m_misc.c: - -// [Alaux] -extern int st_health; -extern int st_armor; - extern int health_red; // health amount less than which status is red extern int health_yellow; // health amount less than which status is yellow extern int health_green; // health amount above is blue, below is green -extern int armor_red; // armor amount less than which status is red -extern int armor_yellow; // armor amount less than which status is yellow -extern int armor_green; // armor amount above is blue, below is green -extern int ammo_red; // ammo percent less than which status is red -extern int ammo_yellow; // ammo percent less is yellow more green #define KEYBLINKMASK 0x8 -#define KEYBLINKTICS (7*KEYBLINKMASK) +#define KEYBLINKTICS (7 * KEYBLINKMASK) extern void ST_SetKeyBlink(struct player_s *player, int blue, int yellow, int red); -extern int ST_BlinkKey(struct player_s *player, int index); extern int st_keyorskull[3]; -extern boolean hud_backpack_thresholds; // backpack changes thresholds -extern boolean hud_armor_type; // color of armor depends on type - extern boolean palette_changes; -extern boolean st_invul; +extern struct patch_s **hu_font; + +void WI_DrawWidgets(void); void ST_BindSTSVariables(void); diff --git a/src/st_widgets.c b/src/st_widgets.c new file mode 100644 index 000000000..83bbe4cf0 --- /dev/null +++ b/src/st_widgets.c @@ -0,0 +1,1055 @@ +// +// Copyright(C) 2024 Roman Fomin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#include "st_widgets.h" + +#include +#include + +#include "dstrings.h" +#include "d_event.h" +#include "d_deh.h" +#include "d_player.h" +#include "doomdef.h" +#include "doomkeys.h" +#include "doomstat.h" +#include "doomtype.h" +#include "hu_command.h" +#include "hu_coordinates.h" +#include "hu_obituary.h" +#include "i_video.h" +#include "m_array.h" +#include "m_config.h" +#include "m_input.h" +#include "m_misc.h" +#include "p_mobj.h" +#include "r_main.h" +#include "r_voxel.h" +#include "s_sound.h" +#include "sounds.h" +#include "st_sbardef.h" +#include "i_timer.h" +#include "v_video.h" +#include "u_mapinfo.h" + +boolean show_messages; +boolean show_toggle_messages; +boolean show_pickup_messages; + +boolean hud_secret_message; // "A secret is revealed!" message +widgetstate_t hud_level_stats; +widgetstate_t hud_level_time; +boolean hud_time_use; +widgetstate_t hud_player_coords; + +static boolean hud_map_announce; +static boolean message_colorized; + +//jff 2/16/98 hud supported automap colors added +int hudcolor_titl; // color range of automap level title +int hudcolor_xyco; // color range of new coords on automap + +boolean chat_on; + +void ST_ClearLines(sbe_widget_t *widget) +{ + array_clear(widget->lines); +} + +void ST_AddLine(sbe_widget_t *widget, const char *string) +{ + widgetline_t line = { .string = string }; + array_push(widget->lines, line); +} + +static void SetLine(sbe_widget_t *widget, const char *string) +{ + array_clear(widget->lines); + widgetline_t line = { .string = string }; + array_push(widget->lines, line); +} + +static char message_string[HU_MAXLINELENGTH]; + +static boolean message_review; + +static void UpdateMessage(sbe_widget_t *widget, player_t *player) +{ + if (!player->message) + { + ST_ClearLines(widget); + return; + } + + static char string[120]; + static int duration_left; + static boolean overwrite = true; + static boolean messages_enabled = true; + + if (messages_enabled) + { + if (message_string[0]) + { + duration_left = widget->duration; + M_StringCopy(string, message_string, sizeof(string)); + message_string[0] = '\0'; + overwrite = false; + } + else if (player->message && player->message[0] && overwrite) + { + duration_left = widget->duration; + M_StringCopy(string, player->message, sizeof(string)); + player->message[0] = '\0'; + } + else if (message_review) + { + message_review = false; + duration_left = widget->duration; + } + } + + if (messages_enabled != show_messages) + { + messages_enabled = show_messages; + } + + if (duration_left == 0) + { + ST_ClearLines(widget); + overwrite = true; + } + else + { + SetLine(widget, string); + --duration_left; + } +} + +static void UpdateSecretMessage(sbe_widget_t *widget, player_t *player) +{ + ST_ClearLines(widget); + + if (!hud_secret_message) + { + return; + } + + static char string[80]; + static int duration_left; + + if (player->secretmessage) + { + duration_left = widget->duration; + M_StringCopy(string, player->secretmessage, sizeof(string)); + player->secretmessage = NULL; + } + + if (duration_left > 0) + { + ST_AddLine(widget, string); + --duration_left; + } +} + +// key tables +// jff 5/10/98 french support removed, +// as it was not being used and couldn't be easily tested +// + +static const char shiftxform[] = +{ + 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, + ' ', '!', '"', '#', '$', '%', '&', + '"', // shift-' + '(', ')', '*', '+', + '<', // shift-, + '_', // shift-- + '>', // shift-. + '?', // shift-/ + ')', // shift-0 + '!', // shift-1 + '@', // shift-2 + '#', // shift-3 + '$', // shift-4 + '%', // shift-5 + '^', // shift-6 + '&', // shift-7 + '*', // shift-8 + '(', // shift-9 + ':', + ':', // shift-; + '<', + '+', // shift-= + '>', '?', '@', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '[', // shift-[ + '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK + ']', // shift-] + '"', '_', + '\'', // shift-` + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '{', '|', '}', '~', 127 +}; + +typedef struct +{ + char string[HU_MAXLINELENGTH]; + int pos; +} chatline_t; + +static chatline_t lines[MAXPLAYERS]; + +static void ClearChatLine(chatline_t *line) +{ + line->pos = 0; + line->string[0] = '\0'; +} + +static boolean AddKeyToChatLine(chatline_t *line, char ch) +{ + if (ch >= ' ' && ch <= '_') + { + if (line->pos == HU_MAXLINELENGTH - 1) + { + return false; + } + line->string[line->pos++] = ch; + line->string[line->pos] = '\0'; + } + else if (ch == KEY_BACKSPACE) // phares + { + if (line->pos == 0) + { + return false; + } + else + { + line->string[--line->pos] = '\0'; + } + } + else if (ch != KEY_ENTER) // phares + { + return false; // did not eat key + } + + return true; // ate the key +} + +#define HU_BROADCAST 5 + +char **player_names[] = +{ + &s_HUSTR_PLRGREEN, + &s_HUSTR_PLRINDIGO, + &s_HUSTR_PLRBROWN, + &s_HUSTR_PLRRED +}; + +void ST_UpdateChatMessage(void) +{ + static char chat_dest[MAXPLAYERS]; + + for (int p = 0; p < MAXPLAYERS; p++) + { + if (!playeringame[p]) + { + continue; + } + + char ch = players[p].cmd.chatchar; + if (p != consoleplayer && ch) + { + if (ch <= HU_BROADCAST) + { + chat_dest[p] = ch; + } + else + { + if (ch >= 'a' && ch <= 'z') + { + ch = (char)shiftxform[(unsigned char)ch]; + } + + if (AddKeyToChatLine(&lines[p], ch) && ch == KEY_ENTER) + { + if (lines[p].pos && (chat_dest[p] == consoleplayer + 1 + || chat_dest[p] == HU_BROADCAST)) + { + M_snprintf(message_string, sizeof(message_string), + "%s%s", *player_names[p], lines[p].string); + + S_StartSoundPitch(0, + gamemode == commercial ? sfx_radio + : sfx_tink, + PITCH_NONE); + } + ClearChatLine(&lines[p]); + } + } + players[p].cmd.chatchar = 0; + } + } +} + +static const char *chat_macros[] = { + HUSTR_CHATMACRO0, HUSTR_CHATMACRO1, HUSTR_CHATMACRO2, HUSTR_CHATMACRO3, + HUSTR_CHATMACRO4, HUSTR_CHATMACRO5, HUSTR_CHATMACRO6, HUSTR_CHATMACRO7, + HUSTR_CHATMACRO8, HUSTR_CHATMACRO9 +}; + +#define QUEUESIZE 128 + +static char chatchars[QUEUESIZE]; +static int head = 0; +static int tail = 0; + +// +// QueueChatChar() +// +// Add an incoming character to the circular chat queue +// +// Passed the character to queue, returns nothing +// + +static void QueueChatChar(char ch) +{ + if (((head + 1) & (QUEUESIZE - 1)) == tail) + { + displaymsg("%s", HUSTR_MSGU); + } + else + { + chatchars[head++] = ch; + head &= QUEUESIZE - 1; + } +} + +// +// ST_DequeueChatChar() +// +// Remove the earliest added character from the circular chat queue +// +// Passed nothing, returns the character dequeued +// + +char ST_DequeueChatChar(void) +{ + char ch; + + if (head != tail) + { + ch = chatchars[tail++]; + tail &= QUEUESIZE - 1; + } + else + { + ch = 0; + } + + return ch; +} + +static chatline_t chatline; + +boolean ST_MessagesResponder(event_t *ev) +{ + static char lastmessage[HU_MAXLINELENGTH + 1]; + + boolean eatkey = false; + static boolean shiftdown = false; + static boolean altdown = false; + int ch; + int numplayers; + + static int num_nobrainers = 0; + + ch = (ev->type == ev_keydown) ? ev->data1.i : 0; + + numplayers = 0; + for (int p = 0; p < MAXPLAYERS; p++) + { + numplayers += playeringame[p]; + } + + if (ev->data1.i == KEY_RSHIFT) + { + shiftdown = ev->type == ev_keydown; + return false; + } + + if (ev->data1.i == KEY_RALT) + { + altdown = ev->type == ev_keydown; + return false; + } + + if (M_InputActivated(input_chat_backspace)) + { + ch = KEY_BACKSPACE; + } + + if (!chat_on) + { + if (M_InputActivated(input_chat_enter)) // phares + { + //jff 2/26/98 toggle list of messages + message_review = true; + eatkey = true; + } + else if (demoplayback) // killough 10/02/98: no chat if demo playback + { + eatkey = false; + } + else if (netgame && M_InputActivated(input_chat)) + { + eatkey = chat_on = true; + ClearChatLine(&chatline); + QueueChatChar(HU_BROADCAST); + } + else if (netgame && numplayers > 2) // killough 11/98: simplify + { + for (int p = 0; p < MAXPLAYERS; p++) + { + if (M_InputActivated(input_chat_dest0 + p)) + { + if (p == consoleplayer) + { + displaymsg("%s", + ++num_nobrainers < 3 ? HUSTR_TALKTOSELF1 + : num_nobrainers < 6 ? HUSTR_TALKTOSELF2 + : num_nobrainers < 9 ? HUSTR_TALKTOSELF3 + : num_nobrainers < 32 + ? HUSTR_TALKTOSELF4 + : HUSTR_TALKTOSELF5); + } + else if (playeringame[p]) + { + eatkey = chat_on = true; + ClearChatLine(&chatline); + QueueChatChar((char)(p + 1)); + break; + } + } + } + } + } // jff 2/26/98 no chat functions if message review is displayed + else + { + if (M_InputActivated(input_chat_enter)) + { + ch = KEY_ENTER; + } + + // send a macro + if (altdown) + { + ch = ch - '0'; + if (ch < 0 || ch > 9) + { + return false; + } + const char *macromessage = chat_macros[ch]; + + // kill last message with a '\n' + QueueChatChar(KEY_ENTER); // DEBUG!!! // phares + + // send the macro message + while (*macromessage) + { + QueueChatChar(*macromessage++); + } + QueueChatChar(KEY_ENTER); // phares + + // leave chat mode and notify that it was sent + chat_on = false; + M_StringCopy(lastmessage, chat_macros[ch], sizeof(lastmessage)); + displaymsg("%s", lastmessage); + eatkey = true; + } + else + { + if (shiftdown || (ch >= 'a' && ch <= 'z')) + { + ch = shiftxform[ch]; + } + eatkey = AddKeyToChatLine(&chatline, ch); + if (eatkey) + { + QueueChatChar(ch); + } + + if (ch == KEY_ENTER) // phares + { + chat_on = false; + if (chatline.pos) + { + M_StringCopy(lastmessage, chatline.string, + sizeof(lastmessage)); + displaymsg("%s", lastmessage); + } + } + else if (ch == KEY_ESCAPE) // phares + { + chat_on = false; + } + } + } + return eatkey; +} + +static void UpdateChat(sbe_widget_t *widget) +{ + static char string[HU_MAXLINELENGTH + 1]; + + string[0] = '\0'; + + if (chat_on) + { + M_StringCopy(string, chatline.string, sizeof(string)); + + if (leveltime & 16) + { + M_StringConcat(string, "_", sizeof(string)); + } + } + + SetLine(widget, string); +} + +static boolean IsVanillaMap(int e, int m) +{ + if (gamemode == commercial) + { + return (e == 1 && m > 0 && m <= 32); + } + else + { + return (e > 0 && e <= 4 && m > 0 && m <= 9); + } +} + +#define HU_TITLE (*mapnames[(gameepisode - 1) * 9 + gamemap - 1]) +#define HU_TITLE2 (*mapnames2[gamemap - 1]) +#define HU_TITLEP (*mapnamesp[gamemap - 1]) +#define HU_TITLET (*mapnamest[gamemap - 1]) + +static char title_string[HU_MAXLINELENGTH]; + +void ST_ResetTitle(void) +{ + title_string[0] = '\0'; + + char *s; + + if (gamemapinfo && gamemapinfo->levelname) + { + if (gamemapinfo->label) + { + s = gamemapinfo->label; + } + else + { + s = gamemapinfo->mapname; + } + + if (s == gamemapinfo->mapname || U_CheckField(s)) + { + M_snprintf(title_string, sizeof(title_string), "%s: ", s); + } + s = gamemapinfo->levelname; + } + else if (gamestate == GS_LEVEL) + { + if (IsVanillaMap(gameepisode, gamemap)) + { + s = (gamemode != commercial) ? HU_TITLE + : (gamemission == pack_tnt) ? HU_TITLET + : (gamemission == pack_plut) ? HU_TITLEP + : HU_TITLE2; + } + // WADs like pl2.wad have a MAP33, and rely on the layout in the + // Vanilla executable, where it is possible to overflow the end of one + // array into the next. + else if (gamemode == commercial && gamemap >= 33 && gamemap <= 35) + { + s = (gamemission == doom2) ? (*mapnamesp[gamemap - 33]) + : (gamemission == pack_plut) ? (*mapnamest[gamemap - 33]) + : ""; + } + else + { + // initialize the map title widget with the generic map lump name + s = MapName(gameepisode, gamemap); + } + } + else + { + s = ""; + } + + char *n; + + // [FG] cap at line break + if ((n = strchr(s, '\n'))) + { + *n = '\0'; + } + + M_StringConcat(title_string, s, sizeof(title_string)); + + if (hud_map_announce && leveltime == 0) + { + displaymsg("%s", title_string); + } +} + +static void UpdateTitle(sbe_widget_t *widget) +{ + SetLine(widget, title_string); +} + +static boolean WidgetEnabled(widgetstate_t state) +{ + if (automapactive && !(state & HUD_WIDGET_AUTOMAP)) + { + return false; + } + else if (!automapactive && !(state & HUD_WIDGET_HUD)) + { + return false; + } + return true; +} + +static void UpdateCoord(sbe_widget_t *widget, player_t *player) +{ + if (hud_player_coords == HUD_WIDGET_ADVANCED) + { + HU_BuildCoordinatesEx(widget, player->mo); + return; + } + + ST_ClearLines(widget); + + if (!WidgetEnabled(hud_player_coords)) + { + return; + } + + fixed_t x, y, z; // killough 10/98: + void AM_Coordinates(const mobj_t *, fixed_t *, fixed_t *, fixed_t *); + + // killough 10/98: allow coordinates to display non-following pointer + AM_Coordinates(player->mo, &x, &y, &z); + + static char string[80]; + + // jff 2/16/98 output new coord display + M_snprintf(string, sizeof(string), + "\x1b%cX " GRAY_S "%d \x1b%cY " GRAY_S "%d \x1b%cZ " GRAY_S "%d", + '0' + hudcolor_xyco, x >> FRACBITS, '0' + hudcolor_xyco, + y >> FRACBITS, '0' + hudcolor_xyco, z >> FRACBITS); + + ST_AddLine(widget, string); +} + +static void UpdateMonSec(sbe_widget_t *widget) +{ + ST_ClearLines(widget); + + if (!WidgetEnabled(hud_level_stats)) + { + return; + } + + static char string[120]; + + int fullkillcount = 0; + int fullitemcount = 0; + int fullsecretcount = 0; + int kill_percent_count = 0; + + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + fullkillcount += players[i].killcount - players[i].maxkilldiscount; + fullitemcount += players[i].itemcount; + fullsecretcount += players[i].secretcount; + kill_percent_count += players[i].killcount; + } + } + + if (respawnmonsters) + { + fullkillcount = kill_percent_count; + max_kill_requirement = totalkills; + } + + int killcolor = (fullkillcount >= max_kill_requirement) ? '0' + CR_BLUE1 + : '0' + CR_GRAY; + int secretcolor = + (fullsecretcount >= totalsecret) ? '0' + CR_BLUE1 : '0' + CR_GRAY; + int itemcolor = + (fullitemcount >= totalitems) ? '0' + CR_BLUE1 : '0' + CR_GRAY; + + M_snprintf(string, sizeof(string), + RED_S "K \x1b%c%d/%d " RED_S "I \x1b%c%d/%d " RED_S "S \x1b%c%d/%d", + killcolor, fullkillcount, max_kill_requirement, + itemcolor, fullitemcount, totalitems, + secretcolor, fullsecretcount, totalsecret); + + ST_AddLine(widget, string); +} + +static void UpdateStTime(sbe_widget_t *widget, player_t *player) +{ + ST_ClearLines(widget); + + if (!WidgetEnabled(hud_level_time)) + { + return; + } + + static char string[80]; + + int offset = 0; + + if (time_scale != 100) + { + offset += + M_snprintf(string, sizeof(string), BLUE_S "%d%% ", time_scale); + } + + if (totalleveltimes) + { + const int time = (totalleveltimes + leveltime) / TICRATE; + + offset += M_snprintf(string + offset, sizeof(string) - offset, + GREEN_S "%d:%02d ", time / 60, time % 60); + } + + if (!player->btuse_tics) + { + M_snprintf(string + offset, sizeof(string) - offset, + GRAY_S "%d:%05.2f\t", leveltime / TICRATE / 60, + (float)(leveltime % (60 * TICRATE)) / TICRATE); + } + else + { + M_snprintf(string + offset, sizeof(string) - offset, + GOLD_S "U %d:%05.2f\t", player->btuse / TICRATE / 60, + (float)(player->btuse % (60 * TICRATE)) / TICRATE); + } + + ST_AddLine(widget, string); +} + +static void UpdateFPS(sbe_widget_t *widget, player_t *player) +{ + ST_ClearLines(widget); + + if (!(player->cheats & CF_SHOWFPS)) + { + return; + } + + static char string[20]; + M_snprintf(string, sizeof(string), GRAY_S "%d " GREEN_S "FPS", fps); + ST_AddLine(widget, string); +} + +static void UpdateRate(sbe_widget_t *widget, player_t *player) +{ + ST_ClearLines(widget); + + if (!(player->cheats & CF_RENDERSTATS)) + { + return; + } + + static char line1[80]; + M_snprintf(line1, sizeof(line1), + GRAY_S "Sprites %4d Segs %4d Visplanes %4d " GREEN_S + "FPS %3d %dx%d", + rendered_vissprites, rendered_segs, rendered_visplanes, + fps, video.width, video.height); + ST_AddLine(widget, line1); + + if (voxels_rendering) + { + static char line2[60]; + M_snprintf(line2, sizeof(line2), GRAY_S " Voxels %4d", + rendered_voxels); + ST_AddLine(widget, line2); + } +} + +int speedometer; + +static void UpdateSpeed(sbe_widget_t *widget, player_t *player) +{ + if (speedometer <= 0) + { + SetLine(widget, ""); + return; + } + + static const double factor[] = {TICRATE, 2.4003, 525.0 / 352.0}; + static const char *units[] = {"ups", "km/h", "mph"}; + const int type = speedometer - 1; + const mobj_t *mo = player->mo; + const double dx = FIXED2DOUBLE(mo->x - mo->oldx); + const double dy = FIXED2DOUBLE(mo->y - mo->oldy); + const double dz = FIXED2DOUBLE(mo->z - mo->oldz); + const double speed = sqrt(dx * dx + dy * dy + dz * dz) * factor[type]; + + static char string[60]; + M_snprintf(string, sizeof(string), GRAY_S "%.*f " GREEN_S "%s", + type && speed ? 1 : 0, speed, units[type]); + SetLine(widget, string); +} + +static void UpdateCmd(sbe_widget_t *widget) +{ + HU_BuildCommandHistory(widget); +} + +// [crispy] print a bar indicating demo progress at the bottom of the screen +boolean ST_DemoProgressBar(boolean force) +{ + const int progress = video.unscaledw * playback_tic / playback_totaltics; + static int old_progress = 0; + + if (old_progress < progress) + { + old_progress = progress; + } + else if (!force) + { + return false; + } + + V_FillRect(0, SCREENHEIGHT - 2, progress, 1, v_darkest_color); + V_FillRect(0, SCREENHEIGHT - 1, progress, 1, v_lightest_color); + + return true; +} + +struct +{ + char **str; + const int cr; + const char *col; +} static const colorize_strings[] = { + // [Woof!] colorize keycard and skull key messages + {&s_GOTBLUECARD, CR_BLUE2, " blue " }, + {&s_GOTBLUESKUL, CR_BLUE2, " blue " }, + {&s_GOTREDCARD, CR_RED, " red " }, + {&s_GOTREDSKULL, CR_RED, " red " }, + {&s_GOTYELWCARD, CR_GOLD, " yellow "}, + {&s_GOTYELWSKUL, CR_GOLD, " yellow "}, + {&s_PD_BLUEC, CR_BLUE2, " blue " }, + {&s_PD_BLUEK, CR_BLUE2, " blue " }, + {&s_PD_BLUEO, CR_BLUE2, " blue " }, + {&s_PD_BLUES, CR_BLUE2, " blue " }, + {&s_PD_REDC, CR_RED, " red " }, + {&s_PD_REDK, CR_RED, " red " }, + {&s_PD_REDO, CR_RED, " red " }, + {&s_PD_REDS, CR_RED, " red " }, + {&s_PD_YELLOWC, CR_GOLD, " yellow "}, + {&s_PD_YELLOWK, CR_GOLD, " yellow "}, + {&s_PD_YELLOWO, CR_GOLD, " yellow "}, + {&s_PD_YELLOWS, CR_GOLD, " yellow "}, + + // [Woof!] colorize multi-player messages + {&s_HUSTR_PLRGREEN, CR_GREEN, "Green: " }, + {&s_HUSTR_PLRINDIGO, CR_GRAY, "Indigo: "}, + {&s_HUSTR_PLRBROWN, CR_BROWN, "Brown: " }, + {&s_HUSTR_PLRRED, CR_RED, "Red: " }, +}; + +static char* PrepareColor(const char *str, const char *col) +{ + char *str_replace, col_replace[16]; + + M_snprintf(col_replace, sizeof(col_replace), + ORIG_S "%s" ORIG_S, col); + str_replace = M_StringReplace(str, col, col_replace); + + return str_replace; +} + +static void UpdateColor(char *str, int cr) +{ + int i; + int len = strlen(str); + + if (!message_colorized) + { + cr = CR_ORIG; + } + + for (i = 0; i < len; ++i) + { + if (str[i] == '\x1b' && i + 1 < len) + { + str[i + 1] = '0'+cr; + break; + } + } +} + +void ST_InitWidgets(void) +{ + // [Woof!] prepare player messages for colorization + for (int i = 0; i < arrlen(colorize_strings); i++) + { + *colorize_strings[i].str = + PrepareColor(*colorize_strings[i].str, colorize_strings[i].col); + } + + ST_ResetMessageColors(); +} + +void ST_ResetMessageColors(void) +{ + int i; + + for (i = 0; i < arrlen(colorize_strings); i++) + { + UpdateColor(*colorize_strings[i].str, colorize_strings[i].cr); + } +} + +sbarelem_t *st_time_elem = NULL; + +void ST_UpdateWidget(sbarelem_t *elem, player_t *player) +{ + sbe_widget_t *widget = elem->subtype.widget; + + switch (widget->type) + { + case sbw_message: + UpdateMessage(widget, player); + break; + case sbw_chat: + UpdateChat(widget); + break; + case sbw_secret: + UpdateSecretMessage(widget, player); + break; + case sbw_title: + UpdateTitle(widget); + break; + + case sbw_monsec: + UpdateMonSec(widget); + break; + case sbw_time: + st_time_elem = elem; + UpdateStTime(widget, player); + break; + case sbw_coord: + UpdateCoord(widget, player); + break; + case sbw_fps: + UpdateFPS(widget, player); + break; + case sbw_rate: + UpdateRate(widget, player); + break; + case sbw_cmd: + UpdateCmd(widget); + break; + case sbw_speed: + UpdateSpeed(widget, player); + break; + default: + break; + } +} + +void ST_BindHUDVariables(void) +{ + M_BindNum("hud_level_stats", &hud_level_stats, NULL, + HUD_WIDGET_OFF, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, + ss_stat, wad_no, + "Show level stats (kills, items, and secrets) widget (1 = On automap; " + "2 = On HUD; 3 = Always)"); + M_BindNum("hud_level_time", &hud_level_time, NULL, + HUD_WIDGET_OFF, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, + ss_stat, wad_no, + "Show level time widget (1 = On automap; 2 = On HUD; 3 = Always)"); + M_BindNum("hud_player_coords", &hud_player_coords, NULL, + HUD_WIDGET_AUTOMAP, HUD_WIDGET_OFF, HUD_WIDGET_ADVANCED, + ss_stat, wad_no, + "Show player coordinates widget (1 = On automap; 2 = On HUD; 3 = Always; 4 = Advanced)"); + M_BindBool("hud_command_history", &hud_command_history, NULL, false, ss_stat, + wad_no, "Show command history widget"); + BIND_NUM(hud_command_history_size, 10, 1, HU_MAXMESSAGES, + "Number of commands to display for command history widget"); + BIND_BOOL(hud_hide_empty_commands, true, + "Hide empty commands from command history widget"); + M_BindBool("hud_time_use", &hud_time_use, NULL, false, ss_stat, wad_no, + "Show split time when pressing the use-button"); + // M_BindNum("hud_widget_font", &hud_widget_font, NULL, + // HUD_WIDGET_OFF, HUD_WIDGET_OFF, HUD_WIDGET_ALWAYS, + // ss_stat, wad_no, + // "Use standard Doom font for widgets (1 = On automap; 2 = On HUD; 3 " + // "= Always)"); + + M_BindNum("hudcolor_titl", &hudcolor_titl, NULL, + CR_GOLD, CR_BRICK, CR_NONE, ss_none, wad_yes, + "Color range used for automap level title"); + M_BindNum("hudcolor_xyco", &hudcolor_xyco, NULL, + CR_GREEN, CR_BRICK, CR_NONE, ss_none, wad_yes, + "Color range used for automap coordinates"); + + BIND_BOOL(show_messages, true, "Show messages"); + M_BindBool("hud_secret_message", &hud_secret_message, NULL, + true, ss_stat, wad_no, "Announce revealed secrets"); + M_BindBool("hud_map_announce", &hud_map_announce, NULL, + false, ss_stat, wad_no, "Announce map titles"); + M_BindBool("show_toggle_messages", &show_toggle_messages, NULL, + true, ss_stat, wad_no, "Show toggle messages"); + M_BindBool("show_pickup_messages", &show_pickup_messages, NULL, + true, ss_stat, wad_no, "Show pickup messages"); + M_BindBool("show_obituary_messages", &show_obituary_messages, NULL, + true, ss_stat, wad_no, "Show obituaries"); + BIND_NUM(hudcolor_obituary, CR_GRAY, CR_BRICK, CR_NONE, + "Color range used for obituaries"); + M_BindBool("message_colorized", &message_colorized, NULL, + false, ss_stat, wad_no, "Colorize player messages"); + +#define BIND_CHAT(num) \ + M_BindStr("chatmacro" #num, &chat_macros[(num)], HUSTR_CHATMACRO##num, \ + wad_yes, "Chat string associated with " #num " key") + + BIND_CHAT(0); + BIND_CHAT(1); + BIND_CHAT(2); + BIND_CHAT(3); + BIND_CHAT(4); + BIND_CHAT(5); + BIND_CHAT(6); + BIND_CHAT(7); + BIND_CHAT(8); + BIND_CHAT(9); +} diff --git a/src/st_widgets.h b/src/st_widgets.h new file mode 100644 index 000000000..c76985294 --- /dev/null +++ b/src/st_widgets.h @@ -0,0 +1,75 @@ +// +// Copyright(C) 2024 Roman Fomin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#ifndef ST_WIDGETS_H +#define ST_WIDGETS_H + +#include "doomtype.h" + +struct sbarelem_s; +struct sbe_widget_s; +struct player_s; +struct event_s; + +#define HU_MAXMESSAGES 20 +#define HU_MAXLINELENGTH 120 + +typedef enum +{ + HUD_WIDGET_OFF, + HUD_WIDGET_AUTOMAP, + HUD_WIDGET_HUD, + HUD_WIDGET_ALWAYS, + HUD_WIDGET_ADVANCED, +} widgetstate_t; + +extern boolean show_messages; +extern boolean show_toggle_messages; +extern boolean show_pickup_messages; +extern boolean hud_secret_message; // "A secret is revealed!" message + +extern boolean chat_on; + +extern widgetstate_t hud_level_stats; +extern widgetstate_t hud_level_time; +extern widgetstate_t hud_player_coords; +extern int hudcolor_titl; +extern int hudcolor_xyco; + +extern boolean hud_time_use; + +extern struct sbarelem_s *st_time_elem; + +void ST_ResetTitle(void); + +void ST_ClearLines(struct sbe_widget_s *widget); +void ST_AddLine(struct sbe_widget_s *widget, const char *string); +void ST_UpdateWidget(struct sbarelem_s *elem, struct player_s *player); + +void ST_UpdateChatMessage(void); +boolean ST_MessagesResponder(struct event_s *ev); + +char ST_DequeueChatChar(void); + +extern char **player_names[]; +extern int speedometer; + +extern int playback_tic, playback_totaltics; +boolean ST_DemoProgressBar(boolean force); + +void ST_InitWidgets(void); +void ST_ResetMessageColors(void); + +void ST_BindHUDVariables(void); + +#endif \ No newline at end of file diff --git a/src/u_mapinfo.c b/src/u_mapinfo.c index c78a5c5b7..e672eda53 100644 --- a/src/u_mapinfo.c +++ b/src/u_mapinfo.c @@ -835,7 +835,7 @@ void U_ParseMapInfo(int lumpnum) G_ValidateMapName(parsed.mapname, &ep, &map); - strcpy(parsed.nextmap, MAPNAME(ep, map + 1)); + strcpy(parsed.nextmap, MapName(ep, map + 1)); } } diff --git a/src/v_video.c b/src/v_video.c index 4e2fccf4c..29e3f0ce1 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -37,7 +37,6 @@ #include "m_swap.h" #include "r_data.h" #include "r_defs.h" -#include "r_draw.h" #include "r_state.h" #include "s_sound.h" #include "sounds.h" @@ -139,6 +138,18 @@ int V_BloodColor(int blood) return bloodcolor[blood]; } +crange_idx_e V_CRByName(const char *name) +{ + for (const crdef_t *p = crdefs; p->name; ++p) + { + if (!strcmp(p->name, name)) + { + return p - crdefs; + } + } + return CR_NONE; +} + int v_lightest_color, v_darkest_color; byte invul_gray[256]; @@ -287,6 +298,8 @@ static void (*drawcolfunc)(const patch_column_t *patchcol); DRAW_COLUMN(, source[frac >> FRACBITS]) DRAW_COLUMN(TR, translation[source[frac >> FRACBITS]]) DRAW_COLUMN(TRTR, translation2[translation1[source[frac >> FRACBITS]]]) +DRAW_COLUMN(TL, tranmap[(*dest << 8) + source[frac >> FRACBITS]]) +DRAW_COLUMN(TRTL, tranmap[(*dest << 8) + translation[source[frac >> FRACBITS]]]) static void DrawMaskedColumn(patch_column_t *patchcol, const int ytop, column_t *column) @@ -501,6 +514,27 @@ void V_DrawPatchTranslated(int x, int y, patch_t *patch, byte *outr) DrawPatchInternal(x, y, patch, false); } +void V_DrawPatchTL(int x, int y, struct patch_s *patch, byte *tl) +{ + x += video.deltaw; + + tranmap = tl; + drawcolfunc = DrawPatchColumnTL; + + DrawPatchInternal(x, y, patch, false); +} + +void V_DrawPatchTRTL(int x, int y, struct patch_s *patch, byte *outr, byte *tl) +{ + x += video.deltaw; + + translation = outr; + tranmap = tl; + drawcolfunc = DrawPatchColumnTRTL; + + DrawPatchInternal(x, y, patch, false); +} + void V_DrawPatchTRTR(int x, int y, patch_t *patch, byte *outr1, byte *outr2) { x += video.deltaw; diff --git a/src/v_video.h b/src/v_video.h index 15e8e66bc..be1e851cf 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -65,6 +65,7 @@ extern byte *red2col[]; // symbolic indices into color translation table pointer array typedef enum { + CR_ORIG = -1, CR_BRICK, // 0 CR_TAN, // 1 CR_GRAY, // 2 @@ -84,8 +85,20 @@ typedef enum CR_LIMIT // 16 //jff 2/27/98 added for range check } crange_idx_e; +#define ORIG_S "\x1b\x2f" +#define BRICK_S "\x1b\x30" +#define TAN_S "\x1b\x31" +#define GRAY_S "\x1b\x32" +#define GREEN_S "\x1b\x33" +#define BROWN_S "\x1b\x34" +#define GOLD_S "\x1b\x35" +#define RED_S "\x1b\x36" +#define BLUE_S "\x1b\x37" + // jff 1/16/98 end palette color range additions +crange_idx_e V_CRByName(const char *name); + extern pixel_t *I_VideoBuffer; // jff 4/24/98 loads color translation lumps @@ -154,6 +167,10 @@ void V_DrawPatchTranslated(int x, int y, struct patch_s *patch, byte *outr); void V_DrawPatchTRTR(int x, int y, struct patch_s *patch, byte *outr1, byte *outr2); +void V_DrawPatchTL(int x, int y, struct patch_s *patch, byte *tl); + +void V_DrawPatchTRTL(int x, int y, struct patch_s *patch, byte *outr, byte *tl); + void V_DrawPatchFullScreen(struct patch_s *patch); // Draw a linear block of pixels into the view buffer. diff --git a/src/wi_interlvl.c b/src/wi_interlvl.c index 59ad0a024..fccc3bd9b 100644 --- a/src/wi_interlvl.c +++ b/src/wi_interlvl.c @@ -16,7 +16,6 @@ #include "doomdef.h" #include "doomtype.h" #include "i_printf.h" -#include "w_wad.h" #include "z_zone.h" #define M_ARRAY_MALLOC(size) Z_Malloc((size), PU_LEVEL, NULL) @@ -153,17 +152,16 @@ static void ParseLevelLayer(json_t *json, interlevellayer_t *out) interlevel_t *WI_ParseInterlevel(const char *lumpname) { - json_t *json = JS_Open("interlevel", (version_t){1, 0, 0}, - W_CacheLumpName(lumpname, PU_CACHE)); + json_t *json = JS_Open(lumpname, "interlevel", (version_t){1, 0, 0}); if (json == NULL) { - JS_Close(json); return NULL; } json_t *data = JS_GetObject(json, "data"); - if (JS_IsNull(data)) + if (JS_IsNull(data) || !JS_IsObject(data)) { + I_Printf(VB_ERROR, "%s: no data", lumpname); JS_Close(json); return NULL; } diff --git a/src/wi_stuff.c b/src/wi_stuff.c index 8a4559e1d..ebb6f902f 100644 --- a/src/wi_stuff.c +++ b/src/wi_stuff.c @@ -27,8 +27,6 @@ #include "doomstat.h" #include "doomtype.h" #include "g_game.h" -#include "hu_lib.h" -#include "hu_stuff.h" #include "i_printf.h" #include "m_misc.h" #include "m_random.h" @@ -36,7 +34,8 @@ #include "mn_menu.h" #include "r_defs.h" #include "s_sound.h" -#include "st_lib.h" +#include "st_sbardef.h" +#include "st_stuff.h" #include "sounds.h" #include "u_mapinfo.h" #include "v_fmt.h" @@ -46,6 +45,8 @@ #include "wi_stuff.h" #include "z_zone.h" +#define LARGENUMBER 1994 + // // Data needed to add patches to full screen intermission pics. // Patches are statistics messages, and animations. @@ -2121,7 +2122,7 @@ static void WI_drawStats(void) { // line height int lh; - int maplump = W_CheckNumForName(MAPNAME(wbs->epsd + 1, wbs->last + 1)); + int maplump = W_CheckNumForName(MapName(wbs->epsd + 1, wbs->last + 1)); lh = (3*SHORT(num[0]->height))/2;