diff --git a/source/common/scripting/interface/vmnatives.cpp b/source/common/scripting/interface/vmnatives.cpp index 4bd8853d7ee..de97b2974bd 100644 --- a/source/common/scripting/interface/vmnatives.cpp +++ b/source/common/scripting/interface/vmnatives.cpp @@ -133,6 +133,55 @@ DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawImage, SBar_DrawImage) return 0; } +void SBar_DrawImageRotated(DStatusBarCore* self, const FString& texid, double x, double y, int flags, double angle, double alpha, double scaleX, double scaleY, int style, int color, int translation) +{ + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->DrawRotated(TexMan.CheckForTexture(texid, ETextureType::Any), x, y, flags, alpha, scaleX, scaleY, color, translation, style); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawImageRotated, SBar_DrawImageRotated) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_STRING(texid); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(flags); + PARAM_FLOAT(angle); + PARAM_FLOAT(alpha); + PARAM_FLOAT(scaleX); + PARAM_FLOAT(scaleY); + PARAM_INT(style); + PARAM_INT(col); + PARAM_INT(trans); + SBar_DrawImageRotated(self, texid, x, y, flags, angle, alpha, scaleX, scaleY, style, col, trans); + return 0; +} + +void SBar_DrawTextureRotated(DStatusBarCore* self, int texid, double x, double y, int flags, double angle, double alpha, double scaleX, double scaleY, int style, int color, int translation) +{ + if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); + self->DrawRotated(FSetTextureID(texid), x, y, flags, alpha, scaleX, scaleY, color, translation, style); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawTextureRotated, SBar_DrawTextureRotated) +{ + PARAM_SELF_PROLOGUE(DStatusBarCore); + PARAM_INT(texid); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(flags); + PARAM_FLOAT(angle); + PARAM_FLOAT(alpha); + PARAM_FLOAT(scaleX); + PARAM_FLOAT(scaleY); + PARAM_INT(style); + PARAM_INT(col); + PARAM_INT(trans); + SBar_DrawTextureRotated(self, texid, x, y, flags, angle, alpha, scaleX, scaleY, style, col, trans); + return 0; +} + + void SBar_DrawString(DStatusBarCore* self, DHUDFont* font, const FString& string, double x, double y, int flags, int trans, double alpha, int wrapwidth, int linespacing, double scaleX, double scaleY, int translation, int style); DEFINE_ACTION_FUNCTION_NATIVE(DStatusBarCore, DrawString, SBar_DrawString) diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index 06f5969196a..5b86234b981 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -1559,6 +1559,25 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Raze, bcos, bcos) ACTION_RETURN_INT(bcos(v, shift)); } +DEFINE_ACTION_FUNCTION_NATIVE(_Raze, GetBuildTime, I_GetBuildTime) +{ + ACTION_RETURN_INT(I_GetBuildTime()); +} + +bool PickTexture(FRenderState* state, FGameTexture* tex, int paletteid, TexturePick& pick); + +DEFINE_ACTION_FUNCTION(_Raze, PickTexture) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + TexturePick pick; + if (PickTexture(nullptr, TexMan.GetGameTexture(FSetTextureID(texid)), TRANSLATION(Translation_Remap, 0), pick)) + { + ACTION_RETURN_INT(pick.texture->GetID().GetIndex()); + } + ACTION_RETURN_INT(texid); +} + DEFINE_ACTION_FUNCTION(_MapRecord, GetCluster) { PARAM_SELF_STRUCT_PROLOGUE(MapRecord); diff --git a/source/games/duke/src/player.cpp b/source/games/duke/src/player.cpp index ae7768fb1ee..f8a149aeb32 100644 --- a/source/games/duke/src/player.cpp +++ b/source/games/duke/src/player.cpp @@ -37,6 +37,7 @@ source as it is released. #include "global.h" #include "mapinfo.h" #include "dukeactor.h" +#include "vm.h" BEGIN_DUKE_NS @@ -1064,4 +1065,203 @@ void shootbloodsplat(DDukeActor* actor, int p, int sx, int sy, int sz, int sa, i } } + +DEFINE_FIELD_X(DukePlayer, player_struct, gotweapon) +DEFINE_FIELD_X(DukePlayer, player_struct, pals) +DEFINE_FIELD_X(DukePlayer, player_struct, weapon_sway) +DEFINE_FIELD_X(DukePlayer, player_struct, oweapon_sway) +DEFINE_FIELD_X(DukePlayer, player_struct, weapon_pos) +DEFINE_FIELD_X(DukePlayer, player_struct, kickback_pic) +DEFINE_FIELD_X(DukePlayer, player_struct, random_club_frame) +DEFINE_FIELD_X(DukePlayer, player_struct, oweapon_pos) +DEFINE_FIELD_X(DukePlayer, player_struct, okickback_pic) +DEFINE_FIELD_X(DukePlayer, player_struct, orandom_club_frame) +DEFINE_FIELD_X(DukePlayer, player_struct, hard_landing) +DEFINE_FIELD_X(DukePlayer, player_struct, ohard_landing) +DEFINE_FIELD_X(DukePlayer, player_struct, psectlotag) +DEFINE_FIELD_X(DukePlayer, player_struct, exitx) +DEFINE_FIELD_X(DukePlayer, player_struct, exity) +DEFINE_FIELD_X(DukePlayer, player_struct, loogiex) +DEFINE_FIELD_X(DukePlayer, player_struct, loogiey) +DEFINE_FIELD_X(DukePlayer, player_struct, numloogs) +DEFINE_FIELD_X(DukePlayer, player_struct, loogcnt) +DEFINE_FIELD_X(DukePlayer, player_struct, invdisptime) +DEFINE_FIELD_X(DukePlayer, player_struct, bobposx) +DEFINE_FIELD_X(DukePlayer, player_struct, bobposy) +DEFINE_FIELD_X(DukePlayer, player_struct, oposx) +DEFINE_FIELD_X(DukePlayer, player_struct, oposy) +DEFINE_FIELD_X(DukePlayer, player_struct, oposz) +DEFINE_FIELD_X(DukePlayer, player_struct, pyoff) +DEFINE_FIELD_X(DukePlayer, player_struct, opyoff) +DEFINE_FIELD_X(DukePlayer, player_struct, posxv) +DEFINE_FIELD_X(DukePlayer, player_struct, posyv) +DEFINE_FIELD_X(DukePlayer, player_struct, poszv) +DEFINE_FIELD_X(DukePlayer, player_struct, last_pissed_time) +DEFINE_FIELD_X(DukePlayer, player_struct, truefz) +DEFINE_FIELD_X(DukePlayer, player_struct, truecz) +DEFINE_FIELD_X(DukePlayer, player_struct, player_par) +DEFINE_FIELD_X(DukePlayer, player_struct, visibility) +DEFINE_FIELD_X(DukePlayer, player_struct, bobcounter) +DEFINE_FIELD_X(DukePlayer, player_struct, randomflamex) +DEFINE_FIELD_X(DukePlayer, player_struct, crack_time) +DEFINE_FIELD_X(DukePlayer, player_struct, aim_mode) +DEFINE_FIELD_X(DukePlayer, player_struct, ftt) +DEFINE_FIELD_X(DukePlayer, player_struct, cursectnum) +DEFINE_FIELD_X(DukePlayer, player_struct, last_extra) +DEFINE_FIELD_X(DukePlayer, player_struct, subweapon) +DEFINE_FIELD_X(DukePlayer, player_struct, ammo_amount) +DEFINE_FIELD_X(DukePlayer, player_struct, frag) +DEFINE_FIELD_X(DukePlayer, player_struct, fraggedself) +DEFINE_FIELD_X(DukePlayer, player_struct, curr_weapon) +DEFINE_FIELD_X(DukePlayer, player_struct, last_weapon) +DEFINE_FIELD_X(DukePlayer, player_struct, tipincs) +DEFINE_FIELD_X(DukePlayer, player_struct, wantweaponfire) +DEFINE_FIELD_X(DukePlayer, player_struct, holoduke_amount) +DEFINE_FIELD_X(DukePlayer, player_struct, hurt_delay) +DEFINE_FIELD_X(DukePlayer, player_struct, hbomb_hold_delay) +DEFINE_FIELD_X(DukePlayer, player_struct, jumping_counter) +DEFINE_FIELD_X(DukePlayer, player_struct, airleft) +DEFINE_FIELD_X(DukePlayer, player_struct, knee_incs) +DEFINE_FIELD_X(DukePlayer, player_struct, access_incs) +DEFINE_FIELD_X(DukePlayer, player_struct, ftq) +DEFINE_FIELD_X(DukePlayer, player_struct, access_wallnum) +DEFINE_FIELD_X(DukePlayer, player_struct, got_access) +DEFINE_FIELD_X(DukePlayer, player_struct, weapon_ang) +DEFINE_FIELD_X(DukePlayer, player_struct, firstaid_amount) +DEFINE_FIELD_X(DukePlayer, player_struct, i) +DEFINE_FIELD_X(DukePlayer, player_struct, one_parallax_sectnum) +DEFINE_FIELD_X(DukePlayer, player_struct, over_shoulder_on) +DEFINE_FIELD_X(DukePlayer, player_struct, fist_incs) +DEFINE_FIELD_X(DukePlayer, player_struct, cheat_phase) +DEFINE_FIELD_X(DukePlayer, player_struct, extra_extra8) +DEFINE_FIELD_X(DukePlayer, player_struct, quick_kick) +DEFINE_FIELD_X(DukePlayer, player_struct, last_quick_kick) +DEFINE_FIELD_X(DukePlayer, player_struct, heat_amount) +DEFINE_FIELD_X(DukePlayer, player_struct, timebeforeexit) +DEFINE_FIELD_X(DukePlayer, player_struct, customexitsound) +DEFINE_FIELD_X(DukePlayer, player_struct, weaprecs) +DEFINE_FIELD_X(DukePlayer, player_struct, weapreccnt) +DEFINE_FIELD_X(DukePlayer, player_struct, interface_toggle_flag) +DEFINE_FIELD_X(DukePlayer, player_struct, dead_flag) +DEFINE_FIELD_X(DukePlayer, player_struct, show_empty_weapon) +DEFINE_FIELD_X(DukePlayer, player_struct, scuba_amount) +DEFINE_FIELD_X(DukePlayer, player_struct, jetpack_amount) +DEFINE_FIELD_X(DukePlayer, player_struct, steroids_amount) +DEFINE_FIELD_X(DukePlayer, player_struct, shield_amount) +DEFINE_FIELD_X(DukePlayer, player_struct, pycount) +DEFINE_FIELD_X(DukePlayer, player_struct, frag_ps) +DEFINE_FIELD_X(DukePlayer, player_struct, transporter_hold) +DEFINE_FIELD_X(DukePlayer, player_struct, last_full_weapon) +DEFINE_FIELD_X(DukePlayer, player_struct, footprintshade) +DEFINE_FIELD_X(DukePlayer, player_struct, boot_amount) +DEFINE_FIELD_X(DukePlayer, player_struct, on_warping_sector) +DEFINE_FIELD_X(DukePlayer, player_struct, footprintcount) +DEFINE_FIELD_X(DukePlayer, player_struct, hbomb_on) +DEFINE_FIELD_X(DukePlayer, player_struct, jumping_toggle) +DEFINE_FIELD_X(DukePlayer, player_struct, rapid_fire_hold) +DEFINE_FIELD_X(DukePlayer, player_struct, on_ground) +DEFINE_FIELD_X(DukePlayer, player_struct, inven_icon) +DEFINE_FIELD_X(DukePlayer, player_struct, buttonpalette) +DEFINE_FIELD_X(DukePlayer, player_struct, jetpack_on) +DEFINE_FIELD_X(DukePlayer, player_struct, spritebridge) +DEFINE_FIELD_X(DukePlayer, player_struct, lastrandomspot) +DEFINE_FIELD_X(DukePlayer, player_struct, scuba_on) +DEFINE_FIELD_X(DukePlayer, player_struct, footprintpal) +DEFINE_FIELD_X(DukePlayer, player_struct, heat_on) +DEFINE_FIELD_X(DukePlayer, player_struct, holster_weapon) +DEFINE_FIELD_X(DukePlayer, player_struct, falling_counter) +DEFINE_FIELD_X(DukePlayer, player_struct, refresh_inventory) +DEFINE_FIELD_X(DukePlayer, player_struct, toggle_key_flag) +DEFINE_FIELD_X(DukePlayer, player_struct, knuckle_incs) +DEFINE_FIELD_X(DukePlayer, player_struct, walking_snd_toggle) +DEFINE_FIELD_X(DukePlayer, player_struct, palookup) +DEFINE_FIELD_X(DukePlayer, player_struct, quick_kick_msg) +DEFINE_FIELD_X(DukePlayer, player_struct, max_secret_rooms) +DEFINE_FIELD_X(DukePlayer, player_struct, secret_rooms) +DEFINE_FIELD_X(DukePlayer, player_struct, max_actors_killed) +DEFINE_FIELD_X(DukePlayer, player_struct, actors_killed) +DEFINE_FIELD_X(DukePlayer, player_struct, resurrected) +DEFINE_FIELD_X(DukePlayer, player_struct, stairs) +DEFINE_FIELD_X(DukePlayer, player_struct, detonate_count) +DEFINE_FIELD_X(DukePlayer, player_struct, noise_x) +DEFINE_FIELD_X(DukePlayer, player_struct, noise_y) +DEFINE_FIELD_X(DukePlayer, player_struct, noise_radius) +DEFINE_FIELD_X(DukePlayer, player_struct, drink_timer) +DEFINE_FIELD_X(DukePlayer, player_struct, eat_timer) +DEFINE_FIELD_X(DukePlayer, player_struct, SlotWin) +DEFINE_FIELD_X(DukePlayer, player_struct, recoil) +DEFINE_FIELD_X(DukePlayer, player_struct, detonate_time) +DEFINE_FIELD_X(DukePlayer, player_struct, yehaa_timer) +DEFINE_FIELD_X(DukePlayer, player_struct, drink_amt) +DEFINE_FIELD_X(DukePlayer, player_struct, eat) +DEFINE_FIELD_X(DukePlayer, player_struct, drunkang) +DEFINE_FIELD_X(DukePlayer, player_struct, eatang) +DEFINE_FIELD_X(DukePlayer, player_struct, shotgun_state) +DEFINE_FIELD_X(DukePlayer, player_struct, donoise) +DEFINE_FIELD_X(DukePlayer, player_struct, keys) +DEFINE_FIELD_X(DukePlayer, player_struct, drug_aspect) +DEFINE_FIELD_X(DukePlayer, player_struct, drug_timer) +DEFINE_FIELD_X(DukePlayer, player_struct, SeaSick) +DEFINE_FIELD_X(DukePlayer, player_struct, MamaEnd) +DEFINE_FIELD_X(DukePlayer, player_struct, moto_drink) +DEFINE_FIELD_X(DukePlayer, player_struct, TiltStatus) +DEFINE_FIELD_X(DukePlayer, player_struct, oTiltStatus) +DEFINE_FIELD_X(DukePlayer, player_struct, VBumpNow) +DEFINE_FIELD_X(DukePlayer, player_struct, VBumpTarget) +DEFINE_FIELD_X(DukePlayer, player_struct, TurbCount) +DEFINE_FIELD_X(DukePlayer, player_struct, drug_stat) +DEFINE_FIELD_X(DukePlayer, player_struct, DrugMode) +DEFINE_FIELD_X(DukePlayer, player_struct, lotag800kill) +DEFINE_FIELD_X(DukePlayer, player_struct, sea_sick_stat) +DEFINE_FIELD_X(DukePlayer, player_struct, hurt_delay2) +DEFINE_FIELD_X(DukePlayer, player_struct, nocheat) +DEFINE_FIELD_X(DukePlayer, player_struct, OnMotorcycle) +DEFINE_FIELD_X(DukePlayer, player_struct, OnBoat) +DEFINE_FIELD_X(DukePlayer, player_struct, moto_underwater) +DEFINE_FIELD_X(DukePlayer, player_struct, NotOnWater) +DEFINE_FIELD_X(DukePlayer, player_struct, MotoOnGround) +DEFINE_FIELD_X(DukePlayer, player_struct, moto_do_bump) +DEFINE_FIELD_X(DukePlayer, player_struct, moto_bump_fast) +DEFINE_FIELD_X(DukePlayer, player_struct, moto_on_oil) +DEFINE_FIELD_X(DukePlayer, player_struct, moto_on_mud) +DEFINE_FIELD_X(DukePlayer, player_struct, vehForwardScale) +DEFINE_FIELD_X(DukePlayer, player_struct, vehReverseScale) +DEFINE_FIELD_X(DukePlayer, player_struct, MotoSpeed) +DEFINE_FIELD_X(DukePlayer, player_struct, vehTurnLeft) +DEFINE_FIELD_X(DukePlayer, player_struct, vehTurnRight) +DEFINE_FIELD_X(DukePlayer, player_struct, vehBraking) +DEFINE_FIELD_X(DukePlayer, player_struct, holoduke_on) + +DEFINE_ACTION_FUNCTION(_DukePlayer, IsFrozen) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_struct); + ACTION_RETURN_BOOL(self->GetActor()->s->pal == 1 && self->last_extra < 2); +} + +DEFINE_ACTION_FUNCTION(_DukePlayer, GetGameVar) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_struct); + PARAM_STRING(name); + PARAM_INT(def); + ACTION_RETURN_INT(GetGameVar(name, def, self->GetActor(), self->GetPlayerNum())); +} + +DEFINE_ACTION_FUNCTION(_Duke, GetViewPlayer) +{ + ACTION_RETURN_POINTER(&ps[screenpeek]); +} + +DEFINE_ACTION_FUNCTION(_Duke, MaxPlayerHealth) +{ + ACTION_RETURN_INT(gs.max_player_health); +} + +DEFINE_ACTION_FUNCTION(_Duke, MaxAmmoAmount) +{ + PARAM_PROLOGUE; + PARAM_INT(weap); + int max = weap < 0 || weap >= MAX_WEAPONS ? 0 : gs.max_ammo_amount[weap]; + ACTION_RETURN_INT(max); +} + END_DUKE_NS diff --git a/source/games/duke/src/sbar.cpp b/source/games/duke/src/sbar.cpp index f4c85cf6ade..cca87b7d398 100644 --- a/source/games/duke/src/sbar.cpp +++ b/source/games/duke/src/sbar.cpp @@ -44,8 +44,8 @@ source as it is released. BEGIN_DUKE_NS -IMPLEMENT_CLASS(DDukeCommonStatusBar, true, true) -IMPLEMENT_POINTERS_START(DDukeCommonStatusBar) +IMPLEMENT_CLASS(DNativeDukeCommonStatusBar, true, true) +IMPLEMENT_POINTERS_START(DNativeDukeCommonStatusBar) IMPLEMENT_POINTER(miniFont) IMPLEMENT_POINTER(numberFont) IMPLEMENT_POINTER(digiFont) @@ -59,7 +59,7 @@ IMPLEMENT_POINTERS_END // //========================================================================== -DDukeCommonStatusBar::DDukeCommonStatusBar() +DNativeDukeCommonStatusBar::DNativeDukeCommonStatusBar() { drawOffset.Y = 0; } @@ -71,7 +71,7 @@ DDukeCommonStatusBar::DDukeCommonStatusBar() // //========================================================================== #if 0 -void DDukeCommonStatusBar::displayfragbar(void) +void DNativeDukeCommonStatusBar::displayfragbar(void) { short i, j; @@ -98,7 +98,7 @@ void DDukeCommonStatusBar::displayfragbar(void) // //========================================================================== -std::pair DDukeCommonStatusBar::ontext(struct player_struct *p) +std::pair DNativeDukeCommonStatusBar::ontext(struct player_struct *p) { std::pair retval(nullptr, CR_RED); @@ -136,7 +136,7 @@ std::pair DDukeCommonStatusBar::ontext(struct player_struct *p // //========================================================================== -void DDukeCommonStatusBar::DrawInventory(const struct player_struct* p, double x, double y, int align) +void DNativeDukeCommonStatusBar::DrawInventory(const struct player_struct* p, double x, double y, int align) { if (p->invdisptime <= 0)return; @@ -173,7 +173,7 @@ void DDukeCommonStatusBar::DrawInventory(const struct player_struct* p, double x // //========================================================================== -PalEntry DDukeCommonStatusBar::LightForShade(int shade) +PalEntry DNativeDukeCommonStatusBar::LightForShade(int shade) { int ll = clamp((numshades - shade) * 255 / numshades, 0, 255); return PalEntry(255, ll, ll, ll); @@ -186,7 +186,7 @@ PalEntry DDukeCommonStatusBar::LightForShade(int shade) // //========================================================================== -void DDukeCommonStatusBar::PrintLevelStats(int bottomy) +void DNativeDukeCommonStatusBar::PrintLevelStats(int bottomy) { FLevelStats stats{}; auto pp = &ps[myconnectindex]; diff --git a/source/games/duke/src/sbar.h b/source/games/duke/src/sbar.h index 135d0134be1..20b02a9eaf8 100644 --- a/source/games/duke/src/sbar.h +++ b/source/games/duke/src/sbar.h @@ -7,9 +7,9 @@ BEGIN_DUKE_NS -class DDukeCommonStatusBar : public DBaseStatusBar +class DNativeDukeCommonStatusBar : public DBaseStatusBar { - DECLARE_ABSTRACT_CLASS(DDukeCommonStatusBar, DBaseStatusBar) + DECLARE_ABSTRACT_CLASS(DNativeDukeCommonStatusBar, DBaseStatusBar) HAS_OBJECT_POINTERS protected: @@ -21,7 +21,7 @@ class DDukeCommonStatusBar : public DBaseStatusBar std::array ammo_sprites; std::array item_icons; - DDukeCommonStatusBar(); + DNativeDukeCommonStatusBar(); std::pair ontext(struct player_struct *p); void DrawInventory(const struct player_struct* p, double x, double y, int align); PalEntry LightForShade(int shade); diff --git a/source/games/duke/src/sbar_d.cpp b/source/games/duke/src/sbar_d.cpp index 56b37104b65..4d2074aa032 100644 --- a/source/games/duke/src/sbar_d.cpp +++ b/source/games/duke/src/sbar_d.cpp @@ -55,14 +55,14 @@ BEGIN_DUKE_NS // //========================================================================== -class DDukeStatusBar : public DDukeCommonStatusBar +class DNativeDukeStatusBar : public DNativeDukeCommonStatusBar { - DECLARE_CLASS(DDukeStatusBar, DDukeCommonStatusBar) + DECLARE_CLASS(DNativeDukeStatusBar, DNativeDukeCommonStatusBar) int fontheight[2]; public: - DDukeStatusBar() + DNativeDukeStatusBar() { numberFont = Create( BigFont, 0, Off, 1, 1 ); indexFont = Create(IndexFont, 4, CellRight, 1, 1 ); @@ -481,11 +481,11 @@ class DDukeStatusBar : public DDukeCommonStatusBar } }; -IMPLEMENT_CLASS(DDukeStatusBar, false, false) +IMPLEMENT_CLASS(DNativeDukeStatusBar, false, false) DBaseStatusBar* CreateDukeStatusBar() { - return Create(); + return Create(); } END_DUKE_NS diff --git a/source/games/duke/src/sbar_r.cpp b/source/games/duke/src/sbar_r.cpp index e411950f4eb..92696965f07 100644 --- a/source/games/duke/src/sbar_r.cpp +++ b/source/games/duke/src/sbar_r.cpp @@ -47,12 +47,12 @@ BEGIN_DUKE_NS // //========================================================================== -class DRedneckStatusBar : public DDukeCommonStatusBar +class DNativeRedneckStatusBar : public DNativeDukeCommonStatusBar { - DECLARE_CLASS(DRedneckStatusBar, DDukeCommonStatusBar) + DECLARE_CLASS(DNativeRedneckStatusBar, DNativeDukeCommonStatusBar) public: - DRedneckStatusBar() + DNativeRedneckStatusBar() { numberFont = Create(BigFont, 0, Off, 1, 1 ); miniFont = Create(SmallFont2, 0, Off, 1, 1 ); @@ -466,11 +466,11 @@ class DRedneckStatusBar : public DDukeCommonStatusBar }; -IMPLEMENT_CLASS(DRedneckStatusBar, false, false) +IMPLEMENT_CLASS(DNativeRedneckStatusBar, false, false) DBaseStatusBar* CreateRedneckStatusBar() { - return Create(); + return Create(); } diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 861421d55da..54b93635ca0 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -31,6 +31,9 @@ version "4.3" #include "zscript/screenjob.zs" #include "zscript/statusbar.zs" #include "zscript/games/duke/dukegame.zs" +#include "zscript/games/duke/ui/sbar.zs" +#include "zscript/games/duke/ui/sbar_d.zs" +#include "zscript/games/duke/ui/sbar_r.zs" #include "zscript/games/duke/ui/screens.zs" #include "zscript/games/duke/ui/cutscenes.zs" #include "zscript/games/duke/ui/menu.zs" diff --git a/wadsrc/static/zscript/engine/ui/statusbar/statusbarcore.zs b/wadsrc/static/zscript/engine/ui/statusbar/statusbarcore.zs index 01157fdc61a..86f93773c13 100644 --- a/wadsrc/static/zscript/engine/ui/statusbar/statusbarcore.zs +++ b/wadsrc/static/zscript/engine/ui/statusbar/statusbarcore.zs @@ -110,6 +110,10 @@ class StatusBarCore native ui native double, double, double, double StatusbarToRealCoords(double x, double y=0, double w=0, double h=0); native void DrawTexture(TextureID texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1), ERenderStyle style = STYLE_Translucent, Color col = 0xffffffff, int translation = 0, double clipwidth = -1); native void DrawImage(String texture, Vector2 pos, int flags = 0, double Alpha = 1., Vector2 box = (-1, -1), Vector2 scale = (1, 1), ERenderStyle style = STYLE_Translucent, Color col = 0xffffffff, int translation = 0, double clipwidth = -1); + + native void DrawTextureRotated(TextureID texid, Vector2 pos, int flags, double angle, double alpha = 1, Vector2 scale = (1, 1), ERenderStyle style = STYLE_Translucent, Color col = 0xffffffff, int translation = 0); + native void DrawImageRotated(String texid, Vector2 pos, int flags, double angle, double alpha = 1, Vector2 scale = (1, 1), ERenderStyle style = STYLE_Translucent, Color col = 0xffffffff, int translation = 0); + native void DrawString(HUDFont font, String string, Vector2 pos, int flags = 0, int translation = Font.CR_UNTRANSLATED, double Alpha = 1., int wrapwidth = -1, int linespacing = 4, Vector2 scale = (1, 1), int pt = 0, ERenderStyle style = STYLE_Translucent); native double, double, double, double TransformRect(double x, double y, double w, double h, int flags = 0); native void Fill(Color col, double x, double y, double w, double h, int flags = 0); diff --git a/wadsrc/static/zscript/games/duke/dukegame.zs b/wadsrc/static/zscript/games/duke/dukegame.zs index ef06f96bd16..97f49acace7 100644 --- a/wadsrc/static/zscript/games/duke/dukegame.zs +++ b/wadsrc/static/zscript/games/duke/dukegame.zs @@ -49,10 +49,26 @@ struct Duke native BASEPALCOUNT }; + enum dukeinvicon_t + { + ICON_NONE, // 0 + ICON_FIRSTAID, + ICON_STEROIDS, + ICON_HOLODUKE, + ICON_JETPACK, + ICON_HEATS, // 5 + ICON_SCUBA, + ICON_BOOTS, + ICON_MAX + }; + native static void PlaySpecialMusic(int which); native static int PlaySound(int num, int channel = CHAN_AUTO, int flags = 0, float vol =0.8f); native static void StopSound(int num); native static bool CheckSoundPlaying(int num); + native static DukePlayer GetViewPlayer(); + native static int MaxPlayerHealth(); + native static int MaxAmmoAmount(int weap); static void PlayBonusMusic() { @@ -111,6 +127,206 @@ struct Duke native } +struct DukePlayer +{ + // The sound code wants to read a vector out of this so we need to define one for the main coordinate. + /* + union + { + vec3_t pos; + struct { int32_t posx, posy, posz; }; + }; + + // player's horizon and angle structs. + PlayerHorizon horizon; + PlayerAngle angle; + + uint16_t frags[MAXPLAYERS]; + */ + + native bool gotweapon[DukeWpn.MAX_WEAPONS]; + + // Palette management uses indices into the engine's palette table now. + native color pals; + + // this was a global variable originally. + //vec2_t fric; + + // weapon drawer variables and their interpolation counterparts. + native int weapon_sway; + native int oweapon_sway; + native int16 weapon_pos, kickback_pic, random_club_frame; + native int16 oweapon_pos, okickback_pic, orandom_club_frame; + native uint8 hard_landing; + native uint8 ohard_landing; + + // Store current psectlotag as determined in processinput() for use with scaling angle aiming. + native int16 psectlotag; + + // From here on it is unaltered from JFDuke with the exception of a few fields that are no longer needed and were removed. + native int exitx, exity, loogiex[64], loogiey[64], numloogs, loogcnt; + native int invdisptime; + native int bobposx, bobposy, oposx, oposy, oposz, pyoff, opyoff; + native int posxv, posyv, poszv, last_pissed_time, truefz, truecz; + native int player_par, visibility; + native int bobcounter; + native int randomflamex, crack_time; + + native int aim_mode, ftt; + + native int16 cursectnum, last_extra, subweapon; + native int16 ammo_amount[DukeWpn.MAX_WEAPONS], frag, fraggedself; + + native int16 curr_weapon, last_weapon, tipincs, wantweaponfire; + native int16 holoduke_amount, hurt_delay, hbomb_hold_delay; + native int16 jumping_counter, airleft, knee_incs, access_incs; + native int16 ftq, access_wallnum; + native int16 got_access, weapon_ang, firstaid_amount; + native int16 i, one_parallax_sectnum; + native int16 over_shoulder_on, fist_incs; + native int16 cheat_phase; + native int16 extra_extra8, quick_kick, last_quick_kick; + native int16 heat_amount, timebeforeexit, customexitsound; + //DDukeActor* actorsqu, *wackedbyactor, *on_crane, *holoduke_on, *somethingonplayer, *access_spritenum, *dummyplayersprite, *newOwner; // later + native voidptr holoduke_on; // cannot do it as a proper actor pointer - but the status bar needs it. + + native int16 weaprecs[256], weapreccnt; + native uint interface_toggle_flag; + + native int16 dead_flag, show_empty_weapon; // JBF 20031220: added orotscrnang + native int16 scuba_amount, jetpack_amount, steroids_amount, shield_amount; + native int16 pycount, frag_ps; + native int16 transporter_hold, last_full_weapon, footprintshade, boot_amount; + + native uint8 on_warping_sector, footprintcount; + native uint8 hbomb_on, jumping_toggle, rapid_fire_hold, on_ground; + //char name[32]; + native uint8 inven_icon, buttonpalette; + + native uint8 jetpack_on, spritebridge, lastrandomspot; + native uint8 scuba_on, footprintpal, heat_on; + + native uint8 holster_weapon; + native uint8 falling_counter; + native uint8 refresh_inventory; + + native uint8 toggle_key_flag, knuckle_incs; // ,select_dir; + native uint8 walking_snd_toggle, palookup; + native bool quick_kick_msg; + + native int max_secret_rooms, secret_rooms, max_actors_killed, actors_killed; + + native bool resurrected; + + // Redneck Rampage additions. Those which did not have names in the reconstructed source got one from either RedneckGDX or RedNukem. + // Items were reordered by size. + native int stairs; + native int detonate_count; // at57e + native int noise_x, noise_y, noise_radius; // at286, at28a, at290 + native int drink_timer; // at58e + native int eat_timer; // at592 + native int SlotWin; + native int16 recoil; + native int16 detonate_time; // at57c + native int16 yehaa_timer; + native int16 drink_amt, eat, drunkang, eatang; + native uint8 shotgun_state[2]; + native uint8 donoise; // at28e + native uint8 keys[5]; + + // RRRA. The same as for the RR block applies. + native int drug_aspect; + native int drug_timer; + native int SeaSick; + native int16 MamaEnd; // raat609 + native int16 moto_drink; + native float TiltStatus, oTiltStatus; + native int16 VBumpNow, VBumpTarget, TurbCount; + native int16 drug_stat[3]; // raat5f1..5 + native uint8 DrugMode, lotag800kill; + native uint8 sea_sick_stat; // raat5dd + native uint8 hurt_delay2, nocheat; + native uint8 OnMotorcycle, OnBoat, moto_underwater, NotOnWater, MotoOnGround; + native uint8 moto_do_bump, moto_bump_fast, moto_on_oil, moto_on_mud; + native double vehForwardScale, vehReverseScale, MotoSpeed; + native bool vehTurnLeft, vehTurnRight, vehBraking; + + // input stuff. + //InputPacket sync; + + /* + DDukeActor* GetActor(); + int GetPlayerNum(); + + void apply_seasick(double factor); + void backuppos(bool noclipping = false); + void backupweapon(); + void checkhardlanding(); + void playerweaponsway(int xvel); + + float adjustavel(float avel) + { + return (psectlotag == ST_2_UNDERWATER)? avel * 0.875f : avel; + } + */ + + native bool IsFrozen(); + native int GetGameVar(String varname, int defval); + + +} + +struct DukeWpn +{ + enum dukeweapon_t + { + KNEE_WEAPON, // 0 + PISTOL_WEAPON, + SHOTGUN_WEAPON, + CHAINGUN_WEAPON, + RPG_WEAPON, + HANDBOMB_WEAPON, // 5 + SHRINKER_WEAPON, + DEVISTATOR_WEAPON, + TRIPBOMB_WEAPON, + FREEZE_WEAPON, + HANDREMOTE_WEAPON, // 10 + GROW_WEAPON, + FLAMETHROWER_WEAPON, // World Tour + + MIN_WEAPON = 0, + MAX_WEAPON = 9, + MAX_WEAPONS = 17 + } +} + +struct RRWpn +{ + enum redneck_weapon_t + { + // These names have been pieced together from RedneckGDX and RedNukem because the reconstructed source recycled Duke's names for the first 11 weapons. + // Names for 0-2 are the same + KNEE_WEAPON, // 0 + PISTOL_WEAPON, + SHOTGUN_WEAPON, + RIFLEGUN_WEAPON, + DYNAMITE_WEAPON, + CROSSBOW_WEAPON, // 5 + THROWSAW_WEAPON, + ALIENBLASTER_WEAPON, + POWDERKEG_WEAPON, + TIT_WEAPON, + THROWINGDYNAMITE_WEAPON, // 10 + BUZZSAW_WEAPON, + BOWLING_WEAPON, + MOTORCYCLE_WEAPON, + BOAT_WEAPON, + SLINGBLADE_WEAPON, // 15 + CHICKEN_WEAPON, + MAX_WEAPONS + } +} + struct DukeSnd native { // This really needs to be done better... diff --git a/wadsrc/static/zscript/games/duke/ui/sbar.zs b/wadsrc/static/zscript/games/duke/ui/sbar.zs new file mode 100644 index 00000000000..77b9a5e4f7d --- /dev/null +++ b/wadsrc/static/zscript/games/duke/ui/sbar.zs @@ -0,0 +1,218 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment +Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements) +Copyright (C) 2020-2021 - Christoph Oelckers + +This file is part of Enhanced Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms + +EDuke enhancements integrated: 04/13/2003 - Matt Saettler + +Note: EDuke source was in transition. Changes are in-progress in the +source as it is released. + +*/ +//------------------------------------------------------------------------- + + +class DukeCommonStatusBar : RazeStatusBar +{ + + HUDFont numberFont; + HUDFont miniFont; + HUDFont digiFont; + double scale; + Array ammo_sprites; + Array item_icons; + + int tileHeight(String tex) + { + let img = TexMan.CheckForTexture(tex, TexMan.TYPE_Any); + let siz = TexMan.GetScaledSize(img); + return int(siz.Y); + } + + //========================================================================== + // + // Frag bar - todo + // + //========================================================================== + /* + void displayfragbar(void) + { + short i, j; + + j = 0; + + for (i = connecthead; i >= 0; i = connectpoint2[i]) + if (i > j) j = i; + + auto tex = tileGetTexture(TILE_FRAGBAR); + for (int y = 0; y < 32; y += 8) + DrawTexture(twod, tex, 0, 0, DTA_FullscreenScale, FSMode_Fit320x200, DTA_ScaleX, 1.001, DTA_ScaleY, 1.001, TAG_Done); + + for (i = connecthead; i >= 0; i = connectpoint2[i]) + { + m initext(21 + (73 * (i & 3)), 2 + ((i & 28) << 1), &ud.user_name[i][0], ps[i].GetActor().s.pal, 2 + 8 + 16 + 128); + sprintf(tempbuf, "%d", ps[i].frag - ps[i].fraggedself); + m initext(17 + 50 + (73 * (i & 3)), 2 + ((i & 28) << 1), tempbuf, ps[i].GetActor().s.pal, 2 + 8 + 16 + 128); + } + } + */ + //========================================================================== + // + // Common inventory icon code for all styles + // + //========================================================================== + + String, int ontext(DukePlayer p) + { + String first = ""; + int second = 6; + + int onstate = 0x80000000; + switch (p.inven_icon) + { + case Duke.ICON_HOLODUKE: + onstate = p.holoduke_on != null; + break; + case Duke.ICON_JETPACK: + onstate = p.jetpack_on; + break; + case Duke.ICON_HEATS: + onstate = p.heat_on; + break; + } + + // Texts are intentionally not translated because the font is too small for making localization work and the translated words are too long. + if (onstate != 0x80000000 && !(gameinfo.gameType & (GAMEFLAG_WW2GI|GAMEFLAG_RRALL))) + { + second = onstate > 0 ? 0 : 2; + first = onstate > 0 ? "ON" : "OFF"; + } + if (p.inven_icon >= Duke.ICON_SCUBA) + { + second = 2; + first = "AUTO"; + } + return first, second; + } + + //========================================================================== + // + // draws the inventory selector + // + //========================================================================== + + void DrawInventory(DukePlayer p, double x, double y, int align) + { + if (p.invdisptime <= 0)return; + + int n = 0, j = 0; + if (p.firstaid_amount > 0) { n |= 1; j++; } + if (p.steroids_amount > 0) { n |= 2; j++; } + if (p.holoduke_amount > 0) { n |= 4; j++; } + if (p.jetpack_amount > 0) { n |= 8; j++; } + if (p.heat_amount > 0) { n |= 16; j++; } + if (p.scuba_amount > 0) { n |= 32; j++; } + if (p.boot_amount > 0) { n |= 64; j++; } + + x -= (j * 11); + y -= 6; + + align |= DI_ITEM_CENTER; + for(int bit = 0; bit < 7; bit++) + { + int i = 1 << bit; + if (n & i) + { + int select = 1 << (p.inven_icon - 1); + double alpha = select == i ? 1.0 : 0.7; + DrawImage(item_icons[bit+1], (x, y), align, alpha, scale:(scale, scale)); + if (select == i) DrawImage("ARROW", (Raze.isWW2GI()? x + 7.5 : x, Raze.isWW2GI()? y + 0.5 : y), align, alpha, scale:(scale, scale)); + x += 22; + } + } + } + + //========================================================================== + // + // Statistics output + // + //========================================================================== + + void DoLevelStats(int bottomy, SummaryInfo info) + { + StatsPrintInfo stats; + stats.fontscale = Raze.isRR() ? 0.5 : 1.; + stats.screenbottomspace = bottomy; + stats.statfont = SmallFont; + if (Raze.isNamWW2GI()) + { + // The stock font of these games is totally unusable for this. + stats.statfont = ConFont; + stats.spacing = ConFont.GetHeight() + 1; + } + + if (automapMode == am_full) + { + bool textfont = am_textfont; + if (!am_textfont) + { + // For non-English languages force use of the text font. The tiny one is simply too small to ever add localized characters to it. + let p = StringTable.Localize("$REQUIRED_CHARACTERS"); + if (p.length() > 0) textfont = true; + } + + if (!textfont) + { + stats.statfont = SmallFont2; + stats.spacing = 6; + } + else stats.spacing = stats.statfont.GetHeight() + 1; + stats.standardColor = (Raze.isNamWW2GI() && am_textfont)? Font.TEXTCOLOR_ORANGE : Font.TEXTCOLOR_UNTRANSLATED; + stats.letterColor = Font.TEXTCOLOR_GOLD; + PrintAutomapInfo(stats, textfont); + } + else if (hud_stats) + { + stats.spacing = Raze.isRR() ? 10 : 7; + stats.letterColor = Font.TEXTCOLOR_ORANGE; + if (Raze.isNamWW2GI()) + { + stats.standardColor = Font.TEXTCOLOR_YELLOW; + stats.completeColor = Font.TEXTCOLOR_FIRE; + } + else if (!Raze.isRR()) + { + stats.standardColor = Font.TEXTCOLOR_CREAM; + stats.completeColor = Font.TEXTCOLOR_FIRE; + } + else + { + stats.standardColor = + stats.completeColor = Font.TEXTCOLOR_UNTRANSLATED; + } + PrintLevelStats(stats, info); + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/games/duke/ui/sbar_d.zs b/wadsrc/static/zscript/games/duke/ui/sbar_d.zs new file mode 100644 index 00000000000..5cb3bc9ee21 --- /dev/null +++ b/wadsrc/static/zscript/games/duke/ui/sbar_d.zs @@ -0,0 +1,479 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment +Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements) +Copyright (C) 2020 - Christoph Oelckers + +This file is part of Enhanced Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms + +EDuke enhancements integrated: 04/13/2003 - Matt Saettler + +Note: EDuke source was in transition. Changes are in-progress in the +source as it is released. + +*/ +//------------------------------------------------------------------------- + + +class DukeStatusBar : DukeCommonStatusBar +{ + int fontheight[2]; + TextureID ThreeByFive[12]; + HUDFont indxfont; + + override void Init() + { + numberFont = HUDFont.Create(BigFont, 0, Mono_Off, 1, 1 ); + indxfont = HUDFont.Create(Font.FindFont("IndexFont"), 4, Mono_CellRight, 1, 1 ); + miniFont = HUDFont.Create(SmallFont2, 0, Mono_Off, 1, 1 ); + digiFont = HUDFont.Create(Font.FindFont("DigiFont"), 1, Mono_Off, 1, 1 ); + + // optionally draw at the top of the screen. + SetSize(tileHeight("BOTTOMSTATUSBAR"), 320, 200); + scale = 1; + + ammo_sprites.PushV("", "AMMO", "SHOTGUNAMMO", "BATTERYAMMO", "RPGAMMO", "HBOMBAMMO", "CRYSTALAMMO", "DEVISTATORAMMO", "TRIPBOMBSPRITE", "FREEZEAMMO1", "HBOMBAMMO", "GROWAMMO", "FLAMETHROWERAMMO1" ); + item_icons.PushV("", "FIRSTAID_ICON", "STEROIDS_ICON", "HOLODUKE_ICON", "JETPACK_ICON", "HEAT_ICON", "AIRTANK_ICON", "BOOT_ICON" ); + + // get the true size of the font. + fontheight[1] = fontheight[0] = 0; + for (int i = 0; i <= 9; i++) + { + let name = String.Format("BIGALPHANUM%d", i); + let zerotex = TexMan.CheckForTexture(name, TexMan.Type_Any); + if (zerotex.IsValid()) + { + int fh0 = TexMan.CheckRealHeight(zerotex); + int fh1 = fh0; + let hitex = Raze.PickTexture(zerotex); + if (hitex.IsValid()) + { + let osize = TexMan.GetScaledSize(zerotex); + let dsize = TexMan.GetScaledSize(hitex); + int dReal = TexMan.CheckRealHeight(hitex); + fh1 = int(dReal * osize.Y / dsize.Y); + } + if (fh0 > fontheight[0]) fontheight[0] = fh0; + if (fh1 > fontheight[1]) fontheight[1] = fh1; + } + } + for (int i = 0; i <= 11; i++) + { + let str = String.Format("THREEBYFIVE%d", i); + ThreeByFive[i] = TexMan.CheckForTexture(str, TexMan.Type_Any); + } + } + + //========================================================================== + // + // Helpers + // + //========================================================================== + + int getinvamount(DukePlayer p) + { + switch (p.inven_icon) + { + case Duke.ICON_FIRSTAID: + return p.firstaid_amount; + case Duke.ICON_STEROIDS: + return (p.steroids_amount + 3) >> 2; + case Duke.ICON_HOLODUKE: + return (p.holoduke_amount + 15) / 24; + case Duke.ICON_JETPACK: + return (p.jetpack_amount + 15) >> 4; + case Duke.ICON_HEATS: + return p.heat_amount / 12; + case Duke.ICON_SCUBA: + return (p.scuba_amount + 63) >> 6; + case Duke.ICON_BOOTS: + return p.boot_amount >> 1; + } + + return -1; + } + + int GetMoraleOrShield(DukePlayer p) + { + // special handling for WW2GI + int lAmount = p.GetGameVar("PLR_MORALE", -1); + if (lAmount == -1) lAmount = p.shield_amount; + return lAmount; + } + + + //========================================================================== + // + // Fullscreen HUD variant #1 + // + //========================================================================== + + void FullscreenHUD1(DukePlayer p) + { + int fh = fontheight[hw_hightile ? 1 : 0]; + String format; + TextureID img; + double imgScale; + double baseScale = (scale * (fh+1)); + double texty = -fh - 2.5; + + // + // Health + // + img = TexMan.CheckForTexture(Raze.isNamWW2GI()? "FIRSTAID_ICON" : "COLA"); + let siz = TexMan.GetScaledSize(img); + imgScale = baseScale / siz.Y; + DrawTexture(img, (2, -1.5), DI_ITEM_LEFT_BOTTOM, scale:(imgScale, imgScale)); + + if (!hud_flashing || p.last_extra > (Duke.MaxPlayerHealth() >> 2) || (PlayClock & 32) || (p.IsFrozen() && p.last_extra < 2)) + { + int s = -8; + if (hud_flashing && p.last_extra > Duke.MaxPlayerHealth()) + s += Raze.bsin(Raze.GetBuildTime() << 5) / 768; + int intens = clamp(255 - 6 * s, 0, 255); + format = String.Format("%d", p.last_extra); + DrawString(numberFont, format, (25, texty), DI_TEXT_ALIGN_LEFT, Font.CR_UNTRANSLATED, intens / 255., 0, 0); + } + + // + // Armor + // + img = TexMan.CheckForTexture("SHIELD"); + siz = TexMan.GetScaledSize(img); + imgScale = baseScale / siz.Y; + DrawTexture(img, (67.375, -1.5), DI_ITEM_LEFT_BOTTOM, scale:(imgScale, imgScale)); + + format = String.Format("%d", GetMoraleOrShield(p)); + DrawString(numberFont, format, (85, texty), DI_TEXT_ALIGN_LEFT, Font.CR_UNTRANSLATED, 1, 0, 0); + + // + // Weapon + // + int weapon = p.curr_weapon; + if (weapon == DukeWpn.HANDREMOTE_WEAPON) weapon = DukeWpn.HANDBOMB_WEAPON; + + let wicon = ammo_sprites[weapon]; + if (wicon.length() > 0) + { + int ammo = p.ammo_amount[weapon]; + if (weapon != DukeWpn.PISTOL_WEAPON || (weapon == DukeWpn.PISTOL_WEAPON && !cl_showmagamt)) + { + format = String.Format("%d", ammo); + } + else + { + int clip = CalcMagazineAmount(ammo, Raze.isNam() ? 20 : 12, p.kickback_pic >= 1); + format = String.Format("%d/%d", clip, ammo - clip); + } + img = TexMan.CheckForTexture(wicon, TexMan.TYPE_Any); + siz = TexMan.GetScaledSize(img); + imgScale = baseScale / siz.Y; + let imgX = 20.; + let strlen = format.length(); + + if (strlen > 1) + { + imgX += (imgX * 0.6) * (strlen - 1); + } + + if (weapon != DukeWpn.KNEE_WEAPON && (!hud_flashing || PlayClock & 32 || ammo > (Duke.MaxAmmoAmount(weapon) / 10))) + { + DrawString(numberFont, format, (-3, texty), DI_TEXT_ALIGN_RIGHT, Font.CR_UNTRANSLATED); + } + + DrawTexture(img, (-imgX, -1.5), DI_ITEM_RIGHT_BOTTOM, scale:(imgScale, imgScale)); + } + + // + // Selected inventory item + // + uint icon = p.inven_icon; + if (icon > 0) + { + int x = 128; + + if (icon < Duke.ICON_MAX) + { + img = TexMan.CheckForTexture(item_icons[icon], TexMan.TYPE_Any); + siz = TexMan.GetScaledSize(img); + imgScale = baseScale / siz.Y; + DrawTexture(img, (x, -1.5), DI_ITEM_LEFT_BOTTOM, scale:(imgScale, imgScale)); + } + + int percentv = getinvamount(p); + format = String.Format("%3d%%", percentv); + int color = percentv > 50 ? 11 : percentv > 25 ? 23 : 2; + DrawString(miniFont, format, (x + 36.5, -indxfont.mFont.GetHeight() + 0.5), DI_TEXT_ALIGN_RIGHT, pt:Translation.MakeID(Translation_Remap, color)); + + String text; + int pal; + [text, pal] = ontext(p); + if (text.length() > 0) DrawString(miniFont, text, (x + 36.5, -miniFont.mFont.GetHeight() - 9.5), DI_TEXT_ALIGN_RIGHT, pt:Translation.MakeID(Translation_Remap, pal)); + } + + // + // keys + // + if (p.got_access & 1) DrawImage("ACCESSCARD", (-12, -23.5), DI_ITEM_RIGHT, 1, (-1, -1), (0.5, 0.5), STYLE_Translucent, 0xffffffff, Translation.MakeID(Translation_Remap, 0)); + if (p.got_access & 4) DrawImage("ACCESSCARD", (-7 , -21.5), DI_ITEM_RIGHT, 1, (-1, -1), (0.5, 0.5), STYLE_Translucent, 0xffffffff, Translation.MakeID(Translation_Remap, 23)); + if (p.got_access & 2) DrawImage("ACCESSCARD", (-2 , -19.5), DI_ITEM_RIGHT, 1, (-1, -1), (0.5, 0.5), STYLE_Translucent, 0xffffffff, Translation.MakeID(Translation_Remap, 21)); + } + + + //========================================================================== + // + // Fullscreen HUD variant #2 + // + //========================================================================== + + void FullscreenHUD2(DukePlayer p) + { + // + // health + // + DrawImage("HEALTHBOX", (5, -2), DI_ITEM_LEFT_BOTTOM, scale:(scale, scale)); + int health = p.IsFrozen() ? 1 : p.last_extra; + String format = String.Format("%d", health); + DrawString(digiFont, format, (20, -digiFont.mFont.GetHeight() * scale - 3), DI_TEXT_ALIGN_CENTER, Font.CR_UNTRANSLATED, scale:(scale, scale)); + + // + // ammo + // + DrawImage("AMMOBOX", (37, -2), DI_ITEM_LEFT_BOTTOM, scale:(scale, scale)); + int wp = (p.curr_weapon == DukeWpn.HANDREMOTE_WEAPON) ? DukeWpn.HANDBOMB_WEAPON : p.curr_weapon; + format = String.Format("%d", p.ammo_amount[wp]); + DrawString(digiFont, format, (52, -digiFont.mFont.GetHeight() * scale - 3), DI_TEXT_ALIGN_CENTER, Font.CR_UNTRANSLATED, scale:(scale, scale)); + + // + // inventory + // + uint icon = p.inven_icon; + if (icon > 0) + { + int x = 73; + DrawImage("INVENTORYBOX", (69, -2), DI_ITEM_LEFT_BOTTOM, scale:(scale, scale)); + if (icon < Duke.ICON_MAX) + DrawImage(item_icons[icon], (x, -13.5), DI_ITEM_LEFT|DI_ITEM_VCENTER, scale:(scale, scale)); + + int percentv = getinvamount(p); + format = String.Format("%3d%%", percentv); + int color = percentv > 50 ? 11 : percentv > 25 ? 23 : 2; + DrawString(miniFont, format, (x + 34, -indxfont.mFont.GetHeight() - 3), DI_TEXT_ALIGN_RIGHT, pt:Translation.MakeID(Translation_Remap, color)); + + String text; + int pal; + [text, pal] = ontext(p); + if (text.length() > 0) DrawString(miniFont, text, (x + 34, -miniFont.mFont.GetHeight() - 14), DI_TEXT_ALIGN_RIGHT, pt:Translation.MakeID(Translation_Remap, pal)); + } + } + + //========================================================================== + // + // Fullscreen HUD drawer + // + //========================================================================== + + void DrawHud(DukePlayer p, int style, SummaryInfo info) + { + BeginHUD(1, false, 320, 200); + if (style == 1) + { + DrawInventory(p, 0, -46, DI_SCREEN_CENTER_BOTTOM); + FullscreenHUD1(p); + DoLevelStats(tileHeight("BIGALPHANUM") +10, info); + } + else if (style == 2) + { + DrawInventory(p, netgame ? 56 : 65, -28, DI_SCREEN_CENTER_BOTTOM); + FullscreenHUD2(p); + DoLevelStats(tileHeight("HEALTHBOX") + 4, info); + } + else + { + DrawInventory(p, 0, -28, DI_SCREEN_CENTER_BOTTOM); + DoLevelStats(2, info); + } + } + + + //========================================================================== + // + // Helper for weapon display + // + //========================================================================== + + void DrawWeaponNum(int index, double x, double y, int num1, int num2, int shade, int numdigits) + { + /* + if (isShareware() && (ind > DukeWpn.HANDBOMB_WEAPON || ind < 0)) + { + minitextshade(x + 1, y - 4, "ORDER", 20, 11, 2 + 8 + 16 + ROTATESPRITE_MAX); + return; + } + */ + String format; + bool parsedDivisor = false; + + if (numdigits == 2) + { + if (num1 > 99) num1 = 99; + if (num2 > 99) num2 = 99; + format = String.Format("%2d/%d", num1, num2); + } + else + { + if (num1 > 999) num1 = 999; + if (num2 > 999) num2 = 999; + format = String.Format("%3d/%d", num1, num2); + } + y--; + DrawTexture(ThreeByFive[index], (x - 7, y), DI_ITEM_LEFT|DI_ITEM_VCENTER, 1, (-1, -1), (1, 1), STYLE_Translucent, Raze.ShadeToLight(shade - 10), Translation.MakeID(Translation_Remap, 7)); + let pe = Raze.ShadeToLight(shade); + DrawTexture(ThreeByFive[10], (x - 3, y), DI_ITEM_LEFT | DI_ITEM_VCENTER, 1, (-1, -1), (1, 1), STYLE_Translucent, pe); + for (int i = 0; i < format.Length(); i++) + { + int cc = format.ByteAt(i); + if (cc != " ") + { + int c = cc == "/" ? 11 : cc - int("0"); + DrawTexture(ThreeByFive[c], (x + 4 * i + (parsedDivisor ? 1 : 0), y), DI_ITEM_LEFT | DI_ITEM_VCENTER, col:pe); + } + if (cc == "/") + { + parsedDivisor = true; + } + } + } + + //========================================================================== + // + // Weapon display (Duke only) + // + //========================================================================== + + int ShadeForWeapon(DukePlayer p, int weapon, int optweapon = -1) + { + // Headache-inducing math at play here. + return (((!p.ammo_amount[weapon]) | (!p.gotweapon[weapon])) * 9) + 12 - 18 * ((p.curr_weapon == weapon) || (optweapon != -1 && p.curr_weapon == optweapon)); + } + + + void DrawWeaponAmounts(DukePlayer p, double x, double y) + { + int cw = p.curr_weapon; + + DrawWeaponNum(2, x, y, p.ammo_amount[DukeWpn.PISTOL_WEAPON], Duke.MaxAmmoAmount(DukeWpn.PISTOL_WEAPON), 12 - 20 * (cw == DukeWpn.PISTOL_WEAPON), 3); + DrawWeaponNum(3, x, y + 6, p.ammo_amount[DukeWpn.SHOTGUN_WEAPON], Duke.MaxAmmoAmount(DukeWpn.SHOTGUN_WEAPON), ShadeForWeapon(p, DukeWpn.SHOTGUN_WEAPON), 3); + DrawWeaponNum(4, x, y + 12, p.ammo_amount[DukeWpn.CHAINGUN_WEAPON], Duke.MaxAmmoAmount(DukeWpn.CHAINGUN_WEAPON), ShadeForWeapon(p, DukeWpn.CHAINGUN_WEAPON), 3); + DrawWeaponNum(5, x + 39, y, p.ammo_amount[DukeWpn.RPG_WEAPON], Duke.MaxAmmoAmount(DukeWpn.RPG_WEAPON), ShadeForWeapon(p, DukeWpn.RPG_WEAPON), 2); + DrawWeaponNum(6, x + 39, y + 6, p.ammo_amount[DukeWpn.HANDBOMB_WEAPON], Duke.MaxAmmoAmount(DukeWpn.HANDBOMB_WEAPON), ShadeForWeapon(p, DukeWpn.HANDBOMB_WEAPON, DukeWpn.HANDREMOTE_WEAPON), 2); + if (p.subweapon & (1 << DukeWpn.GROW_WEAPON)) // original code says: if(!p.ammo_amount[SHRINKER_WEAPON] || cw == GROW_WEAPON) + DrawWeaponNum(7, x + 39, y + 12, p.ammo_amount[DukeWpn.GROW_WEAPON], Duke.MaxAmmoAmount(DukeWpn.GROW_WEAPON), ShadeForWeapon(p, DukeWpn.GROW_WEAPON), 2); + else + DrawWeaponNum(7, x + 39, y + 12, p.ammo_amount[DukeWpn.SHRINKER_WEAPON], Duke.MaxAmmoAmount(DukeWpn.SHRINKER_WEAPON), ShadeForWeapon(p, DukeWpn.SHRINKER_WEAPON), 2); + DrawWeaponNum(8, x + 70, y, p.ammo_amount[DukeWpn.DEVISTATOR_WEAPON], Duke.MaxAmmoAmount(DukeWpn.DEVISTATOR_WEAPON), ShadeForWeapon(p, DukeWpn.DEVISTATOR_WEAPON), 2); + DrawWeaponNum(9, x + 70, y + 6, p.ammo_amount[DukeWpn.TRIPBOMB_WEAPON], Duke.MaxAmmoAmount(DukeWpn.TRIPBOMB_WEAPON), ShadeForWeapon(p, DukeWpn.TRIPBOMB_WEAPON), 2); + DrawWeaponNum(0, x + 70, y + 12, p.ammo_amount[DukeWpn.FREEZE_WEAPON], Duke.MaxAmmoAmount(DukeWpn.FREEZE_WEAPON), ShadeForWeapon(p, DukeWpn.FREEZE_WEAPON), 2); + } + + //========================================================================== + // + // Status bar drawer + // + //========================================================================== + + void Statusbar(DukePlayer p) + { + let bsb = TexMan.CheckForTexture("BOTTOMSTATUSBAR", Texman.Type_Any); + let siz = TexMan.GetScaledSize(bsb); + int h = int(siz.Y); + int top = 200 - h; + int left = (320 - int(siz.X)) / 2; + BeginStatusBar(false, 320, 200, h); + DrawInventory(p, 160, 154, 0); + if (hud_size == Hud_StbarOverlay) Set43ClipRect(); + DrawTexture(bsb, (left, top), DI_ITEM_LEFT_TOP, 1); + screen.ClearClipRect(); + + String format; + + /* + if (ud.multimode > 1 && !ud.coop) + { + DrawTexture("KILLSICON", (228, top + 8), DI_ITEM_OFFSETS, 1, 0, 0); + format = String.Format("%d", max(p.frag - p.fraggedself, 0)); + DrawString(digiFont, format, (287, top + 17), DI_TEXT_ALIGN_CENTER); + } + else*/ + { + let key = TexMan.CheckForTexture("ACCESS_ICON", TexMan.Type_Any); + if (p.got_access & 4) DrawTexture(key, (275.5, top + 16), DI_ITEM_OFFSETS, style:STYLE_Translucent, translation:Translation.MakeID(Translation_Remap, 23)); + if (p.got_access & 2) DrawTexture(key, (288.5, top + 16), DI_ITEM_OFFSETS, style:STYLE_Translucent, translation:Translation.MakeID(Translation_Remap, 21)); + if (p.got_access & 1) DrawTexture(key, (282, top + 23), DI_ITEM_OFFSETS, style:STYLE_Translucent, translation:Translation.MakeID(Translation_Remap, 0)); + } + DrawWeaponAmounts(p, 96, top + 15.5); + + int num = (p.IsFrozen()) ? 1 : p.last_extra; + format = String.Format("%d", num); + DrawString(digiFont, format, (31, top + 17), DI_TEXT_ALIGN_CENTER); + format = String.Format("%d", GetMoraleOrShield(p)); + DrawString(digiFont, format, (63, top + 17), DI_TEXT_ALIGN_CENTER); + + if (p.curr_weapon != DukeWpn.KNEE_WEAPON) + { + int wep = (p.curr_weapon == DukeWpn.HANDREMOTE_WEAPON)? DukeWpn.HANDBOMB_WEAPON : p.curr_weapon; + format = String.Format("%d", p.ammo_amount[wep]); + DrawString(digiFont, format, (207, top + 17), DI_TEXT_ALIGN_CENTER); + } + + int icon = p.inven_icon; + if (icon) + { + int x = 232; + if (icon < Duke.ICON_MAX) + DrawImage(item_icons[icon], (x, top + 20.5), DI_ITEM_LEFT | DI_ITEM_VCENTER); + + int percentv = getinvamount(p); + format = String.Format("%3d%%", percentv); + int color = percentv > 50 ? 11 : percentv > 25 ? 23 : 2; + DrawString(miniFont, format, (x + 34, top + 24), DI_TEXT_ALIGN_RIGHT, Font.CR_UNDEFINED, 1, 0, 0, (1, 1), Translation.MakeID(Translation_Remap, color)); + + String text; + int pal; + [text, pal] = ontext(p); + if (text.length() > 0) DrawString(miniFont, text, (x + 34, top + 14), DI_TEXT_ALIGN_RIGHT, Font.CR_UNDEFINED, 1, 0, 0, (1, 1), Translation.MakeID(Translation_Remap, pal)); + } + } + + override void UpdateStatusBar(SummaryInfo info) + { + let p = Duke.GetViewPlayer(); + if (hud_size >= Hud_Mini) + { + DrawHud(p, hud_size == Hud_Nothing ? 0 : hud_size == Hud_full ? 1 : 2, info); + } + else + { + Statusbar(p); + DoLevelStats(-1, info); + } + } +} diff --git a/wadsrc/static/zscript/games/duke/ui/sbar_r.zs b/wadsrc/static/zscript/games/duke/ui/sbar_r.zs new file mode 100644 index 00000000000..d033f051f5e --- /dev/null +++ b/wadsrc/static/zscript/games/duke/ui/sbar_r.zs @@ -0,0 +1,448 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment +Copyright (C) 2020 - Christoph Oelckers + +This file is part of Enhanced Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms + +*/ +//------------------------------------------------------------------------- + + +class RedneckStatusBar : DukeCommonStatusBar +{ + override void Init() + { + numberFont = HudFont.Create(BigFont, 0, Mono_Off, 1, 1 ); + miniFont = HudFont.Create(SmallFont2, 0, Mono_Off, 1, 1 ); + digiFont = HudFont.Create(Font.FindFont("DigiFont"), 2, Mono_Off, 1, 1 ); + + // optionally draw at the top of the screen. + SetSize(tileHeight("BOTTOMSTATUSBAR"), 320, 200); + scale = 0.5; + + ammo_sprites.PushV("", "AMMO", "SHOTGUNAMMO", "BATTERYAMMO", "HBOMBAMMO", "HBOMBAMMO", "SAWAMMO", "DEVISTATORAMMO", + "TRIPBOMBSPRITE", "GROWSPRITEICON", "HBOMBAMMO", "", "BOWLINGBALLSPRITE", "MOTOAMMO", "BOATAMMO", "", "RPG2SPRITE"); + item_icons.PushV("", "FIRSTAID_ICON", "STEROIDS_ICON", "HOLODUKE_ICON", "JETPACK_ICON", "HEAT_ICON", "AIRTANK_ICON", "BOOT_ICON" ); + } + + + int getinvamount(DukePlayer p) + { + switch (p.inven_icon) + { + case Duke.ICON_FIRSTAID: + return p.firstaid_amount; + case Duke.ICON_STEROIDS: + return (p.steroids_amount + 3) >> 2; + case Duke.ICON_HOLODUKE: + return (p.holoduke_amount) / 400; + case Duke.ICON_JETPACK: + return (p.jetpack_amount) / 100; + case Duke.ICON_HEATS: + return p.heat_amount / 12; + case Duke.ICON_SCUBA: + return (p.scuba_amount + 63) >> 6; + case Duke.ICON_BOOTS: + return (p.boot_amount / 10) >> 1; + } + + return -1; + } + + + //========================================================================== + // + // Fullscreen HUD variant #1 for RR + // + //========================================================================== + + void FullscreenHUD1(DukePlayer p) + { + String format; + TextureID img; + double imgScale; + double baseScale = (scale * numberFont.mFont.GetHeight()) * 0.76; + + // + // Health + // + img = TexMan.CheckForTexture("SPINNINGNUKEICON1"); + let siz = TexMan.GetScaledSize(img); + imgScale = baseScale / siz.Y; + DrawTexture(img, (2, -2), DI_ITEM_LEFT_BOTTOM, scale:(imgScale, imgScale)); + + if (!hud_flashing || p.last_extra > (Duke.MaxPlayerHealth() >> 2) || (PlayClock & 32) || (p.IsFrozen() && p.last_extra < 2)) + { + int s = -8; + if (hud_flashing && p.last_extra > Duke.MaxPlayerHealth()) + s += Raze.bsin(Raze.GetBuildTime() << 5) / 768; + int intens = clamp(255 - 6 * s, 0, 255); + format = String.Format("%d", p.last_extra); + DrawString(numberFont, format, (26.5, -numberFont.mFont.GetHeight() * scale + 4), DI_TEXT_ALIGN_LEFT, Font.CR_UNTRANSLATED, intens / 255., 0, 0, (scale, scale)); + } + + // + // drink + // + img = TexMan.CheckForTexture("BEER"); + siz = TexMan.GetScaledSize(img); + imgScale = baseScale / siz.Y; + DrawTexture(img, (74, -2), DI_ITEM_LEFT_BOTTOM, scale:(imgScale, imgScale)); + format = String.Format("%d", p.drink_amt); + DrawString(numberFont, format, (86, -numberFont.mFont.GetHeight() * scale + 4), DI_TEXT_ALIGN_LEFT, scale:(scale, scale)); + + // + // eat + // + img = TexMan.CheckForTexture("COWPIE"); + siz = TexMan.GetScaledSize(img); + imgScale = baseScale / siz.Y; + DrawTexture(img, (133.5, -2), DI_ITEM_LEFT_BOTTOM, scale:(imgScale, imgScale)); + format = String.Format("%d", p.eat); + DrawString(numberFont, format, (173, -numberFont.mFont.GetHeight() * scale + 4), DI_TEXT_ALIGN_LEFT, scale:(scale, scale)); + + // + // selected weapon + // + int weapon = p.curr_weapon; + if (weapon == RRWpn.THROWINGDYNAMITE_WEAPON) weapon = RRWpn.DYNAMITE_WEAPON; + + let wicon = ammo_sprites[weapon]; + if (wicon.length() > 0) + { + int ammo = p.ammo_amount[weapon]; + bool reloadableWeapon = weapon == RRWpn.PISTOL_WEAPON || weapon == RRWpn.SHOTGUN_WEAPON; + if (!reloadableWeapon || (reloadableWeapon && !cl_showmagamt)) + { + format = String.Format("%d", ammo); + } + else + { + int clip; + switch (weapon) + { + case RRWpn.PISTOL_WEAPON: + clip = CalcMagazineAmount(ammo, 6, p.kickback_pic >= 1); + break; + case RRWpn.SHOTGUN_WEAPON: + clip = CalcMagazineAmount(ammo, 2, p.kickback_pic >= 4); + break; + } + format = String.Format("%d/%d", clip, ammo - clip); + } + img = TexMan.CheckForTexture(wicon, TexMan.TYPE_Any); + siz = TexMan.GetScaledSize(img); + imgScale = baseScale / siz.Y; + let imgX = 22.5; + let strlen = format.Length(); + + if (strlen > 1) + { + imgX += (imgX * 0.755) * (strlen - 1); + } + + if (weapon != RRWpn.KNEE_WEAPON && weapon != RRWpn.SLINGBLADE_WEAPON && (!hud_flashing || PlayClock & 32 || ammo > (Duke.MaxAmmoAmount(weapon) / 10))) + { + DrawString(numberFont, format, (-1, -numberFont.mFont.GetHeight() * scale + 4), DI_TEXT_ALIGN_RIGHT, scale:(scale, scale)); + } + + DrawTexture(img, (-imgX, -2), DI_ITEM_RIGHT_BOTTOM, scale:(imgScale, imgScale)); + } + + // + // Selected inventory item + // + uint icon = p.inven_icon; + if (icon > 0) + { + int x = -130; + + if (icon < Duke.ICON_MAX) + { + img = TexMan.CheckForTexture(item_icons[icon], TexMan.TYPE_Any); + siz = TexMan.GetScaledSize(img); + imgScale = baseScale / siz.Y; + DrawTexture(img, (x, -2), DI_ITEM_RIGHT_BOTTOM, scale:(imgScale, imgScale)); + } + + int percentv = getinvamount(p); + if (icon <= 2) format = String.Format("%d%%", percentv); + else format = String.Format("%d", percentv); + DrawString(miniFont, format, (x + 19, -miniFont.mFont.GetHeight() * scale - 1), DI_TEXT_ALIGN_RIGHT, scale:(scale, scale)); + + let text = ontext(p); + if (text.length() > 0) DrawString(miniFont, text, (x + 20, -miniFont.mFont.GetHeight() * scale - 15), DI_TEXT_ALIGN_RIGHT, scale:(scale, scale)); + } + + // + // keys + // + if (p.keys[1]) DrawImage("ACCESSCARD", (-28.5, -32 ), DI_ITEM_BOTTOM, 1, (-1, -1), (scale, scale), STYLE_Translucent, 0xffffffff, Translation.MakeID(Translation_Remap, 0)); + if (p.keys[3]) DrawImage("ACCESSCARD", (-21.25, -28.375), DI_ITEM_BOTTOM, 1, (-1, -1), (scale, scale), STYLE_Translucent, 0xffffffff, Translation.MakeID(Translation_Remap, 23)); + if (p.keys[2]) DrawImage("ACCESSCARD", (-14, -24.75 ), DI_ITEM_BOTTOM, 1, (-1, -1), (scale, scale), STYLE_Translucent, 0xffffffff, Translation.MakeID(Translation_Remap, 21)); + } + + + //========================================================================== + // + // Fullscreen HUD variant #2 for RR + // + //========================================================================== + + void FullscreenHUD2(DukePlayer p) + { + // + // health + // + DrawImage("HEALTHBOX", (2, -2), DI_ITEM_LEFT_BOTTOM, scale:(scale, scale)); + int health = p.IsFrozen() ? 1 : p.last_extra; + String format = String.Format("%d", health); + DrawString(digiFont, format, (21.5, -digiFont.mFont.GetHeight() * scale - 5.5), DI_TEXT_ALIGN_CENTER, scale:(scale, scale)); + + // + // ammo + // + DrawImage("AMMOBOX", (37, -2), DI_ITEM_LEFT_BOTTOM, scale:(scale, scale)); + int wp = p.curr_weapon == RRWpn.THROWINGDYNAMITE_WEAPON? RRWpn.DYNAMITE_WEAPON : p.curr_weapon; + format = String.Format("%d", p.ammo_amount[wp]); + DrawString(digiFont, format, (60.25, -digiFont.mFont.GetHeight() * scale - 5.5), DI_TEXT_ALIGN_CENTER, scale:(scale, scale)); + + // + // inventory + // + uint icon = p.inven_icon; + if (icon > 0) + { + int x = 84; + DrawImage("INVENTORYBOX", (69, -2), DI_ITEM_LEFT_BOTTOM, scale:(scale, scale)); + if (icon < Duke.ICON_MAX) + DrawImage(item_icons[icon], (x, -15.375), DI_ITEM_LEFT|DI_ITEM_VCENTER, scale:(scale, scale)); + + int percentv = getinvamount(p); + if (icon <= 2) format = String.Format("%d%%", percentv); + else format = String.Format("%d", percentv); + DrawString(miniFont, format, (x + 31.5, -miniFont.mFont.GetHeight() * scale - 6.5), DI_TEXT_ALIGN_RIGHT, scale:(scale, scale)); + } + } + + //========================================================================== + // + // Fullscreen HUD drawer + // + //========================================================================== + + void DrawHud(DukePlayer p, int style, SummaryInfo info) + { + BeginHUD(320, 200, 1.f); + if (style == 1) + { + double y = -40; + //if (ud.multimode > 1) y -= 4; + //if (ud.multimode > 4) y -= 4; + DrawInventory(p, 0, y, DI_SCREEN_CENTER_BOTTOM); + FullscreenHUD1(p); + DoLevelStats(int(scale * tileHeight("BIGALPHANUM") + 10), info); + } + else if (style == 2) + { + DrawInventory(p, 56, -20, DI_SCREEN_CENTER_BOTTOM); + FullscreenHUD2(p); + DoLevelStats(int(scale * tileHeight("HEALTHBOX") + 4), info); + } + else + { + DrawInventory(p, 0, -20, DI_SCREEN_CENTER_BOTTOM); + DoLevelStats(2, info); + } + } + + //========================================================================== + // + // Status bar drawer (RR) + // + //========================================================================== + + void DrawWeaponBar(DukePlayer p, int top) + { + double sbscale = 32800. / 65536.; + + DrawImage("WEAPONBAR", (0, 158), DI_ITEM_OFFSETS, scale:(sbscale, sbscale)); + + for (int i = 0; i < 9; i++) + { + String format, texname; + + if ((gameinfo.gameType & GAMEFLAG_RRRA) && i == 4 && p.curr_weapon == RRWpn.CHICKEN_WEAPON) + { + texname = "AMMO_ICON10"; + format = String.Format("%d", p.ammo_amount[RRWpn.CHICKEN_WEAPON]); + } + else + { + if (p.gotweapon[i+1]) + { + texname = "AMMO_ICON" .. i; + format = String.Format("%d", p.ammo_amount[i+1]); + } + } + + DrawImage(texname, (18 + i * 32, top - 6.5), DI_ITEM_OFFSETS, scale:(sbscale, sbscale)); + + if (format.Length()) + { + DrawString(miniFont, format, (38 + i * 32, 162.75 - miniFont.mFont.GetHeight() * scale * 0.5), DI_TEXT_ALIGN_CENTER, scale:(scale * .875, scale * .875)); + } + } + } + + + //========================================================================== + // + // Status bar drawer (RR) + // + //========================================================================== + + void Statusbar(DukePlayer p) + { + let bsb = TexMan.CheckForTexture("BOTTOMSTATUSBAR", Texman.Type_Any); + let siz = TexMan.GetScaledSize(bsb); + + double wh = 0; + if (hud_size < Hud_Stbar) wh = tileHeight("WEAPONBAR") * scale; + + double h = siz.Y; + double top = 200 - h; + int left = (320 - int(siz.X)) / 2; + BeginStatusBar(false, 320, 200, int(wh + h)); + DrawInventory(p, 160, hud_size <= Hud_Stbar? 148 : 154, 0); + + if (hud_size <= Hud_Stbar) + DrawWeaponBar(p, int(top)); + + if (hud_size == Hud_StbarOverlay) Set43ClipRect(); + DrawTexture(bsb, (left, top), DI_ITEM_LEFT_TOP, scale:(scale, scale)); + screen.ClearClipRect(); + + String format; + + /* + if (ud.multimode > 1 && !ud.coop) + { + DrawTexture("KILLSICON", (228, top + 8), DI_ITEM_OFFSETS, 1, 0, 0); + format = String.Format("%d", max(p.frag - p.fraggedself, 0)); + DrawString(digiFont, format, (287, top + 17), DI_TEXT_ALIGN_CENTER, Font.CR_UNTRANSLATED, 1, 0, 0, (scale, scale)); + } + else*/ + { + let key = TexMan.CheckForTexture("ACCESS_ICON", TexMan.Type_Any); + if (p.keys[3]) DrawTexture(key, (138, top + 13), DI_ITEM_OFFSETS, 1, (-1, -1), (scale, scale), STYLE_Translucent, 0xffffffff, Translation.MakeID(Translation_Remap, 23)); + if (p.keys[2]) DrawTexture(key, (152, top + 13), DI_ITEM_OFFSETS, 1, (-1, -1), (scale, scale), STYLE_Translucent, 0xffffffff, Translation.MakeID(Translation_Remap, 21)); + if (p.keys[1]) DrawTexture(key, (145, top + 21), DI_ITEM_OFFSETS, 1, (-1, -1), (scale, scale), STYLE_Translucent, 0xffffffff, Translation.MakeID(Translation_Remap, 0)); + } + + int num = (p.IsFrozen()) ? 1 : p.last_extra; + format = String.Format("%d", num); + DrawString(digiFont, format, (66.5, top + 16), DI_TEXT_ALIGN_CENTER, scale:(scale, scale)); + + if (p.curr_weapon != RRWpn.KNEE_WEAPON) + { + int wep = (p.curr_weapon == RRWpn.THROWINGDYNAMITE_WEAPON) ? RRWpn.DYNAMITE_WEAPON : p.curr_weapon; + format = String.Format("%d", p.ammo_amount[wep]); + DrawString(digiFont, format, (110, top + 16), DI_TEXT_ALIGN_CENTER, scale:(scale, scale)); + } + + int icon = p.inven_icon; + if (icon) + { + int x = 182; + if (icon < Duke.ICON_MAX) + DrawImage(item_icons[icon], (x, top + 20.125), DI_ITEM_LEFT | DI_ITEM_VCENTER, scale:(scale, scale)); + + int percentv = getinvamount(p); + if (icon <= 2) format = String.Format("%d%%", percentv); + else format = String.Format("%d", percentv); + DrawString(miniFont, format, (x + 38, top + 23.5), DI_TEXT_ALIGN_RIGHT, scale:(scale, scale)); + + if (p.inven_icon == Duke.ICON_SCUBA || p.inven_icon == Duke.ICON_BOOTS) + DrawString(miniFont, "AUTO", (x + 39, top + 13), DI_TEXT_ALIGN_RIGHT, scale:(scale, scale)); + } + + p.drunkang = ((p.drink_amt * 8) + 1647) & 2047; + if (p.drink_amt >= 100) + { + p.drink_amt = 100; + p.drunkang = 400; + } + + DrawImageRotated("GUTMETER", (256, top + 15), DI_ITEM_RELCENTER, p.drunkang * -Raze.BAngToDegree, 1, (scale, scale), 0xffffffff, 0); + DrawImageRotated("GUTMETER", (292, top + 15), DI_ITEM_RELCENTER, p.eatang * -Raze.BAngToDegree, 1, (scale, scale), 0xffffffff, 0); + + if (p.drink_amt >= 0 && p.drink_amt <= 30) + { + DrawImage("GUTMETER_LIGHT1", (239, top + 24), DI_ITEM_OFFSETS, scale:(scale, scale)); + } + else if (p.drink_amt >= 31 && p.drink_amt <= 65) + { + DrawImage("GUTMETER_LIGHT2", (248, top + 24), DI_ITEM_OFFSETS, scale:(scale, scale)); + } + else if (p.drink_amt >= 66 && p.drink_amt <= 87) + { + DrawImage("GUTMETER_LIGHT3", (256, top + 24), DI_ITEM_OFFSETS, scale:(scale, scale)); + } + else + { + DrawImage("GUTMETER_LIGHT4", (265, top + 24), DI_ITEM_OFFSETS, scale:(scale, scale)); + } + + if (p.eat >= 0 && p.eat <= 30) + { + DrawImage("GUTMETER_LIGHT1", (276, top + 24), DI_ITEM_OFFSETS, scale:(scale, scale)); + } + else if (p.eat >= 31 && p.eat <= 65) + { + DrawImage("GUTMETER_LIGHT2", (285, top + 24), DI_ITEM_OFFSETS, scale:(scale, scale)); + } + else if (p.eat >= 66 && p.eat <= 87) + { + DrawImage("GUTMETER_LIGHT3", (294, top + 24), DI_ITEM_OFFSETS, scale:(scale, scale)); + } + else + { + DrawImage("GUTMETER_LIGHT4", (302, top + 24), DI_ITEM_OFFSETS, scale:(scale, scale)); + } + } + + override void UpdateStatusBar(SummaryInfo info) + { + let p = Duke.GetViewPlayer(); + if (hud_size >= Hud_Mini) + { + DrawHud(p, hud_size == Hud_Nothing ? 0 : hud_size == Hud_full ? 1 : 2, info); + } + else + { + Statusbar(p); + DoLevelStats(-1, info); + } + } + +} diff --git a/wadsrc/static/zscript/razebase.zs b/wadsrc/static/zscript/razebase.zs index 5eaffef1a4e..ef9f29201cf 100644 --- a/wadsrc/static/zscript/razebase.zs +++ b/wadsrc/static/zscript/razebase.zs @@ -135,6 +135,7 @@ struct SummaryInfo native struct Raze { const kAngleMask = 0x7FF; + const BAngToDegree = 360. / 2048.; static int calcSinTableValue(int ang) { @@ -150,6 +151,8 @@ struct Raze native static double GetTimeFrac(); native static int bsin(int angle, int shift = 0); native static int bcos(int angle, int shift = 0); + native static TextureID PickTexture(TextureID texid); + native static int GetBuildTime(); static bool specialKeyEvent(InputEvent ev) { @@ -247,13 +250,13 @@ class BaseStatusBar : StatusBarCore native {} -class DukeCommonStatusBar : BaseStatusBar native +class NativeDukeCommonStatusBar : BaseStatusBar native {} -class DukeStatusBar : DukeCommonStatusBar native +class NativeDukeStatusBar : NativeDukeCommonStatusBar native {} -class RedneckStatusBar : DukeCommonStatusBar native +class NativeRedneckStatusBar : NativeDukeCommonStatusBar native {} class SWStatusBar : BaseStatusBar native