diff --git a/README.md b/README.md index 50abebf..e217919 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,28 @@ # zUtilities -This is a simple plugin made in [Union](https://worldofplayers.ru/threads/40376/) **1.0l** for Gothic 1 and 2. +This is a plugin with a set of many quality-of-life and utility features made for [Union](https://worldofplayers.ru/threads/40376/) **1.0m** for Gothic 1 and 2 games. Plugin can also be found on [Steam Workshop](https://steamcommunity.com/sharedfiles/filedetails/?id=2792434617). ### Features -- Allows to quickly save / load game with `F10` and `F12` keys. +> Plugin options can be changed in `gothic.ini`. +> Some of the options can also be changed via ingame menu. (Requires Union 1.0m or higher.) + +- Quickly save / load game with `F10` and `F12` keys. + + - Shortcuts can be changed with `KeyQuickSave` and `KeyQuickLoad` options. A full list of available keys to choose from is [there](https://github.com/Franisz/zUtilities/blob/master/zUtilities/KeyCode.h). - Range of save slots used for quick save can be adjusted in `gothic.ini` with `MinSaveSlot`, `MaxSaveSlot` options. Default, it's 6 bottom slots. - Notice strings are set automatically depending on system language but still can be changed manually in `gothic.ini` with `CantSave`, `CantLoad` and `NoSave` options. - - This feature can be disabled in `gothic.ini` with `UseQuickSave` option. + - This feature can be disabled in `gothic.ini` with `QuickSaveMode` option. + - Change `QuickSaveMode` option for different style or disable: `0` - _Disabled_, `1` - _Standard_, `2` - _Alternative_. - Changes name color of focused npcs, containers, doors and items. - Npcs: `Red` - hostile / wants to kill you, `Orange` - angry / pissed off, `Cyan` - partymember, `Green` - friendly, `Slightly green` - friendly guild, `White` - neutral / dead, `Grey` - dead and looted. - - Doors: `Red` - locked on key, `Orange` - locked, `White` - open. - - Containers: `Red` - locked on key, `Orange` - locked, `Green` - open with items, `Grey` - open and empty. + - Lockables: `Red` - locked on key, `Orange` - locked, `Light red` - can be opened with a key or lockpick, `Green` - open with items, `Grey` - permanently closed or opened and empty. - Items: `White` - default / item can be taken, `Slightly orange` - someone will catch the hero stealing. - - Each group can be disabled separately in `gothic.ini` with `ColorNpcs`, `ColorChests`, `ColorDoors` and `ColorItems` options. + - Intractable book stands: `Green` - unread, `White` - default / read. + - Each group can be disabled separately in `gothic.ini` with `ColorNpcs`, `ColorLockables`, `ColorItems` and `ColorInter` options. - Renders the selected inventory item in the center of the screen instead of in the item description box. @@ -39,14 +45,88 @@ This is a simple plugin made in [Union](https://worldofplayers.ru/threads/40376/ - This feature is inspired by [New World](https://www.newworld.com/)'s damage label and based on [AlterDamage](https://github.com/UnresolvedExternal/Union_AlterDamage) popup code. - Set `DamagePopupMode` option to `1` for _Alter Damage_ style, `2` for _New World_ style and `0` to disable this feature completely. - Popup scale depends on the amount of damage dealt compared to the target's max hp, the fact if the hit was critical or not and `Scale` option from `SystemPack.ini`. Base scale can also be adjusted in `gothic.ini` with `DamagePopupScale`. - - Icons and base colors are unique for every damage type and each can be separately disabled in `gothic.ini` with `DamagePopupShowIcons` and,`DamagePopupColorDmgTypes`options. + - Icons and base colors are unique for every damage type and each can be separately disabled in `gothic.ini` with `DamagePopupShowIcons` and, `DamagePopupColorDmgTypes` options. - By default the number has the same color as the icon, but it can be disabled in `gothic.ini` with `DamagePopupColorOnlyIcon` option. +- Adds few features for status bars. + + - Focused npc hp bar is displayed right above his name. This can be disabled with `ShowEnemyBarAboveHim` option. + - Added option to show numeric values of status bars. Change `StatusBarValueMode` option for different style or disable: `0` - _Disabled_, `1` - _Above_, `2` - _PointToCenter_, `3` - _Inside_. By default, option to show value above bar is active. + - Optionally, text labels can be set to be displayed right next to the bar value. Set `StatusBarNames` like so: `Health|Mana|Stamina`. Leave empty and no text will appear. + - Health, mana and swim status bars position can be changed with `HealthBarPos`, `ManaBarPos` and `SwimBarPos` options. + - Four positions need to be defined in a form `x1|y1|x2|y2` that reflects a virtual position in `0|0|8192|8192` scope. + - Default health bar position for systempack `Scale=1` is: `43|7873|1122|8085` and for `Scale=0`: `43|7964|811|8116` + - Default mana bar position for systempack `Scale=1` is: `7053|7873|8132|8085` and for `Scale=0`: `7381|7964|8149|8116` + - Default swim bar position for systempack `Scale=1` is: `3556|7873|4635|8085` and for `Scale=0`: `3712|7964|4480|8116` + - Leave options empty to use default positions. + +- Allows to change world speed multiplier. + + - This feature is completely disabled by default and can be enabled with `UseTimeMultiplier` option. + - Time multipliers can be changed with `TimeMultipliers` option like so: `0.65|1.0|2.7|3.5`. + - World speed will cycle in the order of set multipliers after pressing `Z`. Shortcut can also be changed with `KeyTimeMultiplier` option. + - Currently used multiplier will be shown next to the time icon. + +- Displays protection icon and value next to the focused npc hp bar. + + - This feature can be disabled in `gothic.ini` with `ShowTargetProtection` option. + +- Displays coin icon next to the focused npc name if player can pickpocket him. + + - This feature can be disabled in `gothic.ini` with `ShowPickpocketIcon` option. + - Works in G2/G2A only. + +- Changes color of log entry titles in player's log book. + + - New log entries will appear green and updated ones will be orange. + - This feature can be disabled in `gothic.ini` with `LogBookColoring` option. + +- Allows to change color of selected text line in dialogues with `SelectedDialogueColor` option. + + - Enter any color in `R|G|B` or `R|G|B|A` format, e.g.: `30|200|60|255` + - Leave option empty to keep using default color. + +- Allows to use alternative way of opening locks with lockpicks. + + - Essentially, the combination doesn't reset after fail. The player can keep going forward without the need to reenter the already discovered combination over again after every fail. + - This is disabled by default and can be enabled with `RememberLockCombination` option. + +- Allows to display current in game time. + + - This is disabled by default and can be enabled with `ShowGameTime` option. + +- Allows to display currently used munition amount. + + - This is disabled by default and can be enabled with `ShowMunitionAmount` option. + - Allows killing meatbugs by stepping on them. - This feature can be disabled in `gothic.ini` with `TrampleMeatbugs` option. -- Allows to check currently used plugin version through in game console with `zutilities version` command. +- Highlights munition used by currently equipped ranged weapon. + + - This feature can be disabled in `gothic.ini` with `ActivateUsedMunition` option. + +- Displays on the status bars how much hovered item will heal. + + - Heal value is based on the `count` value of the item associated with the `text` that is equal to the original recovery string variables `NAME_BONUS_HP` and `NAME_BONUS_MANA`. + - This feature can be disabled in `gothic.ini` with `RecoveryVisualization` option. + +- Allows to use alternative dialogue boxes when talking. + + - This is disabled by default and can be enabled with `AlternativeDialogueBoxes` option. + +- Display debug info data about focused vob or selected in the inventory item. + + - Use `zutilities debug` command to toggle on/off. + +- Insert all items into inventory with `zutilities giveallitems` command. + +- Check currently used plugin version through in game console with `zutilities version` command. + +- Reminds the player to save the game by displaying an icon with a timer after playing without saving the game for too long. + - By default, it reminds the player after 5 minutes since the last save game. It can be changed in `gothic.ini` with `SaveReminder` option. + - It can be turned off by setting `SaveReminder` to `-1` ### Options @@ -61,8 +141,84 @@ TrampleMeatbugs=1 CenterInvItems=1 ; ... enables (1) or disables (0) inventory item rendering in the center of the screen instead of the item description box -UseQuickSave=1 -; ... enables (1) or disables (0) QuickSaving with [F10] and QuickLoading with [F12] +RememberLockCombination=0 +; ... enables (1) or disables (0) alternative way of opening locks, where discovered combination doesn't reset after fail + +ActivateUsedMunition=1 +; ... enables (1) or disables (0) highlighting currently used ranged weapon munition in the inventory + +AlternativeDialogueBoxes=0 +; ... enables (1) or disables (0) alternative dialogue boxes style + +SelectedDialogueColor= +; ... defines color of selected line in dialogues +; ... use 'R|G|B' or 'R|G|B|A' format +; ... leave empty to use default color + +LogBookColoring=1 +; ... enables (1) or disables (0) coloring of new and unread topics in logbook + +ShowGameTime=0 +; ... enables (1) or disables (0) on screen display of in game time + +ShowMunitionAmount=0 +; ... enables (1) or disables (0) on screen display of currently used munition amount + +ShowTargetProtection=1 +; ... enables (1) or disables (0) protection icon and value next to the focused npc hp bar + +ShowPickpocketIcon=1 +; ... enables (1) or disables (0) coin icon next to the focused npc name when it can be pickpocketed + +UseTimeMultiplier=0 +; ... enables (1) or disables (0) time speed multiplier + +KeyTimeMultiplier=KEY_Z +; ... key for cycling time speed + +TimeMultipliers=1.0|2.5 +; ... defines time multipliers + +SaveReminder=5 +; ... Time in minutes after which the reminder to save the game appears on the screen +; ... set to -1 to disable + +RecoveryVisualization=1 +; ... enables (1) or disables (0) visualization of healing that hovered in the inventory item gives + +StatusBarValueMode=1 +; ... specifies mode of showing status bar value, (0) - 'Disabled', (1) - 'Above', (2) - 'PointToCenter', (3) - 'Inside' + +ShowEnemyBarAboveHim=1 +; ... enables (1) or disables (0) showing enemy hp bar above his head + +StatusBarNames= +; ... defines text label for status bars like so: 'Health|Mana|Stamina', leave empty if text is unwanted + +HealthBarPos= +; ... defines position of health bar like so: 'x1|y1|x2|y2' +; ... default position for scale 1 is: '43|7873|1122|8085' and for scale 0: '43|7964|811|8116' +; ... leave empty to use default position + +ManaBarPos= +; ... defines position of mana bar like so: 'x1|y1|x2|y2' +; ... default position for scale 1 is: '7053|7873|8132|8085' and for scale 0: '7381|7964|8149|8116' +; ... leave empty to use default position + +SwimBarPos= +; ... defines position of swim bar like so: 'x1|y1|x2|y2' +; ... default position for scale 1 is: '3556|7873|4635|8085' and for scale 0: '3712|7964|4480|8116' +; ... leave empty to use default position + +QuickSaveMode=1 +; ... specifies QuickSave mode, (0) - 'Disabled', (1) - 'Standard', (2) - 'Alternative' +; ... QuickSave with [F10] and QuickLoad with [F12] + +KeyQuickSave=KEY_F10 +; ... key for QuickSave + +KeyQuickLoad=KEY_F12 +; ... key for QuickLoad MinSaveSlot=15 ; ... defines min range of used save slots @@ -83,16 +239,16 @@ SaveName=QuickSave ; ... name used for quicksaves ColorNpcs=1 -; ... enables (1) or disables (0) coloring of focused Npcs - -ColorChests=1 -; ... enables (1) or disables (0) coloring of focused Chests +; ... enables (1) or disables (0) coloring of focused npcs -ColorDoors=1 -; ... enables (1) or disables (0) coloring of focused Doors +ColorLockables=1 +; ... enables (1) or disables (0) coloring of focused chests, doors and other lockables ColorItems=1 -; ... enables (1) or disables (0) coloring of focused Items +; ... enables (1) or disables (0) coloring of focused items + +ColorInter=1 +; ... enables (1) or disables (0) coloring of interactive bookstands LabelItems=1 ; ... enables (1) or disables (0) inventory item labeling @@ -107,7 +263,7 @@ PutLabelBehind=0 ; ... specifies if the label should be rendered behind the item DamagePopupMode=1 -; ... specifies DamagePopup mode, (0) - Disabled, (1) - 'Alter Damage', (2) - 'New World' +; ... specifies DamagePopup mode, (0) - 'Disabled', (1) - 'Alter Damage', (2) - 'New World' DamagePopupScale=1.10000002 ; ... defines base scale of the popup diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_VALUABLES-C.TEX b/_WORK/DATA/TEXTURES/_COMPILED/LABEL_VALUABLES-C.TEX deleted file mode 100644 index 4804737..0000000 Binary files a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_VALUABLES-C.TEX and /dev/null differ diff --git a/vdf-include/SYSTEM/AUTORUN/ZUTILITIES.D b/vdf-include/SYSTEM/AUTORUN/ZUTILITIES.D new file mode 100644 index 0000000..f744692 --- /dev/null +++ b/vdf-include/SYSTEM/AUTORUN/ZUTILITIES.D @@ -0,0 +1,808 @@ +META +{ + Parser = Menu; + After = zUnionMenu.d; + Namespace = zUtilities; +}; + +// Namespace = zUtilities +// Important !!! +// Supporting Unicode symbols. +// File encoding: UTF-8 (without BOM). + +// ------ Constants ------ +const int Start_PY = 1400; +const int Title_PY = 450; +const int Menu_DY = 550; +// Text +const int Text_PX = 400; // Position at left side +const int Text_SX = 8000; // Size X +const int Text_SY = 750; // Size Y +const int Text_DY = 120; // Delta alignment +// Slider +const int Slider_PX = 6400; // Position at left side +const int Slider_SX = 1500; // Size X +const int Slider_SY = 600; // Size Y +const int Slider_DY = 0; // Delta alignment +// Choice +const int Choice_PX = 6400; // Position at left side +const int Choice_SX = 1500; // Size X +const int Choice_SY = 350; // Size Y +const int Choice_DY = 120; // Delta alignment + +const string MenuBackPic = "UnionMenu_BackPic.tga"; +const string ItemBackPic = ""; +const string ChoiceBackPic = "MENU_CHOICE_BACK.TGA"; +const string SliderBackPic = "MENU_SLIDER_BACK.TGA"; +const string SliderPosPic = "MENU_SLIDER_POS.TGA"; +const string FontSmall = "font_old_10_white.tga"; +const string FontBig = "font_old_20_white.tga"; + +var int CurrentMenuItem_PY; + +// ------ Prototypes ------ +func void InitializeBackPicturesAndFonts() +{ + MenuBackPic = MENU_BACK_PIC; + ItemBackPic = MENU_ITEM_BACK_PIC; + ChoiceBackPic = MENU_CHOICE_BACK_PIC; + SliderBackPic = MENU_SLIDER_BACK_PIC; + SliderPosPic = MENU_SLIDER_POS_PIC; + FontSmall = MENU_FONT_SMALL; + FontBig = MENU_FONT_DEFAULT; +}; + +prototype C_EMPTY_MENU_DEF(C_MENU) +{ + InitializeBackPicturesAndFonts(); + C_MENU_DEF(); + backpic = MenuBackPic; + items[0] = ""; + items[100] = "Union_menuitem_back"; + flags = flags | MENU_SHOW_INFO; +}; + +instance C_MENU_ITEM_TEXT_BASE(C_MENU_ITEM_DEF) +{ + backpic = ItemBackPic; + posx = Text_PX; + posy = Start_PY; + dimx = Text_SX; + dimy = Text_SY; + flags = flags | IT_EFFECTS_NEXT; + onselaction[0] = SEL_ACTION_UNDEF; +}; + +instance C_MENUITEM_CHOICE_BASE(C_MENU_ITEM_DEF) +{ + backpic = ChoiceBackPic; + type = MENU_ITEM_CHOICEBOX; + fontname = FontSmall; + posx = Choice_PX; + posy = Start_PY + Choice_DY; + dimx = Choice_SX; + dimy = Choice_SY; + flags = flags & ~IT_SELECTABLE; + flags = flags | IT_TXT_CENTER; +}; + +instance C_MENUITEM_SLIDER_BASE(C_MENU_ITEM_DEF) +{ + backpic = SliderBackPic; + type = MENU_ITEM_SLIDER; + fontname = FontSmall; + posx = Slider_PX; + posy = Start_PY + Slider_DY; + dimx = Slider_SX; + dimy = Slider_SY; + flags = flags & ~IT_SELECTABLE; + flags = flags | IT_TXT_CENTER; + userstring[0] = SliderPosPic; +}; + +instance MenuItem_Opt_Headline(C_MENU_ITEM_DEF) +{ + type = MENU_ITEM_TEXT; + posx = 0; + posy = Title_PY; + dimx = 8100; + flags = flags & ~IT_SELECTABLE; + flags = flags | IT_TXT_CENTER; + text[0] = Str_GetLocalizedString( + "ZUTILITIES НАСТРОЙКИ", + "ZUTILITIES SETTINGS", + "ZUTILITIES EINSTELLUNGEN", + "USTAWIENIA ZUTILITIES" + ); +}; + +func int Act_OpenWebLink() +{ + Open_Link("https://github.com/Franisz/zUtilities"); + return 0; +}; + +instance MenuItem_Opt_Open_Link(C_MENU_ITEM_DEF) +{ + C_MENU_ITEM_TEXT_BASE(); + posy += MENU_DY * 8; + + posx = 64; + onselaction[0] = SEL_ACTION_UNDEF; + oneventaction[1] = Act_OpenWebLink; + flags = flags | IT_TXT_CENTER; + text[0] = Str_GetLocalizedString( + "Открыть страницу проекта", + "Open project page", + "Projektseite öffnen", + "Otwórz stronę projektu" + ); + + text[1] = "github.com/Franisz/zUtilities"; +}; + +// ------ Menu ------ +instance MenuItem_Union_Auto_zUtilities(C_MENU_ITEM_UNION_DEF) +{ + text[0] = "zUtilities"; + text[1] = "Configure zUtilities settings"; + onselaction[0] = SEL_ACTION_STARTMENU; + onselaction_s[0] = "zUtilities:Menu_Opt_Page0"; +}; + +instance Menu_Opt_Page0(C_EMPTY_MENU_DEF) +{ + Menu_SearchItems("ZUTILITIES:MENUITEM_OPT_PAGE0_*"); +}; + +instance Menu_Opt_Page1(C_EMPTY_MENU_DEF) +{ + Menu_SearchItems("ZUTILITIES:MENUITEM_OPT_PAGE1_*"); +}; + +instance Menu_Opt_Page2(C_EMPTY_MENU_DEF) +{ + Menu_SearchItems("ZUTILITIES:MENUITEM_OPT_PAGE2_*"); +}; + +instance Menu_Opt_Page3(C_EMPTY_MENU_DEF) +{ + Menu_SearchItems("ZUTILITIES:MENUITEM_OPT_PAGE3_*"); +}; + +instance Menu_Opt_Page4(C_EMPTY_MENU_DEF) +{ + Menu_SearchItems("ZUTILITIES:MENUITEM_OPT_PAGE4_*"); +}; + +// Page 0 +instance MenuItem_Opt_Page0_Headline(C_MENU_ITEM) +{ + MenuItem_Opt_Headline(); +}; + +instance MenuItem_Opt_Page0_GoTo_Page1(C_MENU_ITEM_UNION_DEF) +{ + CurrentMenuItem_PY = 1; + C_MENU_ITEM_TEXT_BASE(); + // fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY; + posx = 0; + + flags = flags | IT_TXT_CENTER; + + type = MENU_ITEM_TEXT; + dimx = 8100; + + text[0] = "Miscellaneous 1"; + onselaction[0] = SEL_ACTION_STARTMENU; + onselaction_s[0] = "zUtilities:Menu_Opt_Page1"; +}; + +instance MenuItem_Opt_Page0_GoTo_Page2(C_MENU_ITEM_UNION_DEF) +{ + CurrentMenuItem_PY = 2; + C_MENU_ITEM_TEXT_BASE(); + // fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY; + posx = 0; + + flags = flags | IT_TXT_CENTER; + + type = MENU_ITEM_TEXT; + dimx = 8100; + + text[0] = "Miscellaneous 2"; + onselaction[0] = SEL_ACTION_STARTMENU; + onselaction_s[0] = "zUtilities:Menu_Opt_Page2"; +}; + +instance MenuItem_Opt_Page0_GoTo_Page3(C_MENU_ITEM_UNION_DEF) +{ + CurrentMenuItem_PY = 3; + C_MENU_ITEM_TEXT_BASE(); + // fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY; + posx = 0; + + flags = flags | IT_TXT_CENTER; + + type = MENU_ITEM_TEXT; + dimx = 8100; + + text[0] = "StatusBars & Focus"; + onselaction[0] = SEL_ACTION_STARTMENU; + onselaction_s[0] = "zUtilities:Menu_Opt_Page3"; +}; + +instance MenuItem_Opt_Page0_GoTo_Page4(C_MENU_ITEM_UNION_DEF) +{ + CurrentMenuItem_PY = 4; + C_MENU_ITEM_TEXT_BASE(); + // fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY; + posx = 0; + + flags = flags | IT_TXT_CENTER; + + type = MENU_ITEM_TEXT; + dimx = 8100; + + text[0] = "DamagePopup"; + onselaction[0] = SEL_ACTION_STARTMENU; + onselaction_s[0] = "zUtilities:Menu_Opt_Page4"; +}; + +instance MenuItem_Opt_Page0_Open_Link(C_MENU_ITEM) +{ + MenuItem_Opt_Open_Link(); +}; + +// Page 1 +instance MenuItem_Opt_Page1_Headline(C_MENU_ITEM) +{ + MenuItem_Opt_Headline(); +}; + +instance MenuItem_Opt_Page1_TrampleMeatbugs(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 1; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "TrampleMeatbugs"; + text[1] = "kill meatbugs by stepping on them"; +}; + +instance MenuItem_Opt_Page1_TrampleMeatbugs_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "TrampleMeatbugs"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page1_LogBookColoring(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 2; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "LogBookColoring"; + text[1] = "color log book entries"; +}; + +instance MenuItem_Opt_Page1_LogBookColoring_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "LogBookColoring"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page1_UseTimeMultiplier(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 3; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "UseTimeMultiplier"; + text[1] = "time speed multiplier feature"; +}; + +instance MenuItem_Opt_Page1_UseTimeMultiplier_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "UseTimeMultiplier"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page1_QuickSaveMode(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 4; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "QuickSaveMode"; + text[1] = "quick save / load"; +}; + +instance MenuItem_Opt_Page1_QuickSaveMode_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "QuickSaveMode"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|Standard|Alternative"; +}; + +instance MenuItem_Opt_Page1_ShowGameTime(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 5; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ShowGameTime"; + text[1] = "display game time on the screen"; +}; + +instance MenuItem_Opt_Page1_ShowGameTime_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ShowGameTime"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page1_ShowMunitionAmount(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 6; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ShowMunitionAmount"; + text[1] = "display used munition amount on the screen"; +}; + +instance MenuItem_Opt_Page1_ShowMunitionAmount_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ShowMunitionAmount"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page1_RememberLockCombination(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 7; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "RememberLockCombination"; + text[1] = "lock combination doesn't reset after fail"; +}; + +instance MenuItem_Opt_Page1_RememberLockCombination_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "RememberLockCombination"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page1_AlternativeDialogueBoxes(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 8; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "AlternativeDialogueBoxes"; + text[1] = "alternative style for dialogue boxes"; +}; + +instance MenuItem_Opt_Page1_AlternativeDialogueBoxes_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "AlternativeDialogueBoxes"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +// Page 2 +instance MenuItem_Opt_Page2_Headline(C_MENU_ITEM) +{ + MenuItem_Opt_Headline(); +}; + +instance MenuItem_Opt_Page2_CenterInvItems(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 1; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "CenterInvItems"; + text[1] = "inventory item rendering in the center"; +}; + +instance MenuItem_Opt_Page2_CenterInvItems_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "CenterInvItems"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page2_ActivateUsedMunition(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 2; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ActivateUsedMunition"; + text[1] = "highlight used munition as equipped"; +}; + +instance MenuItem_Opt_Page2_ActivateUsedMunition_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ActivateUsedMunition"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page2_LabelItems(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 3; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "LabelItems"; + text[1] = "labeling system for inventory items"; +}; + +instance MenuItem_Opt_Page2_LabelItems_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "LabelItems"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page2_LabelMissionItems(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 4; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "LabelMissionItems"; + text[1] = "force special label for mission items"; +}; + +instance MenuItem_Opt_Page2_LabelMissionItems_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "LabelMissionItems"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page2_ShowTargetProtection(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 5; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ShowTargetProtection"; + text[1] = "protection icon and value next to the focused npc hp bar"; +}; + +instance MenuItem_Opt_Page2_ShowTargetProtection_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ShowTargetProtection"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +// Page 3 +instance MenuItem_Opt_Page3_Headline(C_MENU_ITEM) +{ + MenuItem_Opt_Headline(); +}; + +instance MenuItem_Opt_Page3_StatusBarValueMode(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 1; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "StatusBarValueMode"; + text[1] = "display numerical values for status bars"; +}; + +instance MenuItem_Opt_Page3_StatusBarValueMode_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "StatusBarValueMode"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|Above|ToCenter|Inside"; +}; + +instance MenuItem_Opt_Page3_ShowEnemyBarAboveHim(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 2; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ShowEnemyBarAboveHim"; + text[1] = "display focused npc health bar above him"; +}; + +instance MenuItem_Opt_Page3_ShowEnemyBarAboveHim_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ShowEnemyBarAboveHim"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page3_RecoveryVisualization(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 3; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "RecoveryVisualization"; + text[1] = "visualization of healing that hovered item gives"; +}; + +instance MenuItem_Opt_Page3_RecoveryVisualization_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "RecoveryVisualization"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page3_ShowPickpocketIcon(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 4; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ShowPickpocketIcon"; + text[1] = "coin icon next to npc name when it can be pickpocketed"; +}; + +instance MenuItem_Opt_Page3_ShowPickpocketIcon_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ShowPickpocketIcon"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page3_ColorNpcs(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 5; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ColorNpcs"; + text[1] = "name coloring of focused npcs"; +}; + +instance MenuItem_Opt_Page3_ColorNpcs_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ColorNpcs"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page3_ColorLockables(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 6; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ColorLockables"; + text[1] = "name coloring of focused chests, doors and other lockables"; +}; + +instance MenuItem_Opt_Page3_ColorLockables_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ColorLockables"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page3_ColorItems(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 7; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ColorItems"; + text[1] = "name coloring of focused items"; +}; + +instance MenuItem_Opt_Page3_ColorItems_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ColorItems"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page3_ColorInter(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 8; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "ColorInter"; + text[1] = "name coloring of interactive bookstands"; +}; + +instance MenuItem_Opt_Page3_ColorInter_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "ColorInter"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +// Page 4 +instance MenuItem_Opt_Page4_Headline(C_MENU_ITEM) +{ + MenuItem_Opt_Headline(); +}; + +instance MenuItem_Opt_Page4_DamagePopupMode(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 1; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "DamagePopupMode"; + text[1] = "damage popup style"; +}; + +instance MenuItem_Opt_Page4_DamagePopupMode_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "DamagePopupMode"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|Style 1|Style 2"; +}; + +instance MenuItem_Opt_Page4_DamagePopupShowIcons(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 2; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "DamagePopupShowIcons"; + text[1] = "damage type icons for the popup"; +}; + +instance MenuItem_Opt_Page4_DamagePopupShowIcons_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "DamagePopupShowIcons"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page4_DamagePopupColorDmgTypes(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 3; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "DamagePopupColorDmgTypes"; + text[1] = "popup coloring by the damage type"; +}; + +instance MenuItem_Opt_Page4_DamagePopupColorDmgTypes_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "DamagePopupColorDmgTypes"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; + +instance MenuItem_Opt_Page4_DamagePopupColorOnlyIcon(C_MENU_ITEM) +{ + CurrentMenuItem_PY = 4; + C_MENU_ITEM_TEXT_BASE(); + fontname = FontSmall; + posy += Menu_DY * CurrentMenuItem_PY + Text_DY; + + text[0] = "DamagePopupColorOnlyIcon"; + text[1] = "color only the popup icon"; +}; + +instance MenuItem_Opt_Page4_DamagePopupColorOnlyIcon_Choice(C_MENU_ITEM_DEF) +{ + C_MENUITEM_CHOICE_BASE(); + posy += Menu_DY * CurrentMenuItem_PY; + + onchgsetoption = "DamagePopupColorOnlyIcon"; + onchgsetoptionsection = "zUtilities"; + text[0] = "Off|On"; +}; diff --git a/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_01.WAV b/vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_01.WAV similarity index 100% rename from _WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_01.WAV rename to vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_01.WAV diff --git a/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_02.WAV b/vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_02.WAV similarity index 100% rename from _WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_02.WAV rename to vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_02.WAV diff --git a/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_03.WAV b/vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_03.WAV similarity index 100% rename from _WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_03.WAV rename to vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_03.WAV diff --git a/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_04.WAV b/vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_04.WAV similarity index 100% rename from _WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_04.WAV rename to vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_04.WAV diff --git a/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_05.WAV b/vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_05.WAV similarity index 100% rename from _WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_05.WAV rename to vdf-include/_WORK/DATA/SOUND/SFX/CS_IAM_UD_FLX_05.WAV diff --git a/_WORK/DATA/TEXTURES/_COMPILED/BLACKBACK-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/BLACKBACK-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/BLACKBACK-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/BLACKBACK-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_BLUNT-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_BLUNT-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/DMGICON_BLUNT-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_BLUNT-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_EDGE-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_EDGE-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/DMGICON_EDGE-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_EDGE-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_FALL-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_FALL-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/DMGICON_FALL-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_FALL-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_FIRE-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_FIRE-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/DMGICON_FIRE-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_FIRE-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_FLY-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_FLY-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/DMGICON_FLY-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_FLY-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_MAGIC-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_MAGIC-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/DMGICON_MAGIC-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_MAGIC-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_POINT-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_POINT-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/DMGICON_POINT-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_POINT-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_UNKNOWN-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_UNKNOWN-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/DMGICON_UNKNOWN-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/DMGICON_UNKNOWN-C.TEX diff --git a/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/ICON_CLOCK-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/ICON_CLOCK-C.TEX new file mode 100644 index 0000000..ffd8ddf Binary files /dev/null and b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/ICON_CLOCK-C.TEX differ diff --git a/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/ICON_PROTECTIONS-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/ICON_PROTECTIONS-C.TEX new file mode 100644 index 0000000..322ad70 Binary files /dev/null and b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/ICON_PROTECTIONS-C.TEX differ diff --git a/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/ICON_SAVE-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/ICON_SAVE-C.TEX new file mode 100644 index 0000000..1c51fb9 Binary files /dev/null and b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/ICON_SAVE-C.TEX differ diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_AMULET-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_AMULET-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_AMULET-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_AMULET-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_DEX-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_DEX-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_DEX-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_DEX-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_HELMET-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_HELMET-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_HELMET-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_HELMET-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_MANA-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_MANA-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_MANA-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_MANA-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_STR-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_STR-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_STR-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_ARM_STR-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_BELT-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_BELT-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_BELT-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_BELT-C.TEX diff --git a/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_BRACELET-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_BRACELET-C.TEX new file mode 100644 index 0000000..bbfdf1e Binary files /dev/null and b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_BRACELET-C.TEX differ diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_DOCS-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_DOCS-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_DOCS-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_DOCS-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_DRINK-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_DRINK-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_DRINK-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_DRINK-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_ELSE-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_ELSE-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_ELSE-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_ELSE-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_HERB-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_HERB-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_HERB-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_FOOD_HERB-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_KEY-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_KEY-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_KEY-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_KEY-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MAGIC-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MAGIC-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_MAGIC-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MAGIC-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MAP-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MAP-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_MAP-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MAP-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MISSION-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MISSION-C.TEX similarity index 51% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_MISSION-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MISSION-C.TEX index 21fe7e7..f7c7eca 100644 Binary files a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MISSION-C.TEX and b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MISSION-C.TEX differ diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MONEY-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MONEY-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_MONEY-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MONEY-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MUN_BOW-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MUN_BOW-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_MUN_BOW-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MUN_BOW-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MUN_CROSSBOW-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MUN_CROSSBOW-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_MUN_CROSSBOW-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_MUN_CROSSBOW-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_POTION-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_POTION-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_POTION-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_POTION-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_RING-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_RING-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_RING-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_RING-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_RUNE-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_RUNE-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_RUNE-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_RUNE-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SECRET-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SECRET-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_SECRET-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SECRET-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SHIELD-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SHIELD-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_SHIELD-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SHIELD-C.TEX diff --git a/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SHOES-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SHOES-C.TEX new file mode 100644 index 0000000..ca7cc5e Binary files /dev/null and b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SHOES-C.TEX differ diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SPELL-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SPELL-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_SPELL-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_SPELL-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_TABLET-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_TABLET-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_TABLET-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_TABLET-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_TORCH-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_TORCH-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_TORCH-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_TORCH-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_TROPHY-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_TROPHY-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_TROPHY-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_TROPHY-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_UNKNOWN-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_UNKNOWN-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_UNKNOWN-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_UNKNOWN-C.TEX diff --git a/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_USABLE-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_USABLE-C.TEX new file mode 100644 index 0000000..e5b6337 Binary files /dev/null and b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_USABLE-C.TEX differ diff --git a/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_VALUABLES-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_VALUABLES-C.TEX new file mode 100644 index 0000000..029de5f Binary files /dev/null and b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_VALUABLES-C.TEX differ diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_AXE-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_AXE-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_AXE-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_AXE-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_AXE_2H-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_AXE_2H-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_AXE_2H-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_AXE_2H-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_BOW-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_BOW-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_BOW-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_BOW-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_CROSSBOW-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_CROSSBOW-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_CROSSBOW-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_CROSSBOW-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_DEX-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_DEX-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_DEX-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_DEX-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_DEX_2H-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_DEX_2H-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_DEX_2H-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_DEX_2H-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MACE-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MACE-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MACE-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MACE-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MACE_2H-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MACE_2H-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MACE_2H-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MACE_2H-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MANA-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MANA-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MANA-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MANA-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MANA_2H-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MANA_2H-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MANA_2H-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_MANA_2H-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_SWORD-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_SWORD-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_SWORD-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_SWORD-C.TEX diff --git a/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_SWORD_2H-C.TEX b/vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_SWORD_2H-C.TEX similarity index 100% rename from _WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_SWORD_2H-C.TEX rename to vdf-include/_WORK/DATA/TEXTURES/_COMPILED/LABEL_WPN_SWORD_2H-C.TEX diff --git a/zUtilities/Archive.cpp b/zUtilities/Archive.cpp new file mode 100644 index 0000000..c13ce32 --- /dev/null +++ b/zUtilities/Archive.cpp @@ -0,0 +1,45 @@ +// Supported with union (c) 2020 Union team +// Union SOURCE file + +namespace GOTHIC_ENGINE { + int zCArchiver::ReadIntSafe( char const* text ) { + zFILE* file = this->GetFile(); + if ( !file ) + return Invalid; + + const long file_pos = file->Pos(); + const bool notValid = !file->SeekText( text ).Length(); + + file->Seek( file_pos ); + + if ( notValid ) + return Invalid; + + return this->ReadInt( text ); + } + + void Archive() { + zCArchiver* ar = zarcFactory->CreateArchiverWrite( Z GetArchivePath( PLUGIN_NAME ), zARC_MODE_ASCII, 0, 0 ); + if ( !ar ) + return; + + playerStatus.Archive( ar ); + logBook.Archive( ar ); + + ar->Close(); + ar->Release(); + } + + void Unarchive() { + zCArchiver* ar = zarcFactory->CreateArchiverRead( Z GetArchivePath( PLUGIN_NAME ), 0 ); + + playerStatus.Unarchive( ar ); + logBook.Unarchive( ar ); + + if ( !ar ) + return; + + ar->Close(); + ar->Release(); + } +} \ No newline at end of file diff --git a/zUtilities/Colors.h b/zUtilities/Colors.h new file mode 100644 index 0000000..3ec5d34 --- /dev/null +++ b/zUtilities/Colors.h @@ -0,0 +1,38 @@ +// Supported with union (c) 2020 Union team +// Union HEADER file + +namespace GOTHIC_ENGINE { + enum { + CR, + CG, + CB, + CA + }; + + namespace Colors { + const zCOLOR White = zCOLOR( 255, 255, 255 ); + const zCOLOR Gray = zCOLOR( 148, 144, 136 ); + + zCOLOR GetColorByDamageIndex( oEIndexDamage index ) { + switch ( index ) + { + case oEIndexDamage::oEDamageIndex_Edge: + return zCOLOR( 240, 220, 194 ); + case oEIndexDamage::oEDamageIndex_Blunt: + return zCOLOR( 255, 218, 121 ); + case oEIndexDamage::oEDamageIndex_Point: + return zCOLOR( 211, 255, 117 ); + case oEIndexDamage::oEDamageIndex_Fire: + return zCOLOR( 230, 126, 34 ); + case oEIndexDamage::oEDamageIndex_Magic: + return zCOLOR( 224, 86, 253 ); + case oEIndexDamage::oEDamageIndex_Fly: + return zCOLOR( 107, 244, 255 ); + case oEIndexDamage::oEDamageIndex_Fall: + return zCOLOR( 191, 222, 255 ); + default: + return White; + } + } + } +} \ No newline at end of file diff --git a/zUtilities/Commands.cpp b/zUtilities/Commands.cpp index f7e24d6..9218a1d 100644 --- a/zUtilities/Commands.cpp +++ b/zUtilities/Commands.cpp @@ -4,6 +4,49 @@ namespace GOTHIC_ENGINE { int (*innerEvalFunc)(const zSTRING&, zSTRING&); + int GiveAllItems() { + auto c_item = parser->GetIndex(oCItem::classDef->scriptClassName); + if (c_item == -1) { + return 0; + } + + int itemsCreated = 0; + for (int i = 0; i < parser->symtab.GetNumInList(); i++) { + zCPar_Symbol* symbol = parser->symtab.table[i]; + + if (i == parser->instance_help) { + continue; + } + + if (symbol->type != zPAR_TYPE_INSTANCE) { + continue; + } + + // Instance isn't global scope + if (symbol->name.HasWord(".")) { + continue; + } + + auto baseClass = parser->GetBaseClass(symbol); + + // Symbol isn't a item class + if (baseClass != c_item) { + continue; + } + + oCItem* item = static_cast(ogame->GetGameWorld()->CreateVob(zVOB_TYPE_ITEM, i)); + if (item->HasFlag(ITM_FLAG_MULTI)) { + item->amount = 50; + } + + player->PutInInv(item); + item->Release(); + itemsCreated++; + } + + return itemsCreated; + } + int ConsoleEvalFunc( const zSTRING& inpstr, zSTRING& msg ) { if ( innerEvalFunc && innerEvalFunc( inpstr, msg ) ) return true; @@ -24,6 +67,20 @@ namespace GOTHIC_ENGINE { return true; } + if (w2 == "GiveAllItems") { + auto result = GiveAllItems(); + msg = "Created " + Z result + " instances."; + + return true; + } + + if (w2 == "ShowTriggers") { + Options::ShowTriggers = !Options::ShowTriggers; + zSTRING state = (Options::ShowTriggers) ? "ON" : "OFF"; + msg = "zUtilities showing triggers " + state; + return true; + } + return false; } @@ -42,5 +99,7 @@ namespace GOTHIC_ENGINE { RegisterEvalFunc(); zcon->Register( "zUtilities Version", "Shows version number" ); zcon->Register( "zUtilities Debug", "Toggles debug mode" ); + zcon->Register( "zUtilities GiveAllItems", "Gives all items" ); + zcon->Register( "zUtilities ShowTriggers", "Toggles the display of invisible triggers in debug mode" ); } } \ No newline at end of file diff --git a/zUtilities/Const.h b/zUtilities/Const.h new file mode 100644 index 0000000..9a1064f --- /dev/null +++ b/zUtilities/Const.h @@ -0,0 +1,9 @@ +// Supported with union (c) 2020 Union team +// Union HEADER file + +namespace GOTHIC_ENGINE { +#define PLUGIN_NAME "ZUTILITIES" +#define VERSION_NUMBER "0.37" +#define printWin(a) ogame->GetTextView()->Printwin(a) +#define del(x) { delete x; x = nullptr; } +} \ No newline at end of file diff --git a/zUtilities/DamagePopup.cpp b/zUtilities/DamagePopup.cpp index 29e4d6d..3e10434 100644 --- a/zUtilities/DamagePopup.cpp +++ b/zUtilities/DamagePopup.cpp @@ -32,10 +32,10 @@ namespace GOTHIC_ENGINE { return false; #if ENGINE >= Engine_G2 - if ( desc.pItemWeapon->HasFlag( ITM_FLAG_2HD_SWD ) || desc.pItemWeapon->HasFlag( ITM_FLAG_2HD_AXE ) ) - return dmgRand <= desc.pNpcAttacker->GetHitChance( NPC_HITCHANCE_2H ); + int talent = (desc.pItemWeapon->HasFlag( ITM_FLAG_2HD_SWD ) || desc.pItemWeapon->HasFlag( ITM_FLAG_2HD_AXE )) + ? NPC_HITCHANCE_2H : NPC_HITCHANCE_1H; - return dmgRand <= desc.pNpcAttacker->GetHitChance( NPC_HITCHANCE_1H ); + return dmgRand < desc.pNpcAttacker->GetHitChance( talent ); #else return desc.fDamageMultiplier > 1.0f; #endif @@ -53,9 +53,10 @@ namespace GOTHIC_ENGINE { unsigned long seed = ptd->_holdrand; #endif - int isCrit = false; + bool isCrit = false; int initialHp = this->attribute[NPC_ATR_HITPOINTS]; + oCNpc::oSDamageDescriptor descOld = desc; THISCALL( Ivk_OnDamage_Hit_Union )(desc); int hpDiff = initialHp - this->attribute[NPC_ATR_HITPOINTS]; @@ -69,20 +70,7 @@ namespace GOTHIC_ENGINE { isCrit = IsCrit( desc ); #endif - new DamagePopup( this, desc, hpDiff, isCrit ); - } - - int DamagePopup::GetTopDmgIndex() { - int topDmgAmount = 0, topDmgIndex = 0; - - for ( int i = 0; i < (int)oEDamageIndex::oEDamageIndex_MAX; i++ ) - if ( (oEDamageType)(1 << (oEDamageIndex)i) & desc->enuModeDamage ) - if ( (int)desc->aryDamageEffective[i] >= topDmgAmount ) { - topDmgAmount = (int)desc->aryDamageEffective[i]; - topDmgIndex = i; - } - - return topDmgIndex; + new DamagePopup( this, descOld, hpDiff, isCrit ); } void DamagePopup::SetMoveMode() { @@ -185,17 +173,19 @@ namespace GOTHIC_ENGINE { } void DamagePopup::SetScale() { - float sysScale; - Union.GetSysPackOption().Read( sysScale, "INTERFACE", "Scale", 1.0f ); - scale = (sysScale) ? 1.15f : 1.0f; + scale = (playerHelper.GetSysScale()) ? 1.15f : 1.0f; scale *= Options::DamagePopupScale; + float baseScale = scale; + if ( dmgAmount > 0 ) { scale += scale * (float)dmgAmount / (float)target->attribute[NPC_ATR_HITPOINTSMAX] / 1.75f; if ( isCrit ) scale *= 1.4f; } + + scale = min( scale, baseScale * 3.5f ); } float DamagePopup::GetRandomDist( float start, int random, bool invertable ) { @@ -213,10 +203,10 @@ namespace GOTHIC_ENGINE { int x, y; cam->Project( &viewPos, x, y ); - pos[0] = view->anx( x + 0.5f ); - pos[1] = view->any( y + 0.5f ); + pos[VX] = view->anx( x + 0.5f ); + pos[VY] = view->any( y + 0.5f ); - return viewPos[2] > cam->nearClipZ; + return viewPos[VZ] > cam->nearClipZ; } float DamagePopup::Scale( float p, float max ) { @@ -225,22 +215,22 @@ namespace GOTHIC_ENGINE { void DamagePopup::CalcOffset( float lifetime ) { const zMAT4& viewTrafo = ogame->GetCamera()->GetTransform( zTCamTrafoType::zCAM_TRAFO_WORLDVIEW_INV ); - offset = zVEC3( viewTrafo[0][0], viewTrafo[1][0], viewTrafo[2][0] ) * Scale( min( lifetime, horizontalMoveTime ), horizontalMoveTime ) * horizontalMoveDist; - offset[1] += Scale( min( lifetime, timeLimitInSecs ), timeLimitInSecs ) * verticalMoveDist; + offset = zVEC3( viewTrafo[VX][VX], viewTrafo[VY][VX], viewTrafo[VZ][VX] ) * Scale( min( lifetime, horizontalMoveTime ), horizontalMoveTime ) * horizontalMoveDist; + offset[VY] += Scale( min( lifetime, timeLimitInSecs ), timeLimitInSecs ) * verticalMoveDist; } void DamagePopup::CalcViewport( zSTRING& text, zCView* view, zVEC2 viewPos, const zVEC2& scaling ) { - float width = view->FontSize( text ) * scaling[0]; - float height = view->FontY() * scaling[1]; + float width = view->FontSize( text ) * scaling[VX]; + float height = view->FontY() * scaling[VY]; if ( Options::DamagePopupShowIcons ) width += height; - viewPos[0] = CoerceInRange( viewPos[0] - width / 2, width, 0, 8191 ); - viewPos[1] = CoerceInRange( viewPos[1] - height / 2, height, 0, 8191 ); + viewPos[VX] = CoerceInRange( viewPos[VX] - width / 2, width, 0, 8191 ); + viewPos[VY] = CoerceInRange( viewPos[VY] - height / 2, height, 0, 8191 ); - vpPos.left = view->nax( viewPos[0] ) + vpOffset[0]; - vpPos.top = view->nay( viewPos[1] ) + vpOffset[1]; + vpPos.left = view->nax( viewPos[VX] ) + vpOffset[VX]; + vpPos.top = view->nay( viewPos[VY] ) + vpOffset[VY]; width = view->nax( width ); height = view->nay( height ); vpPos.right = vpPos.left + width; @@ -251,7 +241,7 @@ namespace GOTHIC_ENGINE { int deltaY = (popups[i]->vpPos.bottom - vpPos.top) / 3.0f; vpPos.top += deltaY; vpPos.bottom += deltaY; - vpOffset[1] += deltaY; + vpOffset[VY] += deltaY; } } @@ -266,8 +256,8 @@ namespace GOTHIC_ENGINE { if ( lastAnchorUpdate <= creationTimeInSecs ) { lastAnchorUpdate = ztimer->totalTimeFloat / 1000.0f; currentLifetimeLimit = max( currentLifetimeLimit, lifetime + prolongationInSecs ); - anchorPos[0] = target->GetPositionWorld()[0]; - anchorPos[2] = target->GetPositionWorld()[2]; + anchorPos[VX] = target->GetPositionWorld()[VX]; + anchorPos[VZ] = target->GetPositionWorld()[VZ]; } if ( lifetime > currentLifetimeLimit ) { @@ -294,6 +284,9 @@ namespace GOTHIC_ENGINE { } void DamagePopup::Print( zCView* view, const zVEC3& pos, const zVEC2& scaling ) { + if ( !ogame->game_drawall ) + return; + zVEC2 viewPos; if ( !WorldToView( pos, view, viewPos ) ) return; @@ -306,7 +299,7 @@ namespace GOTHIC_ENGINE { CalcViewport( text, view, viewPos, scaling ); zCFont* font = view->GetFont(); - float space = font->GetLetterDistance() * scaling[0]; + float space = font->GetLetterDistance() * scaling[VX]; float x = vpPos.left; float y = vpPos.top; @@ -317,7 +310,7 @@ namespace GOTHIC_ENGINE { int charWidth; zVEC2 from, to; font->GetFontData( text[i], charWidth, from, to ); - float fCharWidth = charWidth * scaling[0]; + float fCharWidth = charWidth * scaling[VX]; zrenderer->DrawTile( font->GetFontTexture(), zVEC2( x, y ), zVEC2( x + fCharWidth, y + height ), z, from, to, textColor ); x += fCharWidth + space; @@ -347,7 +340,11 @@ namespace GOTHIC_ENGINE { this->desc = &desc; this->isCrit = isCrit; - dmgIndex = GetTopDmgIndex(); + int aryDamageEffective[oEDamageIndex::oEDamageIndex_MAX]; + for ( int i = 0; i < oEDamageIndex::oEDamageIndex_MAX; i++ ) + aryDamageEffective[i] = (int)this->desc->aryDamageEffective[i]; + + dmgIndex = GetTopDmgIndex( aryDamageEffective, this->desc->enuModeDamage ); SetMoveMode(); SetColor(); SetIcon(); @@ -356,7 +353,7 @@ namespace GOTHIC_ENGINE { creationTimeInSecs = ztimer->totalTimeFloat / 1000.0f; lastAnchorUpdate = creationTimeInSecs; anchorPos = target->GetPositionWorld(); - anchorPos[1] += (target->bbox3D.maxs[1] - target->bbox3D.mins[1]) * anchorStartPosMultiplier; + anchorPos[VY] += (target->bbox3D.maxs[VY] - target->bbox3D.mins[VY]) * anchorStartPosMultiplier; vpOffset = zVEC2( 0, 0 ); CalcOffset( 0 ); Update(); diff --git a/zUtilities/DamagePopup.h b/zUtilities/DamagePopup.h index ecf8a11..881f642 100644 --- a/zUtilities/DamagePopup.h +++ b/zUtilities/DamagePopup.h @@ -3,15 +3,16 @@ namespace GOTHIC_ENGINE { namespace Options { - int DamagePopupMode, DamagePopupShowIcons, DamagePopupColorDmgTypes, DamagePopupColorOnlyIcon; + bool DamagePopupShowIcons, DamagePopupColorDmgTypes, DamagePopupColorOnlyIcon; + int DamagePopupMode; float DamagePopupScale; void DamagePopup() { DamagePopupMode = zoptions->ReadInt( PLUGIN_NAME, "DamagePopupMode", 1 ); DamagePopupScale = zoptions->ReadReal( PLUGIN_NAME, "DamagePopupScale", 1.1f ); - DamagePopupShowIcons = zoptions->ReadInt( PLUGIN_NAME, "DamagePopupShowIcons", true ); - DamagePopupColorDmgTypes = zoptions->ReadInt( PLUGIN_NAME, "DamagePopupColorDmgTypes", true ); - DamagePopupColorOnlyIcon = zoptions->ReadInt( PLUGIN_NAME, "DamagePopupColorOnlyIcon", false ); + DamagePopupShowIcons = zoptions->ReadBool( PLUGIN_NAME, "DamagePopupShowIcons", true ); + DamagePopupColorDmgTypes = zoptions->ReadBool( PLUGIN_NAME, "DamagePopupColorDmgTypes", true ); + DamagePopupColorOnlyIcon = zoptions->ReadBool( PLUGIN_NAME, "DamagePopupColorOnlyIcon", false ); } } @@ -44,7 +45,6 @@ namespace GOTHIC_ENGINE { float alpha = 255.0f; float scale; - int GetTopDmgIndex(); void SetMoveMode(); void SetColor(); void SetIcon(); diff --git a/zUtilities/DebugHelper.cpp b/zUtilities/DebugHelper.cpp index 607b07d..87c6315 100644 --- a/zUtilities/DebugHelper.cpp +++ b/zUtilities/DebugHelper.cpp @@ -1,198 +1,268 @@ -// Supported with union (c) 2020 Union team +// Supported with union ( c ) 2020 Union team // Union SOURCE file namespace GOTHIC_ENGINE { void DebugHelper::InfoNpc( oCNpc* npc ) { - Print( textView, "Instance", npc->GetInstanceName() + " (" + Z npc->instanz + ")" ); - Print( textView, "Name", npc->GetName( 0 ) ); - Print( textView, "Guild", npc->GetGuildName() + " (" + Z npc->GetGuild() + ")" ); - Print( sideView, "Level", Z npc->level ); - AddSeparator(); - Print( textView, "HP", Z npc->GetAttribute( NPC_ATR_HITPOINTS ) + "/" + Z npc->GetAttribute( NPC_ATR_HITPOINTSMAX ) ); -#if ENGINE >= Engine_G2 - Print( sideView, "1H", Z npc->GetHitChance( NPC_HITCHANCE_1H ) ); -#else - Print( sideView, "1H", Z npc->GetTalentValue( NPC_HITCHANCE_1H ) ); -#endif - Print( textView, "MANA", Z npc->GetAttribute( NPC_ATR_MANA ) + "/" + Z npc->GetAttribute( NPC_ATR_MANAMAX ) ); -#if ENGINE >= Engine_G2 - Print( sideView, "2H", Z npc->GetHitChance( NPC_HITCHANCE_2H ) ); -#else - Print( sideView, "2H", Z npc->GetTalentValue( NPC_HITCHANCE_2H ) ); -#endif - Print( textView, "STR", Z npc->GetAttribute( NPC_ATR_STRENGTH ) ); -#if ENGINE >= Engine_G2 - Print( sideView, "BOW", Z npc->GetHitChance( NPC_HITCHANCE_BOW ) ); -#else - Print( sideView, "BOW", Z npc->GetTalentValue( NPC_HITCHANCE_BOW ) ); -#endif - Print( textView, "DEX", Z npc->GetAttribute( NPC_ATR_DEXTERITY ) ); -#if ENGINE >= Engine_G2 - Print( sideView, "CBOW", Z npc->GetHitChance( NPC_HITCHANCE_CROSSBOW ) ); -#else - Print( sideView, "CBOW", Z npc->GetTalentValue( NPC_HITCHANCE_CROSSBOW ) ); -#endif - AddSeparator(); - Print( textView, "PROT_EDGE", Z npc->GetProtectionByIndex( oEDamageIndex_Edge ) ); - Print( textView, "PROT_BLUNT", Z npc->GetProtectionByIndex( oEDamageIndex_Blunt ) ); - Print( textView, "PROT_POINT", Z npc->GetProtectionByIndex( oEDamageIndex_Point ) ); - Print( textView, "PROT_FIRE", Z npc->GetProtectionByIndex( oEDamageIndex_Fire ) ); - Print( textView, "PROT_MAGIC", Z npc->GetProtectionByIndex( oEDamageIndex_Magic ) ); - Print( textView, "PROT_FLY", Z npc->GetProtectionByIndex( oEDamageIndex_Fly ) ); - Print( textView, "PROT_FALL", Z npc->GetProtectionByIndex( oEDamageIndex_Fall ) ); - AddSeparator(); - Print( textView, "Waypoint", npc->wpname ); - Print( textView, "Flags", Z npc->variousFlags ); - Print( sideView, "NpcType", Z npc->npcType ); - Print( textView, "Attitude", Z npc->GetAttitude( player ) ); - Print( sideView, "PermAttitude", Z npc->GetPermAttitude( player ) ); - Print( textView, "SensesRange", Z npc->senses_range ); - Print( sideView, "DistToPlayer", Z( int )npc->GetDistanceToVob( *player ) ); - Print( textView, "DetectedPlayer", Z npc->HasVobDetected( player ) ); - Print( sideView, "Voice", Z npc->voice ); - Print( textView, "AIState", Z npc->GetAIState() ); - Print( sideView, "DailyRoutine", Z npc->daily_routine ); - Print( textView, "FightMode", Z npc->fmode ); - Print( sideView, "FightTactic", Z npc->fighttactic ); + //LEFT SIDE + Print( leftView, "--- " + npc->_GetClassDef()->className, npc->GetInstanceName() + " ( " + Z npc->instanz + " )" ); + Print( leftView, "Name", npc->GetName( 0 ) ); + Print( leftView, "Level", Z npc->level ); + Print( leftView, "Guild", npc->GetGuildName() + " ( " + Z npc->GetGuild() + " )" ); + Print( leftView, "Voice", Z npc->voice ); + Print( leftView, "Flags", Z npc->variousFlags ); + Print( leftView, "NpcType", Z npc->npcType ); + Print( leftView, "Attitude", Z npc->GetAttitude( player ) ); + Print( leftView, "PermAttitude", Z npc->GetPermAttitude( player ) ); + Print( leftView, "SensesRange", Z npc->senses_range ); + Print( leftView, "DetectedPlayer", Z npc->HasVobDetected( player ) ); + Print( leftView, "DistToPlayer", Z( int )npc->GetDistanceToVob( *player ) ); + + AddSeparator( leftView, "Fight AI" ); + Print( leftView, "FightMode", Z npc->fmode ); + Print( leftView, "FightTactic", Z npc->fighttactic ); + Print( leftView, "FightRangeBase", Z npc->GetFightRangeBase() ); + Print( leftView, "FightRangeFist", Z npc->GetFightRangeFist() ); + Print( leftView, "FightRangeDynamic", Z npc->GetFightRangeDynamic() ); + Print( leftView, "FightRange", Z npc->GetFightRange() ); if ( npc->enemy != nullptr ) - Print( textView, "Enemy", npc->enemy->GetInstanceName() ); + Print( leftView, "Enemy", npc->enemy->GetInstanceName() ); + AddSeparator( leftView, "Visual/Armor" ); if ( zCVisual* visual = npc->GetVisual() ) { - AddSeparator( "Visual" ); - Print( textView, "VisualFile", visual->GetVisualName() ); - Print( textView, "BodyName", npc->GetVisualBody() ); - Print( textView, "HeadName", npc->GetVisualHead() ); + Print( leftView, "VisualFile", visual->GetVisualName() ); + Print( leftView, "ModelScale", Z npc->model_scale[VX] + Z " " + npc->model_scale[VY] + Z " " + npc->model_scale[VZ] ); + Print( leftView, "BodyName", npc->GetVisualBody() ); + Print( leftView, "HeadName", npc->GetVisualHead() ); #if ENGINE == Engine_G2A - Print( textView, "EffectName", npc->effect ); + Print( leftView, "EffectName", npc->effect ); #endif - if ( oCItem* armor = npc->GetEquippedArmor() ) { - AddSeparator( "Armor" ); - Print( textView, "VisualFile", armor->GetVisual()->GetVisualName() ); - Print( textView, "VisualChange", armor->GetVisualChange() ); + } + + if ( oCItem* armor = npc->GetEquippedArmor() ) { + Print( leftView, "VisualChange", armor->GetVisualChange() ); #if ENGINE == Engine_G2A - Print( textView, "EffectName", armor->GetEffectName() ); + Print( leftView, "EffectName", armor->GetEffectName() ); #endif - } } + + AddSeparator( leftView, "Routine" ); + Print( leftView, "Waypoint", npc->wpname ); + if ( auto sym = parser->GetSymbol( npc->GetAIState() ) ) + { + Print( leftView, "AIState", sym->name ); + } + else + { + Print( leftView, "AIState", Z npc->GetAIState() ); + } + if ( auto sym = parser->GetSymbol( npc->daily_routine ) ) + { + Print( leftView, "DailyRoutine", sym->name ); + } + else + { + Print( leftView, "DailyRoutine", Z npc->daily_routine ); + } + + //RIGHT SIDE + AddSeparator( rightView, "Attributes" ); + Print( rightView, "HP", Z npc->GetAttribute( NPC_ATR_HITPOINTS ) + "/" + Z npc->GetAttribute( NPC_ATR_HITPOINTSMAX ) ); + Print( rightView, "MANA", Z npc->GetAttribute( NPC_ATR_MANA ) + "/" + Z npc->GetAttribute( NPC_ATR_MANAMAX ) ); + Print( rightView, "STR", Z npc->GetAttribute( NPC_ATR_STRENGTH ) ); + Print( rightView, "DEX", Z npc->GetAttribute( NPC_ATR_DEXTERITY ) ); + + AddSeparator( rightView, "Fight talents" ); +#if ENGINE >= Engine_G2 + Print( rightView, "1H", Z npc->GetHitChance( NPC_HITCHANCE_1H ) ); + Print( rightView, "2H", Z npc->GetHitChance( NPC_HITCHANCE_2H ) ); + Print( rightView, "BOW", Z npc->GetHitChance( NPC_HITCHANCE_BOW ) ); + Print( rightView, "CBOW", Z npc->GetHitChance( NPC_HITCHANCE_CROSSBOW ) ); +#else + Print( rightView, "1H", Z npc->GetTalentValue( NPC_HITCHANCE_1H ) ); + Print( rightView, "2H", Z npc->GetTalentValue( NPC_HITCHANCE_2H ) ); + Print( rightView, "BOW", Z npc->GetTalentValue( NPC_HITCHANCE_BOW ) ); + Print( rightView, "CBOW", Z npc->GetTalentValue( NPC_HITCHANCE_CROSSBOW ) ); +#endif + + AddSeparator( rightView, "Damage" ); + Print( rightView, "DAM_EDGE", Z npc->GetDamageByIndex( oEDamageIndex_Edge ) ); + Print( rightView, "DAM_BLUNT", Z npc->GetDamageByIndex( oEDamageIndex_Blunt ) ); + Print( rightView, "DAM_POINT", Z npc->GetDamageByIndex( oEDamageIndex_Point ) ); + Print( rightView, "DAM_FIRE", Z npc->GetDamageByIndex( oEDamageIndex_Fire ) ); + Print( rightView, "DAM_MAGIC", Z npc->GetDamageByIndex( oEDamageIndex_Magic ) ); + Print( rightView, "DAM_FLY", Z npc->GetDamageByIndex( oEDamageIndex_Fly ) ); + Print( rightView, "DAM_FALL", Z npc->GetDamageByIndex( oEDamageIndex_Fall ) ); + Print( rightView, "DamageType", Z npc->damagetype ); + + AddSeparator( rightView, "Protection" ); + Print( rightView, "PROT_EDGE", Z npc->GetProtectionByIndex( oEDamageIndex_Edge ) ); + Print( rightView, "PROT_BLUNT", Z npc->GetProtectionByIndex( oEDamageIndex_Blunt ) ); + Print( rightView, "PROT_POINT", Z npc->GetProtectionByIndex( oEDamageIndex_Point ) ); + Print( rightView, "PROT_FIRE", Z npc->GetProtectionByIndex( oEDamageIndex_Fire ) ); + Print( rightView, "PROT_MAGIC", Z npc->GetProtectionByIndex( oEDamageIndex_Magic ) ); + Print( rightView, "PROT_FLY", Z npc->GetProtectionByIndex( oEDamageIndex_Fly ) ); + Print( rightView, "PROT_FALL", Z npc->GetProtectionByIndex( oEDamageIndex_Fall ) ); } void DebugHelper::InfoItem( oCItem* item ) { - Print( textView, "Instance", item->GetInstanceName() + " (" + Z item->instanz + ")" ); - Print( textView, "Name", Z item->name ); - Print( textView, "Description", Z item->GetDescription() ); - Print( textView, "Value", Z item->GetValue() ); - - AddSeparator(); - if ( item->HasFlag( ITM_CAT_ARMOR ) || item->HasFlag( ITM_CAT_NF ) || item->HasFlag( ITM_CAT_FF ) ) { - Print( textView, "PROT_EDGE", Z item->GetProtectionByIndex( oEDamageIndex_Edge ) ); - Print( sideView, "DAM_EDGE", Z item->GetDamageByIndex( oEDamageIndex_Edge ) ); - Print( textView, "PROT_BLUNT", Z item->GetProtectionByIndex( oEDamageIndex_Blunt ) ); - Print( sideView, "DAM_BLUNT", Z item->GetDamageByIndex( oEDamageIndex_Blunt ) ); - Print( textView, "PROT_POINT", Z item->GetProtectionByIndex( oEDamageIndex_Point ) ); - Print( sideView, "DAM_POINT", Z item->GetDamageByIndex( oEDamageIndex_Point ) ); - Print( textView, "PROT_FIRE", Z item->GetProtectionByIndex( oEDamageIndex_Fire ) ); - Print( sideView, "DAM_FIRE", Z item->GetDamageByIndex( oEDamageIndex_Fire ) ); - Print( textView, "PROT_MAGIC", Z item->GetProtectionByIndex( oEDamageIndex_Magic ) ); - Print( sideView, "DAM_MAGIC", Z item->GetDamageByIndex( oEDamageIndex_Magic ) ); - Print( textView, "PROT_FLY", Z item->GetProtectionByIndex( oEDamageIndex_Fly ) ); - Print( sideView, "DAM_FLY", Z item->GetDamageByIndex( oEDamageIndex_Fly ) ); - Print( textView, "PROT_FALL", Z item->GetProtectionByIndex( oEDamageIndex_Fall ) ); - Print( sideView, "DAM_FALL", Z item->GetDamageByIndex( oEDamageIndex_Fall ) ); - Print( textView, "TotalDamage", Z item->damageTotal ); - AddSeparator(); + Print( leftView, "--- " + item->_GetClassDef()->className, item->GetInstanceName() + " ( " + Z item->instanz + " )" ); + Print( leftView, "Name", Z item->name ); + Print( leftView, "Description", Z item->GetDescription() ); + Print( leftView, "Value", Z item->GetValue() ); + Print( leftView, "Owner", Z item->owner ); + if ( item->ownerGuild ) + Print( leftView, "OwnerGuild", ogame->GetGuilds()->GetGuildName( item->ownerGuild ) + " ( " + Z item->ownerGuild + " )" ); + Print( leftView, "SchemeName", Z item->GetSchemeName() ); + Print( leftView, "Material", Z item->GetSoundMaterial() ); + if ( auto symbol = parser->GetSymbol( item->GetStateFunc() ) ) + Print( leftView, "onState", symbol->name ); + + + if ( item->HasFlag( ITM_CAT_ARMOR ) || item->HasFlag( ITM_CAT_NF ) || item->HasFlag( ITM_CAT_FF ) || item->HasFlag( ITM_CAT_MUN ) ) { + Print( leftView, "Range", Z item->range ); + + AddSeparator( rightView, "Damage" ); + Print( rightView, "DAM_EDGE", Z item->GetDamageByIndex( oEDamageIndex_Edge ) ); + Print( rightView, "DAM_BLUNT", Z item->GetDamageByIndex( oEDamageIndex_Blunt ) ); + Print( rightView, "DAM_POINT", Z item->GetDamageByIndex( oEDamageIndex_Point ) ); + Print( rightView, "DAM_FIRE", Z item->GetDamageByIndex( oEDamageIndex_Fire ) ); + Print( rightView, "DAM_MAGIC", Z item->GetDamageByIndex( oEDamageIndex_Magic ) ); + Print( rightView, "DAM_FLY", Z item->GetDamageByIndex( oEDamageIndex_Fly ) ); + Print( rightView, "DAM_FALL", Z item->GetDamageByIndex( oEDamageIndex_Fall ) ); + Print( rightView, "TotalDamage", Z item->damageTotal ); + Print( rightView, "DamageTypes", Z item->damageTypes ); + + AddSeparator( rightView, "Protection" ); + Print( rightView, "PROT_EDGE", Z item->GetProtectionByIndex( oEDamageIndex_Edge ) ); + Print( rightView, "PROT_BLUNT", Z item->GetProtectionByIndex( oEDamageIndex_Blunt ) ); + Print( rightView, "PROT_POINT", Z item->GetProtectionByIndex( oEDamageIndex_Point ) ); + Print( rightView, "PROT_FIRE", Z item->GetProtectionByIndex( oEDamageIndex_Fire ) ); + Print( rightView, "PROT_MAGIC", Z item->GetProtectionByIndex( oEDamageIndex_Magic ) ); + Print( rightView, "PROT_FLY", Z item->GetProtectionByIndex( oEDamageIndex_Fly ) ); + Print( rightView, "PROT_FALL", Z item->GetProtectionByIndex( oEDamageIndex_Fall ) ); } else if ( item->spell ) { - Print( textView, "SpellID", Z item->spell ); - Print( sideView, "Circle", Z item->mag_circle ); + AddSeparator( rightView, "Spell" ); + Print( rightView, "SpellID", Z item->spell ); + Print( rightView, "Circle", Z item->mag_circle ); + + oCSpell* spl = new oCSpell( item->spell ); + Print( rightView, "SpellName", spl->GetName() ); + spl->Release(); } + AddSeparator( leftView, "Flags" ); + Print( leftView, "Mainflag", Z item->mainflag ); + Print( leftView, "Flags", Z item->flags ); + + AddSeparator( leftView, "Requirements" ); for ( int i = 0; i < ITM_COND_MAX; i++ ) { if ( !item->cond_atr[i] ) continue; - Print( textView, "Cond" + Z i, Z item->cond_atr[i] + " (" + Z item->cond_value[i] + ")" ); + Print( leftView, GetAttributeName( item->cond_atr[i] ), Z item->cond_value[i] ); } - Print( textView, "Mainflag", Z item->mainflag ); - Print( sideView, "Flags", Z item->flags ); - Print( textView, "Owner", Z item->owner ); - if ( item->ownerGuild ) - Print( textView, "OwnerGuild", ogame->GetGuilds()->GetGuildName( item->ownerGuild ) + " (" + Z item->ownerGuild + ")" ); - Print( textView, "SchemeName", Z item->GetSchemeName() ); - Print( sideView, "Material", Z item->GetSoundMaterial() ); - if ( zCVisual* visual = item->GetVisual() ) { - AddSeparator( "Visual" ); - Print( textView, "VisualFile", visual->GetVisualName() ); - Print( textView, "VisualChange", item->GetVisualChange() ); + AddSeparator( leftView, "Visual" ); + Print( leftView, "VisualFile", visual->GetVisualName() ); + Print( leftView, "VisualChange", item->GetVisualChange() ); #if ENGINE == Engine_G2A - Print( textView, "EffectName", item->GetEffectName() ); + Print( leftView, "EffectName", item->GetEffectName() ); #endif } } void DebugHelper::InfoMob( oCMOB* mob ) { - Print( textView, "MobName", mob->name ); - Print( textView, "Name", mob->GetName() ); - Print( textView, "Owner", mob->ownerStr ); - Print( textView, "ScemeName", mob->GetScemeName() ); + Print( leftView, "--- " + mob->_GetClassDef()->className, mob->name ); + Print( leftView, "Name", mob->GetName() ); + Print( leftView, "Owner", mob->ownerStr ); + Print( leftView, "ScemeName", mob->GetScemeName() ); if ( oCMobInter* inter = mob->CastTo() ) { - AddSeparator( "Inter" ); - Print( textView, "UseItem", inter->useWithItem ); - Print( textView, "ConditionFuncName", inter->conditionFunc ); - Print( textView, "OnStateFuncName", inter->onStateFuncName ); + AddSeparator( leftView, "Inter" ); + Print( leftView, "TriggerTarget", inter->triggerTarget ); + Print( leftView, "UseItem", inter->useWithItem ); + Print( leftView, "ConditionFuncName", inter->conditionFunc ); + Print( leftView, "OnStateFuncName", inter->onStateFuncName ); } if ( oCMobLockable* lockable = mob->CastTo() ) { - AddSeparator( "Lockable" ); - Print( textView, "KeyInstance", lockable->keyInstance ); - Print( textView, "LockString", lockable->pickLockStr ); - Print( textView, "Locked", Z lockable->locked ); + AddSeparator( rightView, "Lockable" ); + Print( rightView, "KeyInstance", lockable->keyInstance ); + Print( rightView, "LockString", lockable->pickLockStr ); + Print( rightView, "Locked", Z lockable->locked ); + } + + if ( zCVisual* visual = mob->GetVisual() ) { + AddSeparator( leftView, "Visual" ); + Print( leftView, "VisualFile", visual->GetVisualName() ); } if ( oCMobContainer* container = mob->CastTo() ) + { if ( auto list = container->containList.GetNextInList() ) { int itemCount = container->containList.GetNumInList(); int printedItems = 0; - AddSeparator( "Container" ); + AddSeparator( leftView, "Container" ); while ( list != nullptr ) { - Print( textView, list->GetData()->name, Z list->GetData()->amount ); + Print( leftView, list->GetData()->name, Z list->GetData()->amount ); printedItems++; - if ( itemCount > 5 && printedItems >= 5 ) { - Print( textView, "", "And " + Z( itemCount - printedItems ) + " more..." ); + if ( itemCount > 15 && printedItems >= 15 ) { + Print( leftView, "", "And " + Z( itemCount - printedItems ) + " more..." ); break; } list = list->GetNextInList(); } } - - if ( zCVisual* visual = mob->GetVisual() ) { - AddSeparator( "Visual" ); - Print( textView, "VisualFile", visual->GetVisualName() ); } } - void DebugHelper::AddSeparator( zSTRING str ) { - if ( textLines > 0 ) - textLines++; + void DebugHelper::AddSeparator( zCView* view, zSTRING str ) { + int textLines; + + + if ( view == leftView ) + textLinesLeft++; + else if ( view == rightView ) + textLinesRight++; if ( !str.Length() ) return; - textLines++; - textView->Print( 0, textHeight * textLines, "--- " + str ); + if ( view == rightView ) + { + textLinesRight++; + + textLines = textLinesRight; + } + else + { + textLinesLeft++; + + textLines = textLinesLeft; + } + + view->Print( 0, textHeight * textLines, "--- " + str ); } void DebugHelper::Print( zCView* view, zSTRING name, zSTRING value ) { if ( !value.Length() ) value = "-"; - zSTRING text = (name.Length()) ? name + ": " + value : value; - - if ( view == textView ) - textLines++; + zSTRING text = ( name.Length() ) ? name + ": " + value : value; + int textLines; + if ( view == rightView ) + { + textLinesRight++; + textLines = textLinesRight; + } + else + { + textLinesLeft++; + textLines = textLinesLeft; + } view->Print( 0, textHeight * textLines, text ); } @@ -200,7 +270,6 @@ namespace GOTHIC_ENGINE { bool DebugHelper::TryPrintInfo() { if ( player->inventory2.IsOpen() ) if ( oCItem* item = player->inventory2.GetSelectedItem() ) { - AddSeparator( item->_GetClassDef()->className ); InfoItem( item ); return true; } @@ -209,8 +278,6 @@ namespace GOTHIC_ENGINE { if ( !vob ) return false; - AddSeparator( vob->_GetClassDef()->className ); - if ( oCNpc* npc = vob->CastTo() ) InfoNpc( npc ); else if ( oCItem* item = vob->CastTo() ) @@ -224,30 +291,48 @@ namespace GOTHIC_ENGINE { void DebugHelper::Clear() { if ( mainView == nullptr ) return; - mainView->RemoveItem( textView ); - mainView->RemoveItem( sideView ); - screen->RemoveItem( mainView ); - textView = nullptr; - sideView = nullptr; - mainView = nullptr; + del( leftView ); + del( rightView ); + del( mainView ); + } + + void DebugHelper::ShowTriggerBoxes() { + if (!Options::ShowTriggers) { + return; + } + + zCArray listVobs; + player->CreateVobList(listVobs, 5000.0f); + for (int i = 0; i < listVobs.GetNumInList(); i++) + { + auto vob = listVobs[i]; + + if (!vob) + continue; + + auto trigger = vob->CastTo(); + if (!trigger) + continue; + + trigger->bbox3D.Draw(GFX_RED); + } } - void DebugHelper::DebugHelperLoop() { + void DebugHelper::Loop() { if ( !Options::UsingDebugHelper || ogame->pause_screen - || zcon->IsVisible() - || !ogame->showPlayerStatus - || player->inventory2.GetNextContainerLeft( &player->inventory2 ) ) { + || playerHelper.IsConUp() + || quickSave->IsBusy() + || !ogame->game_drawall + || playerHelper.LeftInvOpen() ) { Clear(); return; } if ( mainView == nullptr ) { - float sysScale; - Union.GetSysPackOption().Read( sysScale, "INTERFACE", "Scale", 1.0f ); - int scaleBonus = 512 * sysScale; + int offset = 512 * playerHelper.GetSysScale(); - mainView = new zCView( 0, 1024 - scaleBonus, 2304 + scaleBonus, 7168 + scaleBonus ); + mainView = new zCView( 0, 1024 - offset, 3456 + offset, 7168 + offset ); mainView->InsertBack( "BLACKBACK" ); mainView->SetAlphaBlendFunc( zRND_ALPHA_FUNC_BLEND ); mainView->SetTransparency( 150 ); @@ -256,15 +341,18 @@ namespace GOTHIC_ENGINE { textHeight = mainView->FontY(); margin = textHeight; - textView = new zCView( margin, 0, 8192 - margin, 8192 ); - sideView = new zCView( margin + 8192 * 0.6f, 0, 8192 - margin, 8192 ); - mainView->InsertItem( textView ); - mainView->InsertItem( sideView ); + leftView = new zCView( margin, 0, 8192 - margin, 8192 ); + rightView = new zCView( margin + 8192 * 0.6f, 0, 8192 - margin, 8192 ); + mainView->InsertItem( leftView ); + mainView->InsertItem( rightView ); } - textView->ClrPrintwin(); - sideView->ClrPrintwin(); - textLines = 0; + leftView->ClrPrintwin(); + rightView->ClrPrintwin(); + textLinesLeft = 0; + textLinesRight = 0; + + ShowTriggerBoxes(); if ( TryPrintInfo() ) return; diff --git a/zUtilities/DebugHelper.h b/zUtilities/DebugHelper.h index 800821b..ab96dcd 100644 --- a/zUtilities/DebugHelper.h +++ b/zUtilities/DebugHelper.h @@ -4,28 +4,31 @@ namespace GOTHIC_ENGINE { namespace Options { bool UsingDebugHelper = false; + bool ShowTriggers = false; } class DebugHelper { private: zCView* mainView; - zCView* textView; - zCView* sideView; + zCView* leftView; + zCView* rightView; - int textLines; + int textLinesLeft; + int textLinesRight; int textHeight; int margin; void InfoNpc( oCNpc* npc ); void InfoItem( oCItem* item ); void InfoMob( oCMOB* mob ); - void AddSeparator( zSTRING str = "" ); + void AddSeparator( zCView* view, zSTRING str = "" ); void Print( zCView* view, zSTRING name, zSTRING value ); bool TryPrintInfo(); + void ShowTriggerBoxes(); public: void Clear(); - void DebugHelperLoop(); + void Loop(); }; DebugHelper debugHelper; diff --git a/zUtilities/Dialogue.cpp b/zUtilities/Dialogue.cpp new file mode 100644 index 0000000..3537ffb --- /dev/null +++ b/zUtilities/Dialogue.cpp @@ -0,0 +1,67 @@ +// Supported with union (c) 2020 Union team +// Union SOURCE file + +namespace GOTHIC_ENGINE { + int choiceTextLine = 0; + + HOOK Hook_zCViewPrint_Blit PATCH( &zCViewPrint::Blit, &zCViewPrint::Blit_Union ); + void zCViewPrint::Blit_Union() { + if ( !Options::AlternativeDialogueBoxes || this != oCInformationManager::GetInformationManager().DlgChoice ) { + THISCALL( Hook_zCViewPrint_Blit )(); + return; + } + + if ( VirtualPosition.X != 0 ) { + VirtualPosition.X = 0; + SetVirtualPosition( VirtualPosition ); + } + + if ( VirtualSize.X != 8192 ) { + VirtualSize.X = 8192; + SetVirtualSize( VirtualSize ); + } + + choiceTextLine = 0; + + THISCALL( Hook_zCViewPrint_Blit )(); + } + + HOOK Hook_zCViewPrint_BlitTextCharacters PATCH( &zCViewPrint::BlitTextCharacters, &zCViewPrint::BlitTextCharacters_Union ); + void zCViewPrint::BlitTextCharacters_Union( zCViewText2* a1, zCFont* a2, zCOLOR& a3 ) { + if ( !Options::AlternativeDialogueBoxes || this != oCInformationManager::GetInformationManager().DlgChoice ) { + THISCALL( Hook_zCViewPrint_BlitTextCharacters )(a1, a2, a3); + return; + } + + int vx = VirtualSize.X / 2 - screen->FontSize( a1->Text ) / 2; + int px = screen->nax( vx ); + a1->PixelPosition.X = px; + + bool offLimits = VirtualSize.Y - SizeMargin[0].Y - SizeMargin[1].Y - screen->FontY() * (ListTextLines.GetNumInList() + 1) < 0; + if ( !offLimits ) { + int vy = VirtualSize.Y / 2 - screen->FontY() / 2 * ListTextLines.GetNumInList(); + vy += screen->FontY() * choiceTextLine; + choiceTextLine++; + + int py = screen->nay( vy ); + a1->PixelPosition.Y = py; + } + + THISCALL( Hook_zCViewPrint_BlitTextCharacters )(a1, a2, a3); + } + + HOOK Hook_zCView_DialogMessageCXY PATCH( &zCView::DialogMessageCXY, &zCView::DialogMessageCXY_Union ); + void zCView::DialogMessageCXY_Union( zSTRING const& a1, zSTRING const& a2, float a3, zCOLOR& a4 ) { + if ( !Options::AlternativeDialogueBoxes || !playerHelper.IsInInfo() ) { + THISCALL( Hook_zCView_DialogMessageCXY )(a1, a2, a3, a4); + return; + } + + if ( vposy < 2048 ) { + SetPos( 0, 0 ); + SetSize( 8192, vsizey ); + } + + THISCALL( Hook_zCView_DialogMessageCXY )(a1, a2, a3, a4); + } +} \ No newline at end of file diff --git a/zUtilities/Extensions.h b/zUtilities/Extensions.h new file mode 100644 index 0000000..ed5de96 --- /dev/null +++ b/zUtilities/Extensions.h @@ -0,0 +1,111 @@ +// Supported with union (c) 2020 Union team +// Union HEADER file + +namespace GOTHIC_ENGINE { + int GetTopDmgIndex( int damageArr[], int damagetype ) { + int topDmgAmount = 0, topDmgIndex = 0; + + for ( int i = 0; i < (int)oEDamageIndex::oEDamageIndex_MAX; i++ ) + if ( (oEDamageType)(1 << (oEDamageIndex)i) & damagetype ) + if ( damageArr[i] >= topDmgAmount ) { + topDmgAmount = damageArr[i]; + topDmgIndex = i; + } + + return topDmgIndex; + } + + int oCNpc::GetFistDamageIndex() { + return GetTopDmgIndex( this->damage, this->damagetype ); + } + + int oCNpc::GetWeaponDamageIndex() { + oCItem* weapon = this->GetWeapon(); + + if ( !weapon ) + return Invalid; + + int index = GetTopDmgIndex( weapon->damage, weapon->damageTypes ); + + if ( !weapon->HasFlag( ITM_CAT_FF ) || weapon->munition <= 0 ) + return index; + + oCItem* munition = this->GetHandMunition(); + + if ( !munition ) + return index; + + if ( munition->instanz != weapon->munition ) + return index; + + return GetTopDmgIndex( munition->damage, munition->damageTypes ); + } + + int oCNpc::GetSpellDamageIndex() { + oCMag_Book* book = this->mag_book; + + if ( !book ) + return Invalid; + + oCSpell* spell = book->GetSelectedSpell(); + + if ( !spell ) + return Invalid; + + for ( int i = 0; i < oEIndexDamage::oEDamageIndex_MAX; i++ ) + if ( (oETypeDamage)(1 << (oEIndexDamage)i) & spell->damageType ) + return i; + + return Invalid; + } + + int oCNpc::GetActiveDamageIndex() { + if ( this->IsInFightMode_S( NPC_WEAPON_FIST ) ) + return this->GetFistDamageIndex(); + + if ( this->IsInFightMode_S( NPC_WEAPON_MAG ) ) + return this->GetSpellDamageIndex(); + + return this->GetWeaponDamageIndex(); + } + + oCPortalRoom* zCVob::GetCurrentPortalRoom() { + oCPortalRoomManager* rooms = ogame->GetPortalRoomManager(); + + if ( !rooms ) return nullptr; + + const zSTRING* portalName = this->GetSectorNameVobIsIn(); + + if ( !portalName ) return nullptr; + + int portalIndex = rooms->GetPortalRoomIndex( *portalName ); + + if ( portalIndex == Invalid ) return nullptr; + + return rooms->portals[portalIndex]; + } + + bool zCVob::IsInRoomWith( zCVob* vob ) { + oCPortalRoom* room = this->GetCurrentPortalRoom(); + if ( room == nullptr ) + return false; + + return room == vob->GetCurrentPortalRoom(); + } + + float zCVob::GetHeightDifferenceToVob( zCVob* vob ) { + return std::abs( this->GetPositionWorld()[VY] - vob->GetPositionWorld()[VY] ); + } + + oCItem* oCNpc::GetHandMunition() { + oCItem* weapon = this->GetWeapon(); + + if ( !weapon ) + return nullptr; + + if ( !weapon->HasFlag( ITM_CAT_FF ) || weapon->munition <= 0 ) + return nullptr; + + return (weapon->HasFlag( ITM_FLAG_CROSSBOW )) ? this->GetLeftHand()->CastTo() : this->GetRightHand()->CastTo(); + } +} \ No newline at end of file diff --git a/zUtilities/FocusColor.cpp b/zUtilities/FocusColor.cpp index 545c9cd..8c5f474 100644 --- a/zUtilities/FocusColor.cpp +++ b/zUtilities/FocusColor.cpp @@ -4,9 +4,8 @@ namespace GOTHIC_ENGINE { HOOK Ivk_Print_Union PATCH( &zCView::Print, &zCView::Print_Union ); void zCView::Print_Union( int x, int y, const zSTRING& text ) { - if ( player && !focusColor.AllOptionsOff() && !focusColor.isNameOnScreen && this != focusColor.focusView ) - if ( focusColor.TryPrintName( x, y, text ) ) - return; + if ( focusColor.CanPrintFocus( this, x, y, text ) ) + return; THISCALL( Ivk_Print_Union )(x, y, text); } @@ -29,25 +28,36 @@ namespace GOTHIC_ENGINE { CRIME_MURDER = (sym) ? sym->single_intdata : Invalid; } - bool FocusColor::CanStealNow( oCItem* focusItem ) { - int ZS_Clear = parser->GetIndex( "ZS_ClearRoom" ); + bool FocusColor::CanStealNow( oCItem* item ) { + static const int ZS_Clear = parser->GetIndex( "ZS_ClearRoom" ); #if ENGINE >= Engine_G2 - int ZS_Observe = parser->GetIndex( "ZS_ObservePlayer" ); + static const int ZS_Observe = parser->GetIndex( "ZS_ObservePlayer" ); #else - int ZS_Observe = parser->GetIndex( "ZS_ObservePerson" ); + static const int ZS_Observe = parser->GetIndex( "ZS_ObservePerson" ); #endif if ( !ZS_Observe || !ZS_Clear ) return false; - auto list = ogame->GetGameWorld()->voblist_npcs->GetNextInList(); + static const zCPar_Symbol* sym1 = parser->GetSymbol( "PERC_DIST_INDOOR_HEIGHT" ); + static const int PERC_DIST_INDOOR_HEIGHT = (sym1) ? sym1->single_intdata : 250; + + static const zCPar_Symbol* sym2 = parser->GetSymbol( "PERC_DIST_ACTIVE_MAX" ); + static const int PERC_DIST_ACTIVE_MAX = (sym2) ? sym2->single_intdata : 2000; + + oCPortalRoom* playerRoom = player->GetCurrentPortalRoom(); - while ( list != nullptr ) { - oCNpc* npc = list->GetData(); - list = list->GetNextInList(); + zCArray vobs; + player->CreateVobList( vobs, PERC_DIST_ACTIVE_MAX ); - if ( npc->attribute[NPC_ATR_HITPOINTS] <= 0 || npc == player ) continue; + for ( int i = 0; i < vobs.GetNum(); i++ ) { + oCNpc* npc = vobs[i]->CastTo(); + if ( !npc || !npc->homeWorld ) + continue; + + if ( npc->attribute[NPC_ATR_HITPOINTS] <= 0 || npc == player ) + continue; if ( !npc->HasPerception( NPC_PERC_ASSESSTHEFT ) ) continue; @@ -55,23 +65,30 @@ namespace GOTHIC_ENGINE { if ( !npc->IsInPerceptionRange( NPC_PERC_ASSESSTHEFT, (int)npc->GetDistanceToVob( *player ) ) ) continue; -#if ENGINE < Engine_G2 - if ( npc->GetAivar( "AIV_ITEMSCHWEIN" ) && npc->HasVobDetected( player ) ) +#if ENGINE >= Engine_G2 + if ( playerRoom && playerRoom->GetOwnerGuild() >= NPC_GIL_NONE && (int)player->GetHeightDifferenceToVob( npc ) > PERC_DIST_INDOOR_HEIGHT ) { + continue; + } +#else + if ( npc->HasVobDetected( player ) && npc->GetAivar( "AIV_ITEMSCHWEIN" ) ) return false; #endif - if ( ogame->GetGuilds()->GetAttitude( npc->guild, player->guild ) == NPC_ATT_FRIENDLY ) continue; - if ( npc->IsFriendly( player ) || npc->npcType == TYPE_FRIEND ) continue; + if ( ogame->GetGuilds()->GetAttitude( npc->guild, player->guild ) == NPC_ATT_FRIENDLY ) + continue; + + if ( npc->IsFriendly( player ) || npc->npcType == TYPE_FRIEND ) + continue; - if ( !npc->HasVobDetected( player ) ) { - if ( npc->IsAIState( ZS_Clear ) || npc->IsAIState( ZS_Observe ) ) + if ( !npc->CanSee( player, 0 ) ) { + if ( (npc->IsAIState( ZS_Clear ) || npc->IsAIState( ZS_Observe )) && npc->IsInRoomWith( player ) ) return false; continue; } #if ENGINE < Engine_G2 - if ( !focusItem->owner && !focusItem->ownerGuild ) + if ( !item->owner && !item->ownerGuild ) continue; #endif @@ -82,12 +99,12 @@ namespace GOTHIC_ENGINE { } #if ENGINE >= Engine_G2 - bool FocusColor::CanTakeFromRoom( oCItem* focusItem ) { + bool FocusColor::CanTakeFromRoom( oCItem* item ) { oCPortalRoomManager* rooms = ogame->GetPortalRoomManager(); if ( !rooms ) return true; - const zSTRING* portalName = focusItem->GetSectorNameVobIsIn(); + const zSTRING* portalName = item->GetSectorNameVobIsIn(); if ( !portalName ) return true; @@ -111,40 +128,34 @@ namespace GOTHIC_ENGINE { } int FocusColor::GetAbsolutionLevel( oCNpc* slf ) { - zCPar_Symbol* sym = nullptr; - - sym = parser->GetSymbol( "NPCTYPE_OCAMBIENT" ); - int TYPE_OCAMBIENT = (sym) ? sym->single_intdata : Invalid; - - sym = parser->GetSymbol( "NPCTYPE_OCMAIN" ); - int TYPE_OCMAIN = (sym) ? sym->single_intdata : Invalid; - - sym = parser->GetSymbol( "NPCTYPE_BL_AMBIENT" ); - int TYPE_BL_AMBIENT = (sym) ? sym->single_intdata : Invalid; - - sym = parser->GetSymbol( "NPCTYPE_BL_MAIN" ); - int TYPE_BL_MAIN = (sym) ? sym->single_intdata : Invalid; - - if ( (TYPE_OCAMBIENT && slf->npcType == TYPE_OCAMBIENT) || (TYPE_OCMAIN && slf->npcType == TYPE_OCMAIN) ) { + static const zCPar_Symbol* NPCTYPE_OCAMBIENT = parser->GetSymbol( "NPCTYPE_OCAMBIENT" ); + static const zCPar_Symbol* NPCTYPE_OCMAIN = parser->GetSymbol( "NPCTYPE_OCMAIN" ); + static const zCPar_Symbol* NPCTYPE_BL_AMBIENT = parser->GetSymbol( "NPCTYPE_BL_AMBIENT" ); + static const zCPar_Symbol* NPCTYPE_BL_MAIN = parser->GetSymbol( "NPCTYPE_BL_MAIN" ); + + static const zCPar_Symbol* ABSOLUTIONLEVEL_OldCamp = parser->GetSymbol( "ABSOLUTIONLEVEL_OldCamp" ); + static const zCPar_Symbol* ABSOLUTIONLEVEL_City = parser->GetSymbol( "ABSOLUTIONLEVEL_City" ); + static const zCPar_Symbol* ABSOLUTIONLEVEL_Monastery = parser->GetSymbol( "ABSOLUTIONLEVEL_Monastery" ); + static const zCPar_Symbol* ABSOLUTIONLEVEL_Farm = parser->GetSymbol( "ABSOLUTIONLEVEL_Farm" ); + static const zCPar_Symbol* ABSOLUTIONLEVEL_BL = parser->GetSymbol( "ABSOLUTIONLEVEL_BL" ); + + if ( (NPCTYPE_OCAMBIENT && slf->npcType == NPCTYPE_OCAMBIENT->single_intdata) + || (NPCTYPE_OCMAIN && slf->npcType == NPCTYPE_OCMAIN->single_intdata) ) { if ( slf->guild == NPC_GIL_PALADIN || slf->guild == NPC_GIL_MILIZ || slf->guild == NPC_GIL_VOLK ) - if ( sym = parser->GetSymbol( "ABSOLUTIONLEVEL_OldCamp" ) ) - return sym->single_intdata; + if ( ABSOLUTIONLEVEL_OldCamp ) return ABSOLUTIONLEVEL_OldCamp->single_intdata; } else if ( slf->guild == NPC_GIL_PALADIN || slf->guild == NPC_GIL_MILIZ || slf->guild == NPC_GIL_VOLK ) { - if ( sym = parser->GetSymbol( "ABSOLUTIONLEVEL_City" ) ) - return sym->single_intdata; + if ( ABSOLUTIONLEVEL_City ) return ABSOLUTIONLEVEL_City->single_intdata; } else if ( slf->guild == NPC_GIL_FEUERKREIS || slf->guild == NPC_GIL_NOVIZE ) { - if ( sym = parser->GetSymbol( "ABSOLUTIONLEVEL_Monastery" ) ) - return sym->single_intdata; + if ( ABSOLUTIONLEVEL_Monastery ) return ABSOLUTIONLEVEL_Monastery->single_intdata; } else if ( slf->guild == NPC_GIL_BAUERN ) { - if ( sym = parser->GetSymbol( "ABSOLUTIONLEVEL_Farm" ) ) - return sym->single_intdata; + if ( ABSOLUTIONLEVEL_Farm ) return ABSOLUTIONLEVEL_Farm->single_intdata; } - else if ( (TYPE_BL_AMBIENT && slf->npcType == TYPE_BL_AMBIENT) || (TYPE_BL_MAIN && slf->npcType == TYPE_BL_MAIN) ) { - if ( sym = parser->GetSymbol( "ABSOLUTIONLEVEL_BL" ) ) - return sym->single_intdata; + else if ( (NPCTYPE_BL_AMBIENT && slf->npcType == NPCTYPE_BL_AMBIENT->single_intdata) + || (NPCTYPE_BL_MAIN && slf->npcType == NPCTYPE_BL_MAIN->single_intdata) ) { + if ( ABSOLUTIONLEVEL_BL ) return ABSOLUTIONLEVEL_BL->single_intdata; } return 0; @@ -165,193 +176,286 @@ namespace GOTHIC_ENGINE { } #endif - zCOLOR FocusColor::NpcColor( oCNpc* focusNpc ) { - if ( focusNpc->attribute[NPC_ATR_HITPOINTS] <= 0 ) { - if ( !focusNpc->stealcontainer->contList.GetNumInList() ) + zCOLOR FocusColor::NpcColor( oCNpc* npc ) { + if ( npc->attribute[NPC_ATR_HITPOINTS] <= 0 ) { + if ( !npc->stealcontainer->contList.GetNumInList() ) return zCOLOR( 175, 175, 175 ); else return colDefault; } - bool inAttack = focusNpc->IsAIState( parser->GetIndex( "ZS_Attack" ) ); - bool inReact = focusNpc->IsAIState( parser->GetIndex( "ZS_ReactToDamage" ) ); + static const int ZS_Attack = parser->GetIndex( "ZS_Attack" ); + static const int ZS_ReactToDamage = parser->GetIndex( "ZS_ReactToDamage" ); #if ENGINE >= Engine_G2 - if ( focusNpc->IsHostile( player ) && focusNpc->GetPermAttitude( player ) == NPC_ATT_HOSTILE - || (focusNpc->enemy == player && inAttack && HasReasonToKill( focusNpc )) ) + if ( npc->IsHostile( player ) && npc->GetPermAttitude( player ) == NPC_ATT_HOSTILE + || (npc->enemy == player && npc->IsAIState( ZS_Attack ) && HasReasonToKill( npc )) ) return zCOLOR( 255, 0, 0 ); - if ( focusNpc->IsAngry( player ) || (focusNpc->enemy == player && inAttack) ) + if ( npc->IsAngry( player ) || (npc->enemy == player && npc->IsAIState( ZS_Attack )) ) return zCOLOR( 255, 180, 0 ); int day, hour, min; ogame->GetTime( day, hour, min ); - if ( focusNpc->GetAivar( "AIV_NpcSawPlayerCommit" ) - && !(focusNpc->GetAivar( "AIV_NpcSawPlayerCommit" ) < CRIME_MURDER && focusNpc->GetAivar( "AIV_NpcSawPlayerCommitDay" ) < day - 2) - && !(focusNpc->GetAivar( "AIV_CrimeAbsolutionLevel" ) < GetAbsolutionLevel( focusNpc )) ) + if ( npc->GetAivar( "AIV_NpcSawPlayerCommit" ) + && !(npc->GetAivar( "AIV_NpcSawPlayerCommit" ) < CRIME_MURDER && npc->GetAivar( "AIV_NpcSawPlayerCommitDay" ) < day - 2) + && !(npc->GetAivar( "AIV_CrimeAbsolutionLevel" ) < GetAbsolutionLevel( npc )) ) return zCOLOR( 255, 180, 0 ); #else - if ( (focusNpc->IsHostile( player ) && focusNpc->GetPermAttitude( player ) == NPC_ATT_HOSTILE) - || (focusNpc->enemy == player && inAttack && focusNpc->GetAivar( "AIV_ATTACKREASON" )) ) + if ( (npc->IsHostile( player ) && npc->GetPermAttitude( player ) == NPC_ATT_HOSTILE) + || (npc->enemy == player && npc->IsAIState( ZS_Attack ) && npc->GetAivar( "AIV_ATTACKREASON" )) ) return zCOLOR( 255, 0, 0 ); - if ( (focusNpc->IsAngry( player ) || focusNpc->enemy == player) && (inAttack || inReact) ) + if ( (npc->IsAngry( player ) || npc->enemy == player) && (npc->IsAIState( ZS_Attack ) || npc->IsAIState( ZS_ReactToDamage )) ) return zCOLOR( 255, 180, 0 ); #endif - if ( inReact ) + if ( npc->IsAIState( ZS_ReactToDamage ) ) return colDefault; - if ( focusNpc->GetAivar( "AIV_PARTYMEMBER" ) ) + if ( npc->GetAivar( "AIV_PARTYMEMBER" ) ) return zCOLOR( 51, 235, 255 ); - if ( (focusNpc->IsFriendly( player ) || focusNpc->npcType == TYPE_FRIEND) ) + if ( (npc->IsFriendly( player ) || npc->npcType == TYPE_FRIEND) ) return zCOLOR( 0, 255, 0 ); - if ( ogame->GetGuilds()->GetAttitude( focusNpc->guild, player->guild ) == NPC_ATT_FRIENDLY ) + if ( ogame->GetGuilds()->GetAttitude( npc->guild, player->guild ) == NPC_ATT_FRIENDLY ) return zCOLOR( 175, 255, 175 ); return colDefault; } - zCOLOR FocusColor::ChestColor( oCMobContainer* focusContainer ) { - if ( focusContainer->locked ) - if ( focusContainer->keyInstance != "" ) + zCOLOR FocusColor::LockableColor( oCMobLockable* lockable ) { + if ( lockable->locked ) + if ( lockable->keyInstance.Length() && lockable->pickLockStr.Length() ) + return zCOLOR( 255, 135, 150 ); + else if ( lockable->keyInstance.Length() ) return zCOLOR( 255, 20, 20 ); - else + else if ( lockable->pickLockStr.Length() ) return zCOLOR( 255, 175, 0 ); + else + return zCOLOR( 175, 175, 175 ); - if ( focusContainer->containList.GetNumInList() ) - return zCOLOR( 0, 175, 0 ); - - return zCOLOR( 175, 175, 175 ); - } - - zCOLOR FocusColor::DoorColor( oCMobDoor* focusDoor ) { - if ( focusDoor->locked ) - if ( focusDoor->keyInstance != "" ) - return zCOLOR( 255, 20, 20 ); + if ( oCMobContainer* container = lockable->CastTo() ) + if ( container->containList.GetNumInList() ) + return zCOLOR( 30, 220, 30 ); else - return zCOLOR( 255, 175, 0 ); + return zCOLOR( 175, 175, 175 ); return colDefault; } - zCOLOR FocusColor::ItemColor( oCItem* focusItem ) { + zCOLOR FocusColor::ItemColor( oCItem* item ) { #if ENGINE >= Engine_G2 - if ( focusItem->HasFlag( ITM_FLAG_DROPPED ) ) + if ( item->HasFlag( ITM_FLAG_DROPPED ) ) return colDefault; #endif - if ( focusItem->IsOwnedByNpc( player->GetInstance() ) ) + if ( item->IsOwnedByNpc( player->GetInstance() ) ) return colDefault; - if ( focusItem->IsOwnedByGuild( player->guild ) ) + if ( item->IsOwnedByGuild( player->guild ) ) return colDefault; #if ENGINE >= Engine_G2 - if ( CanTakeFromRoom( focusItem ) ) + if ( CanTakeFromRoom( item ) ) return colDefault; #endif - if ( CanStealNow( focusItem ) ) + if ( CanStealNow( item ) ) return colDefault; return zCOLOR( 255, 200, 100 ); } - zCOLOR FocusColor::CheckFocus( zCVob* focusVob ) { - if ( !TYPE_FRIEND || !CRIME_MURDER ) - InitData(); - - if ( Options::ColorChests ) - if ( oCMobContainer* focusContainer = focusVob->CastTo() ) - return ChestColor( focusContainer ); - - if ( Options::ColorDoors ) - if ( oCMobDoor* focusDoor = focusVob->CastTo() ) - return DoorColor( focusDoor ); + zCOLOR FocusColor::InterColor( oCMobInter* inter ) { + if ( !inter->onStateFuncName.Length() ) + return colDefault; - if ( Options::ColorNpcs ) - if ( oCNpc* focusNpc = focusVob->CastTo() ) - return NpcColor( focusNpc ); + if ( inter->GetScemeName() != "BOOK" ) + return colDefault; - if ( Options::ColorItems ) - if ( oCItem* focusItem = focusVob->CastTo() ) - return ItemColor( focusItem ); + if ( playerStatus.KnowStateFunc( inter ) ) + return colDefault; - return colDefault; + return zCOLOR( 30, 220, 30 ); } - zSTRING FocusColor::GetName( zCVob* focusVob ) { - if ( Options::ColorChests ) - if ( oCMobContainer* focusContainer = focusVob->CastTo() ) - return focusContainer->GetName(); + zCOLOR FocusColor::GetFocusColor( zCVob* vob ) { + if ( !TYPE_FRIEND || !CRIME_MURDER ) + InitData(); - if ( Options::ColorDoors ) - if ( oCMobDoor* focusDoor = focusVob->CastTo() ) - return focusDoor->GetName(); + if ( Options::ColorLockables ) + if ( oCMobLockable* lockable = vob->CastTo() ) + return LockableColor( lockable ); if ( Options::ColorNpcs ) - if ( oCNpc* focusNpc = focusVob->CastTo() ) - return focusNpc->name[0]; + if ( oCNpc* npc = vob->CastTo() ) + return NpcColor( npc ); if ( Options::ColorItems ) - if ( oCItem* focusItem = focusVob->CastTo() ) - return focusItem->name; + if ( oCItem* item = vob->CastTo() ) + return ItemColor( item ); - return ""; + if ( Options::ColorInter ) + if ( oCMobInter* inter = vob->CastTo() ) + return InterColor( inter ); + + return colDefault; } - bool FocusColor::TryPrintName( int x, int y, const zSTRING& text ) { - //if ( AllOptionsOff() ) - // return false; + zSTRING FocusColor::GetName( zCVob* vob ) { + if ( oCMobLockable* lockable = vob->CastTo() ) + return lockable->GetName(); - if ( playerHelper.IsInInfo() ) - return false; + if ( oCNpc* npc = vob->CastTo() ) + return npc->name[0]; - zCVob* focusVob = player->GetFocusVob(); - if ( !focusVob ) return false; + if ( oCItem* item = vob->CastTo() ) + return item->name; - zSTRING name = GetName( focusVob ); + if ( oCMobInter* inter = vob->CastTo() ) + return inter->GetName(); - if ( text != name + "\n" && text != name ) return false; + return ""; + } - zCOLOR col = CheckFocus( focusVob ); + bool FocusColor::TryPrintFocus( int x, int y, zSTRING name, zCVob* vob ) { + zCOLOR col = GetFocusColor( vob ); if ( col.GetDescription() == colDefault.GetDescription() ) - return false; + col = screen->GetColor(); if ( focusView == nullptr ) { focusView = new zCView( 0, 0, 8192, 8192 ); screen->InsertItem( focusView ); + + if ( protView == nullptr ) { + protView = new zCView( 0, 0, 8192, 8192 ); + focusView->InsertItem( protView ); + } + } + else { + protView->ClrPrintwin(); + focusView->ClrPrintwin(); + } + + if ( playerStatus.focusBar && playerStatus.focusBar->NeedAdjustPosition( x, y, vob->CastTo() ) ) { + x = ogame->focusBar->vposx + ogame->focusBar->vsizex / 2 - focusView->FontSize( name ) / 2; + y = ogame->focusBar->vposy + ogame->focusBar->vsizey / 2 + focusView->FontY(); } - focusView->ClrPrintwin(); + if ( ogame->hpBar ) + col.alpha = ogame->hpBar->alpha; + focusView->SetFontColor( col ); - focusView->Print( x, y, text ); - isNameOnScreen = true; + focusView->Print( x, y, name ); + vobOnScreen = true; + + if ( oCNpc* npc = vob->CastTo() ) { + TryAddIcons( x, y, name, npc ); + TryShowProt( npc ); + } + return true; } - bool FocusColor::AllOptionsOff() { - return !Options::ColorNpcs && !Options::ColorChests && !Options::ColorDoors && !Options::ColorItems; + void FocusColor::TryAddIcons( int x, int y, zSTRING name, oCNpc* npc ) { + if ( npc->attribute[NPC_ATR_HITPOINTS] <= 0 ) + return; + + int iconNr = 1; + int startX = x + focusView->FontSize( name ); + int margin = focusView->FontY() * 0.1f; + int size = focusView->FontY() * 0.55f; + +#if ENGINE >= Engine_G2 + if ( Options::ShowPickpocketIcon && playerStatus.CanPickpocketNpc( npc ) ) { + zCOLOR color = zCOLOR( 241, 196, 15, ogame->hpBar->alpha ); + zSTRING texture = "LABEL_MONEY"; // https://game-icons.net/1x1/delapouite/two-coins.html + IconInfo icon = IconInfo( startX + margin * iconNr + size * (iconNr++ - 1), y, size, color, texture ); + } +#endif } - void FocusColor::FocusColorLoop() { - if ( AllOptionsOff() ) + void FocusColor::TryShowProt( oCNpc* npc ) { + if ( !Options::ShowTargetProtection ) + return; + + if ( npc->attribute[NPC_ATR_HITPOINTS] <= 0 ) + return; + + if ( player->IsInFightMode_S( 0 ) ) + return; + + oCViewStatusBar* bar = ogame->focusBar; + + if ( !bar ) return; - if ( focusView == nullptr ) + int dmgIndex = player->GetActiveDamageIndex(); + if ( !dmgIndex ) return; - focusView->ClrPrintwin(); - isNameOnScreen = false; + int protection = npc->GetProtectionByIndex( (oEIndexDamage)dmgIndex ); + bool isImmune = protection < 0 || npc->HasFlag( NPC_FLAG_IMMORTAL ); - zCVob* focusVob = player->GetFocusVob(); - if ( !focusVob ) { - screen->RemoveItem( focusView ); - focusView = nullptr; - }; + int margin = protView->FontY() * 0.1f; + int size = protView->FontY() * 0.75f; + + int startX = bar->vposx + bar->vsizex; + int iconY = bar->vposy + bar->vsizey / 2 - size; + int fontY = bar->vposy + bar->vsizey / 2 - protView->FontY() / 2; + + int iconNr = 1; + + zCOLOR color = isImmune ? Colors::Gray : Colors::GetColorByDamageIndex( (oEIndexDamage)dmgIndex ); + if ( ogame->hpBar ) + color.alpha = ogame->hpBar->alpha; + + zSTRING texture = "ICON_PROTECTIONS"; // https://game-icons.net/1x1/lorc/cracked-shield.html + IconInfo icon = IconInfo( startX + margin * iconNr + size * (iconNr++ - 1), iconY, size, color, texture ); + + if ( !isImmune ) { + protView->SetFontColor( color ); + protView->Print( startX + margin * iconNr + size * (iconNr++ - 1), fontY, A protection ); + } + } + + bool FocusColor::CanPrintFocus( zCView* view, int x, int y, const zSTRING& text ) { + if ( !player || playerHelper.IsInInfo() || view == focusColor.focusView || focusColor.vobOnScreen ) + return false; + + zCVob* vob = player->GetFocusVob(); + if ( !vob ) return false; + + zSTRING name = GetName( vob ); + if ( text != name + "\n" && text != name + " (locked)\n" ) + return false; + + return focusColor.TryPrintFocus( x, y, text, vob ); + } + + void FocusColor::Clear() { + if ( focusView ) + vobOnScreen = false; + + del( protView ); + del( focusView ); + } + + void FocusColor::Loop() { + if ( focusView ) { + protView->ClrPrintwin(); + focusView->ClrPrintwin(); + } + + vobOnScreen = false; + + zCVob* vob = player->GetFocusVob(); + if ( !vob || quickSave->IsBusy() || ogame->IsOnPause() ) { + Clear(); + return; + } } } \ No newline at end of file diff --git a/zUtilities/FocusColor.h b/zUtilities/FocusColor.h index 54666ba..fa02833 100644 --- a/zUtilities/FocusColor.h +++ b/zUtilities/FocusColor.h @@ -3,19 +3,22 @@ namespace GOTHIC_ENGINE { namespace Options { - int ColorNpcs, ColorChests, ColorDoors, ColorItems; + bool ColorNpcs, ColorLockables, ColorItems, ColorInter; void FocusColor() { - ColorNpcs = zoptions->ReadInt( PLUGIN_NAME, "ColorNpcs", true ); - ColorChests = zoptions->ReadInt( PLUGIN_NAME, "ColorChests", true ); - ColorDoors = zoptions->ReadInt( PLUGIN_NAME, "ColorDoors", true ); - ColorItems = zoptions->ReadInt( PLUGIN_NAME, "ColorItems", true ); + ColorNpcs = zoptions->ReadBool( PLUGIN_NAME, "ColorNpcs", true ); + ColorLockables = zoptions->ReadBool( PLUGIN_NAME, "ColorLockables", true ); + ColorItems = zoptions->ReadBool( PLUGIN_NAME, "ColorItems", true ); + ColorInter = zoptions->ReadBool( PLUGIN_NAME, "ColorInter", true ); } } class FocusColor { private: + zCView* focusView; + zCView* protView; zCOLOR colDefault = zCOLOR( 255, 255, 255 ); + bool vobOnScreen = false; int TYPE_FRIEND; int CRIME_MURDER; @@ -25,19 +28,20 @@ namespace GOTHIC_ENGINE { bool HasReasonToKill( oCNpc* slf ); bool CanStealNow( oCItem* item ); bool CanTakeFromRoom( oCItem* item ); - zSTRING GetName( zCVob* focusVob ); - zCOLOR CheckFocus( zCVob* focusVob ); - zCOLOR DoorColor( oCMobDoor* focusDoor ); - zCOLOR ChestColor( oCMobContainer* focusContainer ); - zCOLOR NpcColor( oCNpc* focusNpc ); - zCOLOR ItemColor( oCItem* focusItem ); + zSTRING GetName( zCVob* vob ); + zCOLOR GetFocusColor( zCVob* vob ); + zCOLOR LockableColor( oCMobLockable* lockable ); + zCOLOR InterColor( oCMobInter* inter ); + zCOLOR NpcColor( oCNpc* npc ); + zCOLOR ItemColor( oCItem* item ); + bool TryPrintFocus( int x, int y, zSTRING name, zCVob* vob ); + void TryAddIcons( int x, int y, zSTRING name, oCNpc* npc ); + void TryShowProt( oCNpc* npc ); public: - zCView* focusView; - bool isNameOnScreen; - bool TryPrintName( int x, int y, const zSTRING& text ); - void FocusColorLoop(); - bool AllOptionsOff(); + bool CanPrintFocus( zCView* view, int x, int y, const zSTRING& text ); + void Clear(); + void Loop(); }; FocusColor focusColor; diff --git a/zUtilities/Headers.h b/zUtilities/Headers.h index 47b6d0a..7cd3f71 100644 --- a/zUtilities/Headers.h +++ b/zUtilities/Headers.h @@ -2,15 +2,24 @@ // Add your headers this // Automatically generated block +#include #pragma region Includes +#include "Const.h" +#include "Colors.h" +#include "Extensions.h" #include "Randomizer.h" -#include "Options.h" +#include "KeyCode.h" +#include "IconInfo.h" #include "PlayerHelper.h" #include "DebugHelper.h" #include "FocusColor.h" #include "QuickSave.h" #include "ItemLabel.h" #include "DamagePopup.h" +#include "StatusBar.h" +#include "LogBook.h" +#include "PlayerStatus.h" +#include "Options.h" #include "Plugin.h" #pragma endregion diff --git a/zUtilities/IconInfo.cpp b/zUtilities/IconInfo.cpp new file mode 100644 index 0000000..e26d2be --- /dev/null +++ b/zUtilities/IconInfo.cpp @@ -0,0 +1,55 @@ +// Supported with union (c) 2020 Union team +// Union SOURCE file + +namespace GOTHIC_ENGINE { + void IconInfo::Draw() { + if ( !ogame || !player ) + return; + + if ( quickSave->IsBusy() || !ogame->GetShowPlayerStatus() || !ogame->game_drawall || ogame->IsOnPause() || playerHelper.IsInInfo() || player->attribute[NPC_ATR_HITPOINTS] <= 0 ) + return; + + RestoreViewport(); //because some plugins don't restore viewport after Blitting, so it messes with prints in other plugins + DrawIcon(); + PrintText(); + } + + void IconInfo::DrawIcon() { + px1 = screen->nax( vx ); + py1 = screen->nay( vy ); + psize = screen->nax( vsize ); + px2 = px1 + psize; + py2 = py1 + psize; + + float z = ZenDef( 0.9f, 0.9f, 1.1f, 1.1f ); + zCTexture* texture = texture->Load( texName, true ); + zrenderer->DrawTile( texture, zVEC2( px1, py1 ), zVEC2( px2, py2 ), z, zVEC2( 0, 0 ), zVEC2( 1.0f, 1.0f ), color ); + texture->Release(); + } + + void IconInfo::PrintText() { + if ( !text.Length() ) + return; + + int x = vx + vsize + screen->FontY() / 10; + int y = vy + (screen->any( py2 ) - vy) / 2 - screen->FontY() / 2; + + zCView* view = new zCView( 0, 0, 8192, 8192 ); + view->SetFontColor( zCOLOR( 255, 255, 255, color.alpha ) ); + screen->InsertItem( view ); + view->Print( x, y, text ); + view->BlitText(); + delete view; + } + + void IconInfo::RestoreViewport() { + int ScreenX, ScreenY, ScreenSX, ScreenSY; + screen->GetViewport(ScreenX, ScreenY, ScreenSX, ScreenSY); + zrenderer->SetViewport(ScreenX, ScreenY, ScreenSX, ScreenSY); + } + + IconInfo::IconInfo( int x, int y, int size, zCOLOR color, zSTRING texName, zSTRING text = "" ) + : vx( x ), vy( y ), vsize( size ), color( color ), texName( texName ), text( text ) { + Draw(); + }; +} \ No newline at end of file diff --git a/zUtilities/IconInfo.h b/zUtilities/IconInfo.h new file mode 100644 index 0000000..bddb4b3 --- /dev/null +++ b/zUtilities/IconInfo.h @@ -0,0 +1,29 @@ +// Supported with union (c) 2020 Union team +// Union HEADER file + +namespace GOTHIC_ENGINE { + class IconInfo { + private: + int vx; + int vy; + int vsize; + + int px1; + int px2; + int py1; + int py2; + int psize; + + zCOLOR color; + zSTRING texName; + zSTRING text; + + void Draw(); + void DrawIcon(); + void PrintText(); + void RestoreViewport(); + + public: + IconInfo( int x, int y, int size, zCOLOR color, zSTRING texName, zSTRING text ); + }; +} \ No newline at end of file diff --git a/zUtilities/Interface.cpp b/zUtilities/Interface.cpp index 099c2eb..1eeee89 100644 --- a/zUtilities/Interface.cpp +++ b/zUtilities/Interface.cpp @@ -5,7 +5,6 @@ #pragma comment (lib,"Gdiplus.lib") using namespace Gdiplus; - // Static RTTI DynamicCast pointer #if _DLL != 1 extern void* __cdecl __RTDynamicCast( void*, long, void*, void*, int ); @@ -13,7 +12,6 @@ extern "C" __declspec(dllexport) uint RTDynamicCast_MT = (uint)__RTDynamicCast; #endif - // Check executed engine with current source code #define CHECK_THIS_ENGINE (Union.GetEngineVersion() == ENGINE) #define Engine_G1 1 @@ -21,7 +19,6 @@ uint RTDynamicCast_MT = (uint)__RTDynamicCast; #define Engine_G2 3 #define Engine_G2A 4 - // Include headers #ifdef __G1 #define GOTHIC_ENGINE Gothic_I_Classic @@ -44,7 +41,6 @@ uint RTDynamicCast_MT = (uint)__RTDynamicCast; #include "Headers.h" #endif - // Include source files (with same as header parameters) #ifdef __G1 #define GOTHIC_ENGINE Gothic_I_Classic diff --git a/zUtilities/Inventory.cpp b/zUtilities/Inventory.cpp new file mode 100644 index 0000000..512cb67 --- /dev/null +++ b/zUtilities/Inventory.cpp @@ -0,0 +1,80 @@ +// Supported with union (c) 2020 Union team +// Union SOURCE file + +namespace GOTHIC_ENGINE { + oCItem* lastActiveMunition; + + void HandleMunition( oCItem* weapon ) { + if ( weapon == nullptr ) { + if ( lastActiveMunition ) { + lastActiveMunition->ClearFlag( ITM_FLAG_ACTIVE ); + lastActiveMunition = nullptr; + } + return; + } + + player->inventory2.UnpackAllItems(); + oCItem* munition = player->IsInInv( weapon->munition, 1 ); + + if ( !munition ) + return; + + if ( munition->HasFlag( ITM_FLAG_ACTIVE ) ) + return; + + munition->SetFlag( ITM_FLAG_ACTIVE ); + + if ( lastActiveMunition ) + if ( lastActiveMunition != munition ) + lastActiveMunition->ClearFlag( ITM_FLAG_ACTIVE ); + + lastActiveMunition = munition; + } + + void HandleMunitionLoop() { + if ( !Options::ActivateUsedMunition ) + return; + + if (!player->inventory2.IsOpen()) + return; + + if (lastActiveMunition) { + if (player->inventory2.IsIn(lastActiveMunition, 1) == nullptr + && player->GetLeftHand() != lastActiveMunition + && player->GetRightHand() != lastActiveMunition) { + lastActiveMunition = nullptr; + } + } + + if ( playerStatus.traderNpc ) { + HandleMunition( nullptr ); + return; + } + + oCItem* weapon = player->GetEquippedRangedWeapon(); + + if ( !weapon ) weapon = player->GetWeapon(); + + if ( !weapon || !weapon->HasFlag( ITM_CAT_FF ) || !weapon->munition ) { + HandleMunition( nullptr ); + return; + } + + if ( lastActiveMunition && weapon->munition == lastActiveMunition->instanz ) + return; + + HandleMunition( weapon ); + } + + HOOK Hook_oCInformationManager_OnTradeBegin PATCH( &oCInformationManager::OnTradeBegin, &oCInformationManager::OnTradeBegin_Union ); + void oCInformationManager::OnTradeBegin_Union() { + THISCALL( Hook_oCInformationManager_OnTradeBegin )(); + playerStatus.traderNpc = Npc; + } + + HOOK Hook_oCItemContainer_Close PATCH( &oCItemContainer::Close, &oCItemContainer::Close_Union ); + void oCItemContainer::Close_Union() { + playerStatus.traderNpc = nullptr; + THISCALL( Hook_oCItemContainer_Close )(); + } +} \ No newline at end of file diff --git a/zUtilities/ItemLabel.cpp b/zUtilities/ItemLabel.cpp index 959f4af..2234504 100644 --- a/zUtilities/ItemLabel.cpp +++ b/zUtilities/ItemLabel.cpp @@ -2,6 +2,22 @@ // Union SOURCE file namespace GOTHIC_ENGINE { + bool canDrawLabels; + + HOOK Hook_oCItemContainer_Draw PATCH( &oCItemContainer::Draw, &oCItemContainer::Draw_Union ); + void oCItemContainer::Draw_Union() { + canDrawLabels = true; + THISCALL( Hook_oCItemContainer_Draw )(); + canDrawLabels = false; + } + + HOOK Hook_oCItemContainer_DrawItemInfo PATCH( &oCItemContainer::DrawItemInfo, &oCItemContainer::DrawItemInfo_Union ); + void oCItemContainer::DrawItemInfo_Union( oCItem* item, zCWorld* world ) { + canDrawLabels = false; + THISCALL( Hook_oCItemContainer_DrawItemInfo )(item, world); + canDrawLabels = true; + } + int oCItem::GetHighestCond() { int maxCond = 0; int maxIndex = -1; @@ -15,25 +31,16 @@ namespace GOTHIC_ENGINE { return (maxIndex != -1) ? this->cond_atr[maxIndex] : -1; } - bool ItemLabel::CanDrawLabel( zCViewBase* viewBase ) { - auto list = oCItemContainer::contList.GetNextInList(); - while ( list != nullptr ) { - oCItemContainer* container = list->GetData(); - list = list->GetNextInList(); - - if ( viewBase == container->viewItem -#if ENGINE < Engine_G2 - || viewBase == container->viewItemFocus - || viewBase == container->viewItemActiveFocus - || viewBase == container->viewItemHightlightedFocus - || viewBase == container->viewItemActiveHighlightedFocus -#endif - || viewBase == container->viewItemActive - || viewBase == container->viewItemHightlighted - || viewBase == container->viewItemActiveHighlighted ) - return true; - } - return false; + int oCItem::GetStateFunc() { + for ( int i = 0; i < ITM_STATE_MAX; i++ ) + if ( this->onState[i] ) + return this->onState[i]; + + return Invalid; + } + + bool ItemLabel::CanDrawLabel() { + return canDrawLabels; } void ItemLabel::SetLabelParams() { @@ -48,6 +55,7 @@ namespace GOTHIC_ENGINE { zCOLOR goldYellow = zCOLOR( 241, 196, 15 ); zCOLOR grey = zCOLOR( 189, 195, 199 ); zCOLOR lightBronze = zCOLOR( 205, 127, 50 ); + zCOLOR statePink = zCOLOR( 255, 171, 243 ); // ITEM_MISSION if ( Options::LabelMissionItems && item->HasFlag( ITM_FLAG_MI ) ) { @@ -56,70 +64,50 @@ namespace GOTHIC_ENGINE { return; } - // Melee - if ( item->HasFlag( ITM_CAT_NF ) ) { - - if ( item->HasFlag( ITM_FLAG_2HD_AXE ) || item->HasFlag( ITM_FLAG_2HD_SWD ) ) { - if ( condAtr == NPC_ATR_MANAMAX ) { - color = manaBlue; - texture = "WPN_MANA_2H"; // https://game-icons.net/1x1/lorc/moebius-star.html - return; - } - - if ( condAtr == NPC_ATR_DEXTERITY ) { - color = dexGreen; - texture = "WPN_DEX_2H"; // https://game-icons.net/1x1/lorc/barbed-spear.html - return; - } - - if ( item->damageTypes == oEDamageType_Blunt ) { - color = bluntYellow; - texture = "WPN_MACE_2H"; // https://game-icons.net/1x1/lorc/gavel.html - return; - } - - if ( item->HasFlag( ITM_FLAG_2HD_AXE ) ) { - color = strRed; - texture = "WPN_AXE_2H"; // https://game-icons.net/1x1/lorc/battle-axe.html - return; - } + static const zCPar_Symbol* ITEM_ARMREIF = parser->GetSymbol( "ITEM_ARMREIF" ); + static const int ITM_FLAG_ARMREIF = (ITEM_ARMREIF) ? ITEM_ARMREIF->single_intdata : Invalid; - color = strRed; - texture = "WPN_SWORD_2H"; // https://game-icons.net/1x1/lorc/shard-sword.html + if ( ITM_FLAG_ARMREIF && item->HasFlag( ITM_CAT_MAGIC ) ) { + if ( item->GetInstanceName().StartWith( "ITBR" ) ) { + color = zCOLOR( 83, 64, 214 ); + texture = "BRACELET"; // https://game-icons.net/1x1/cathelineau/torc.html return; } - - if ( item->HasFlag( ITM_FLAG_SWD ) || item->HasFlag( ITM_FLAG_AXE ) || item->HasFlag( ITM_FLAG_DAG ) ) { - if ( condAtr == NPC_ATR_MANAMAX ) { - color = manaBlue; - texture = "WPN_MANA"; // https://game-icons.net/1x1/lorc/rune-sword.html - return; - } - - if ( condAtr == NPC_ATR_DEXTERITY || item->HasFlag( ITM_FLAG_DAG ) ) { - color = dexGreen; - texture = "WPN_DEX"; // https://game-icons.net/1x1/lorc/sacrificial-dagger.html - return; - } - - if ( item->damageTypes == oEDamageType_Blunt ) { - color = bluntYellow; - texture = "WPN_MACE"; // https://game-icons.net/1x1/lorc/spiked-mace.html - return; - } - - if ( item->HasFlag( ITM_FLAG_AXE ) ) { - color = strRed; - texture = "WPN_AXE"; // https://game-icons.net/1x1/lorc/battered-axe.html - return; - } - - color = strRed; - texture = "WPN_SWORD"; // https://game-icons.net/1x1/skoll/gladius.html + else if ( item->GetInstanceName().StartWith( "ITAR" ) ) { + color = zCOLOR( 199, 169, 149 ); + texture = "SHOES"; // https://game-icons.net/1x1/lorc/tread.html return; } } + // Melee + if ( item->HasFlag( ITM_CAT_NF ) && !item->HasFlag( ITM_FLAG_SHIELD ) ) { + if ( condAtr == NPC_ATR_MANAMAX || item->mag_circle ) + color = manaBlue; + else if ( condAtr == NPC_ATR_DEXTERITY ) + color = dexGreen; + else if ( item->damageTypes & oEDamageType_Blunt ) + color = bluntYellow; + else + color = strRed; + + if ( item->damageTypes & oEDamageType_Magic ) + texture = "WPN_MANA"; // https://game-icons.net/1x1/lorc/barbed-spear.html + else if ( item->damageTypes & oEDamageType_Point ) + texture = "WPN_DEX"; // https://game-icons.net/1x1/lorc/barbed-spear.html + else if ( item->damageTypes & oEDamageType_Blunt ) + texture = "WPN_MACE"; // https://game-icons.net/1x1/lorc/gavel.html + else if ( item->HasFlag( ITM_FLAG_2HD_AXE ) ) + texture = "WPN_AXE"; // https://game-icons.net/1x1/lorc/battle-axe.html + else + texture = "WPN_SWORD"; // https://game-icons.net/1x1/lorc/shard-sword.html + + if ( item->HasFlag( ITM_FLAG_2HD_AXE ) || item->HasFlag( ITM_FLAG_2HD_SWD ) ) + texture = texture + "_2H"; + + return; + } + // Ranged if ( item->HasFlag( ITM_CAT_FF ) ) { if ( item->HasFlag( ITM_FLAG_BOW ) ) { @@ -150,6 +138,13 @@ namespace GOTHIC_ENGINE { } } + // Shield + if ( item->HasFlag( ITM_FLAG_SHIELD ) ) { + color = zCOLOR( 247, 143, 179 ); + texture = "SHIELD"; // https://game-icons.net/1x1/lorc/checked-shield.html + return; + } + // Armors if ( item->HasFlag( ITM_CAT_ARMOR ) ) { if ( item->wear == ITM_WEAR_HEAD ) { @@ -175,12 +170,6 @@ namespace GOTHIC_ENGINE { return; } - if ( item->HasFlag( ITM_FLAG_SHIELD ) ) { - color = zCOLOR( 247, 143, 179 ); - texture = "SHIELD"; // https://game-icons.net/1x1/lorc/checked-shield.html - return; - } - if ( item->HasFlag( ITM_FLAG_AMULET ) && !item->HasFlag( ITM_CAT_NONE ) ) { color = zCOLOR( 190, 46, 221 ); texture = "AMULET"; // https://game-icons.net/1x1/lorc/gem-chain.html @@ -226,7 +215,7 @@ namespace GOTHIC_ENGINE { } if ( item->HasFlag( ITM_CAT_RUNE ) ) { - if ( item->GetInstanceName().StartWith( "ITRU" ) || item->GetInstanceName().StartWith( "ITARRUNE" ) ) { + if ( !item->HasFlag( ITM_FLAG_MULTI ) ) { color = zCOLOR( 217, 128, 250 ); texture = "RUNE"; // https://game-icons.net/1x1/lorc/cursed-star.html return; @@ -247,17 +236,17 @@ namespace GOTHIC_ENGINE { if ( item->GetSoundMaterial() == SND_MAT_STONE ) { color = grey; texture = "TABLET"; // https://game-icons.net/1x1/lorc/stone-tablet.html - return; } - - if ( item->GetInstanceName().HasWord( "MAP" ) ) { + else if ( item->GetInstanceName().HasWord( "MAP" ) ) { color = goldYellow; texture = "MAP"; // https://game-icons.net/1x1/lorc/treasure-map.html - return; + } + else { + color = zCOLOR( 153, 128, 250 ); + texture = "DOCS"; // https://game-icons.net/1x1/lorc/tied-scroll.html } - color = zCOLOR( 153, 128, 250 ); - texture = "DOCS"; // https://game-icons.net/1x1/lorc/tied-scroll.html + color = (!playerStatus.KnowStateFunc( item )) ? statePink : color; return; } @@ -267,9 +256,10 @@ namespace GOTHIC_ENGINE { return; } - if ( item->GetInstanceName().StartWith( "ITKE" ) ) { - color = zCOLOR( 113, 128, 147 ); - texture = "KEY"; // https://game-icons.net/1x1/lorc/key.html + static const zCPar_Symbol* TRADE_CURRENCY_INSTANCE = parser->GetSymbol( "TRADE_CURRENCY_INSTANCE" ); + if ( TRADE_CURRENCY_INSTANCE && TRADE_CURRENCY_INSTANCE->stringdata == item->GetInstanceName() ) { + color = goldYellow; + texture = "MONEY"; // https://game-icons.net/1x1/delapouite/two-coins.html return; } @@ -279,32 +269,31 @@ namespace GOTHIC_ENGINE { return; } + if ( item->GetInstanceName().StartWith( "ITKE" ) ) { + color = zCOLOR( 113, 128, 147 ); + texture = "KEY"; // https://game-icons.net/1x1/lorc/key.html + } + if ( item->GetInstanceName().StartWith( "ITAT" ) ) { color = lightBronze; texture = "TROPHY"; // https://game-icons.net/1x1/lorc/flat-paw-print.html - return; } - if ( auto sym = parser->GetSymbol( "TRADE_CURRENCY_INSTANCE" ) ) - if ( item->GetInstanceName() == sym->stringdata ) { - color = goldYellow; - texture = "MONEY"; // https://game-icons.net/1x1/delapouite/two-coins.html - return; - } - #if ENGINE >= Engine_G2 if ( item->GetInstanceName().HasWord( "SILVER" ) || item->GetInstanceName().HasWord( "GOLD" ) ) { color = zCOLOR( 72, 219, 251 ); texture = "VALUABLES"; // https://game-icons.net/1x1/lorc/cut-diamond.html - return; } #endif + + if ( item->GetStateFunc() != Invalid ) + color = statePink; } ItemLabel::ItemLabel( oCItem* renderedItem, zCViewBase* viewBase ) { item = renderedItem; - if ( !CanDrawLabel( viewBase ) ) + if ( !CanDrawLabel() ) return; zCView* itemView = dynamic_cast(viewBase); @@ -317,13 +306,13 @@ namespace GOTHIC_ENGINE { int endPos = startPos + 2000 * Options::LabelScale; - zCView labelView( startPos, startPos, endPos, endPos ); - labelView.InsertBack( "LABEL_" + texture ); - labelView.SetAlphaBlendFunc( zRND_ALPHA_FUNC_BLEND ); - labelView.SetTransparency( 255 ); - labelView.SetColor( color ); - itemView->InsertItem( &labelView ); - labelView.Blit(); - itemView->RemoveItem( &labelView ); + zCView* labelView = new zCView( startPos, startPos, endPos, endPos ); + labelView->InsertBack( "LABEL_" + texture ); + labelView->SetAlphaBlendFunc( zRND_ALPHA_FUNC_BLEND ); + labelView->SetTransparency( 255 ); + labelView->SetColor( color ); + itemView->InsertItem( labelView ); + labelView->Blit(); + delete labelView; } } \ No newline at end of file diff --git a/zUtilities/ItemLabel.h b/zUtilities/ItemLabel.h index 95228bd..e1b0bab 100644 --- a/zUtilities/ItemLabel.h +++ b/zUtilities/ItemLabel.h @@ -3,14 +3,14 @@ namespace GOTHIC_ENGINE { namespace Options { - int LabelItems, PutLabelBehind, LabelMissionItems; + bool LabelItems, PutLabelBehind, LabelMissionItems; float LabelScale; void ItemLabel() { - LabelItems = zoptions->ReadInt( PLUGIN_NAME, "LabelItems", true ); + LabelItems = zoptions->ReadBool( PLUGIN_NAME, "LabelItems", true ); LabelScale = zoptions->ReadReal( PLUGIN_NAME, "LabelScale", 1.25f ); - LabelMissionItems = zoptions->ReadInt( PLUGIN_NAME, "LabelMissionItems", false ); - PutLabelBehind = zoptions->ReadInt( PLUGIN_NAME, "PutLabelBehind", false ); + LabelMissionItems = zoptions->ReadBool( PLUGIN_NAME, "LabelMissionItems", false ); + PutLabelBehind = zoptions->ReadBool( PLUGIN_NAME, "PutLabelBehind", false ); } } @@ -22,7 +22,7 @@ namespace GOTHIC_ENGINE { zSTRING texture = "UNKNOWN"; // https://game-icons.net/1x1/lorc/swap-bag.html void SetLabelParams(); - bool CanDrawLabel( zCViewBase* viewBase ); + bool CanDrawLabel(); public: ItemLabel( oCItem* item, zCViewBase* viewBase ); diff --git a/zUtilities/KeyCode.h b/zUtilities/KeyCode.h new file mode 100644 index 0000000..2a52a54 --- /dev/null +++ b/zUtilities/KeyCode.h @@ -0,0 +1,185 @@ +// Supported with union (c) 2020 Union team +// Union HEADER file + +namespace GOTHIC_ENGINE { + int GetEmulationKeyCode( string code ) { +#define CHECKCODE(x) if( code == #x ) return x + CHECKCODE( MOUSE_DX ); + CHECKCODE( MOUSE_DY ); + CHECKCODE( MOUSE_UP ); + CHECKCODE( MOUSE_DOWN ); + CHECKCODE( MOUSE_LEFT ); + CHECKCODE( MOUSE_RIGHT ); + CHECKCODE( MOUSE_WHEELUP ); + CHECKCODE( MOUSE_WHEELDOWN ); + CHECKCODE( MOUSE_BUTTONLEFT ); + CHECKCODE( MOUSE_BUTTONRIGHT ); + CHECKCODE( MOUSE_BUTTONMID ); + CHECKCODE( MOUSE_XBUTTON1 ); + CHECKCODE( MOUSE_XBUTTON2 ); + CHECKCODE( MOUSE_XBUTTON3 ); + CHECKCODE( MOUSE_XBUTTON4 ); + CHECKCODE( MOUSE_XBUTTON5 ); + CHECKCODE( KEY_ESCAPE ); + CHECKCODE( KEY_1 ); + CHECKCODE( KEY_2 ); + CHECKCODE( KEY_3 ); + CHECKCODE( KEY_4 ); + CHECKCODE( KEY_5 ); + CHECKCODE( KEY_6 ); + CHECKCODE( KEY_7 ); + CHECKCODE( KEY_8 ); + CHECKCODE( KEY_9 ); + CHECKCODE( KEY_0 ); + CHECKCODE( KEY_MINUS ); + CHECKCODE( KEY_EQUALS ); + CHECKCODE( KEY_BACK ); + CHECKCODE( KEY_TAB ); + CHECKCODE( KEY_Q ); + CHECKCODE( KEY_W ); + CHECKCODE( KEY_E ); + CHECKCODE( KEY_R ); + CHECKCODE( KEY_T ); + CHECKCODE( KEY_Y ); + CHECKCODE( KEY_U ); + CHECKCODE( KEY_I ); + CHECKCODE( KEY_O ); + CHECKCODE( KEY_P ); + CHECKCODE( KEY_LBRACKET ); + CHECKCODE( KEY_RBRACKET ); + CHECKCODE( KEY_RETURN ); + CHECKCODE( KEY_LCONTROL ); + CHECKCODE( KEY_A ); + CHECKCODE( KEY_S ); + CHECKCODE( KEY_D ); + CHECKCODE( KEY_F ); + CHECKCODE( KEY_G ); + CHECKCODE( KEY_H ); + CHECKCODE( KEY_J ); + CHECKCODE( KEY_K ); + CHECKCODE( KEY_L ); + CHECKCODE( KEY_SEMICOLON ); + CHECKCODE( KEY_APOSTROPHE ); + CHECKCODE( KEY_GRAVE ); + CHECKCODE( KEY_LSHIFT ); + CHECKCODE( KEY_BACKSLASH ); + CHECKCODE( KEY_Z ); + CHECKCODE( KEY_X ); + CHECKCODE( KEY_C ); + CHECKCODE( KEY_V ); + CHECKCODE( KEY_B ); + CHECKCODE( KEY_N ); + CHECKCODE( KEY_M ); + CHECKCODE( KEY_COMMA ); + CHECKCODE( KEY_PERIOD ); + CHECKCODE( KEY_SLASH ); + CHECKCODE( KEY_RSHIFT ); + CHECKCODE( KEY_MULTIPLY ); + CHECKCODE( KEY_LMENU ); + CHECKCODE( KEY_SPACE ); + CHECKCODE( KEY_CAPITAL ); + CHECKCODE( KEY_F1 ); + CHECKCODE( KEY_F2 ); + CHECKCODE( KEY_F3 ); + CHECKCODE( KEY_F4 ); + CHECKCODE( KEY_F5 ); + CHECKCODE( KEY_F6 ); + CHECKCODE( KEY_F7 ); + CHECKCODE( KEY_F8 ); + CHECKCODE( KEY_F9 ); + CHECKCODE( KEY_F10 ); + CHECKCODE( KEY_NUMLOCK ); + CHECKCODE( KEY_SCROLL ); + CHECKCODE( KEY_NUMPAD7 ); + CHECKCODE( KEY_NUMPAD8 ); + CHECKCODE( KEY_NUMPAD9 ); + CHECKCODE( KEY_SUBTRACT ); + CHECKCODE( KEY_NUMPAD4 ); + CHECKCODE( KEY_NUMPAD5 ); + CHECKCODE( KEY_NUMPAD6 ); + CHECKCODE( KEY_ADD ); + CHECKCODE( KEY_NUMPAD1 ); + CHECKCODE( KEY_NUMPAD2 ); + CHECKCODE( KEY_NUMPAD3 ); + CHECKCODE( KEY_NUMPAD0 ); + CHECKCODE( KEY_DECIMAL ); + CHECKCODE( KEY_OEM_102 ); + CHECKCODE( KEY_F11 ); + CHECKCODE( KEY_F12 ); + CHECKCODE( KEY_F13 ); + CHECKCODE( KEY_F14 ); + CHECKCODE( KEY_F15 ); + CHECKCODE( KEY_KANA ); + CHECKCODE( KEY_ABNT_C1 ); + CHECKCODE( KEY_CONVERT ); + CHECKCODE( KEY_NOCONVERT ); + CHECKCODE( KEY_YEN ); + CHECKCODE( KEY_ABNT_C2 ); + CHECKCODE( KEY_NUMPADEQUALS ); + CHECKCODE( KEY_PREVTRACK ); + CHECKCODE( KEY_AT ); + CHECKCODE( KEY_COLON ); + CHECKCODE( KEY_UNDERLINE ); + CHECKCODE( KEY_KANJI ); + CHECKCODE( KEY_STOP ); + CHECKCODE( KEY_AX ); + CHECKCODE( KEY_UNLABELED ); + CHECKCODE( KEY_NEXTTRACK ); + CHECKCODE( KEY_NUMPADENTER ); + CHECKCODE( KEY_RCONTROL ); + CHECKCODE( KEY_MUTE ); + CHECKCODE( KEY_CALCULATOR ); + CHECKCODE( KEY_PLAYPAUSE ); + CHECKCODE( KEY_MEDIASTOP ); + CHECKCODE( KEY_VOLUMEDOWN ); + CHECKCODE( KEY_VOLUMEUP ); + CHECKCODE( KEY_WEBHOME ); + CHECKCODE( KEY_NUMPADCOMMA ); + CHECKCODE( KEY_DIVIDE ); + CHECKCODE( KEY_SYSRQ ); + CHECKCODE( KEY_RMENU ); + CHECKCODE( KEY_PAUSE ); + CHECKCODE( KEY_HOME ); + CHECKCODE( KEY_UP ); + CHECKCODE( KEY_PRIOR ); + CHECKCODE( KEY_LEFT ); + CHECKCODE( KEY_RIGHT ); + CHECKCODE( KEY_END ); + CHECKCODE( KEY_DOWN ); + CHECKCODE( KEY_NEXT ); + CHECKCODE( KEY_INSERT ); + CHECKCODE( KEY_DELETE ); + CHECKCODE( KEY_LWIN ); + CHECKCODE( KEY_RWIN ); + CHECKCODE( KEY_APPS ); + CHECKCODE( KEY_POWER ); + CHECKCODE( KEY_SLEEP ); + CHECKCODE( KEY_WAKE ); + CHECKCODE( KEY_WEBSEARCH ); + CHECKCODE( KEY_WEBFAVORITES ); + CHECKCODE( KEY_WEBREFRESH ); + CHECKCODE( KEY_WEBSTOP ); + CHECKCODE( KEY_WEBFORWARD ); + CHECKCODE( KEY_WEBBACK ); + CHECKCODE( KEY_MYCOMPUTER ); + CHECKCODE( KEY_MAIL ); + CHECKCODE( KEY_MEDIASELECT ); + CHECKCODE( KEY_BACKSPACE ); + CHECKCODE( KEY_NUMPADSTAR ); + CHECKCODE( KEY_LALT ); + CHECKCODE( KEY_CAPSLOCK ); + CHECKCODE( KEY_NUMPADMINUS ); + CHECKCODE( KEY_NUMPADPLUS ); + CHECKCODE( KEY_NUMPADPERIOD ); + CHECKCODE( KEY_NUMPADSLASH ); + CHECKCODE( KEY_RALT ); + CHECKCODE( KEY_UPARROW ); + CHECKCODE( KEY_PGUP ); + CHECKCODE( KEY_LEFTARROW ); + CHECKCODE( KEY_RIGHTARROW ); + CHECKCODE( KEY_DOWNARROW ); + CHECKCODE( KEY_PGDN ); +#undef CHECKCODE + return 0; + } +} \ No newline at end of file diff --git a/zUtilities/Lockable.cpp b/zUtilities/Lockable.cpp new file mode 100644 index 0000000..59850b1 --- /dev/null +++ b/zUtilities/Lockable.cpp @@ -0,0 +1,42 @@ +// Supported with union (c) 2020 Union team +// Union SOURCE file + +namespace GOTHIC_ENGINE { + int KnownLockCombination = 0; + + HOOK Hook_oCMobLockable_PickLock PATCH( &oCMobLockable::PickLock, &oCMobLockable::PickLock_Union ); + int oCMobLockable::PickLock_Union( oCNpc* npc, char key ) { + if ( !Options::RememberLockCombination ) { + int result = THISCALL( Hook_oCMobLockable_PickLock )(npc, key); + return result; + } + + // Restore largest known combination + if ( pickLockNr < KnownLockCombination ) + pickLockNr = KnownLockCombination; + + int result = THISCALL( Hook_oCMobLockable_PickLock )(npc, key); + + // Update largest known combination + if ( pickLockNr > KnownLockCombination ) + KnownLockCombination = pickLockNr; + + return result; + } + + HOOK Hook_oCMobInter_StopInteraction PATCH( &oCMobInter::StopInteraction, &oCMobInter::StopInteraction_Union ); + void oCMobInter::StopInteraction_Union( oCNpc* npc ) { + if ( npc != player || !Options::RememberLockCombination ) { + THISCALL( Hook_oCMobInter_StopInteraction )(npc); + return; + } + + // Reset when leaving lockable + if ( oCMobLockable* lockable = this->CastTo() ) { + KnownLockCombination = 0; + lockable->pickLockNr = 0; + } + + THISCALL( Hook_oCMobInter_StopInteraction )(npc); + } +} \ No newline at end of file diff --git a/zUtilities/LogBook.cpp b/zUtilities/LogBook.cpp new file mode 100644 index 0000000..44741bf --- /dev/null +++ b/zUtilities/LogBook.cpp @@ -0,0 +1,112 @@ +// Supported with union (c) 2020 Union team +// Union SOURCE file + +namespace GOTHIC_ENGINE { + HOOK Hook_oCLogTopic_AddEntry PATCH( &oCLogTopic::AddEntry, &oCLogTopic::AddEntry_Union ); + void oCLogTopic::AddEntry_Union( zSTRING const& entry ) { + THISCALL( Hook_oCLogTopic_AddEntry )(entry); + + logBook.AddTopic( this ); + } + + HOOK Hook_zCMenuItemList_ShowContent PATCH( &zCMenuItemList::ShowContent, &zCMenuItemList::ShowContent_Union ); + void zCMenuItemList::ShowContent_Union() { + THISCALL( Hook_zCMenuItemList_ShowContent )(); + + if ( !Options::LogBookColoring || !logBook.CanColorList( this ) ) + return; + + logBook.MarkRead( this->m_list[m_cur_element].title ); + + // zCMenuItemList::DrawFront function is not called after closing content so color must be updated here + logBook.UpdateView( this->m_pInnerWindow ); + } + + HOOK Hook_zCMenuItemList_DrawFront PATCH( &zCMenuItemList::DrawFront, &zCMenuItemList::DrawFront_Union ); + void zCMenuItemList::DrawFront_Union() { + THISCALL( Hook_zCMenuItemList_DrawFront )(); + + if ( !Options::LogBookColoring || !logBook.CanColorList( this ) ) + return; + + logBook.UpdateView( this->m_pInnerWindow ); + } + + void LogBook::UpdateView( zCView* view ) { + if ( !view ) return; + + auto list = view->textLines.GetNextInList(); + + while ( list != nullptr ) { + auto item = list->GetData(); + list = list->GetNextInList(); + + logBook.UpdateColor( item ); + } + } + + void LogBook::UpdateColor( zCViewText* view ) { + if ( !colorOld ) colorOld = new zCOLOR( view->color ); + + zSTRING topic = view->text; + zCOLOR color = *colorOld; + + if ( newTopics.IsInList( topic ) ) + color = zCOLOR( 0, 255, 0 ); + else if ( unreadTopics.IsInList( topic ) ) + color = zCOLOR( 255, 160, 0 ); + + view->color = color; + view->colored = true; + } + + bool LogBook::CanColorList( zCMenuItemList* list ) { + return list->id == "MENU_ITEM_LIST_LOG" || list->id == "MENU_ITEM_LIST_MISSIONS_ACT" || list->id == "MENU_ITEM_LIST_MISSIONS_OLD" || list->id == "MENU_ITEM_LIST_MISSIONS_FAILED"; + } + + void LogBook::AddTopic( oCLogTopic* topic ) { + if ( unreadTopics.IsInList( topic->m_strDescription ) || newTopics.IsInList( topic->m_strDescription ) ) + return; + + if ( topic->m_lstEntries.GetNum() == 1 ) { + newTopics.Insert( topic->m_strDescription ); + return; + } + + unreadTopics.Insert( topic->m_strDescription ); + } + + void LogBook::MarkRead( zSTRING topic ) { + if ( unreadTopics.IsInList( topic ) ) + unreadTopics.Remove( topic ); + + if ( newTopics.IsInList( topic ) ) + newTopics.Remove( topic ); + } + + void LogBook::Archive( zCArchiver* ar ) { + ar->WriteInt( "unreadTopicsCount", unreadTopics.GetNum() ); + for ( int i = 0; i < unreadTopics.GetNum(); i++ ) + ar->WriteString( "unreadTopics", unreadTopics[i] ); + + ar->WriteInt( "newTopicsCount", newTopics.GetNum() ); + for ( int i = 0; i < newTopics.GetNum(); i++ ) + ar->WriteString( "newTopics", newTopics[i] ); + } + + void LogBook::Unarchive( zCArchiver* ar ) { + unreadTopics.EmptyList(); + newTopics.EmptyList(); + + if ( !ar ) + return; + + int unreadTopicsCount = ar->ReadIntSafe( "unreadTopicsCount" ); + for ( int i = 0; i < unreadTopicsCount; i++ ) + unreadTopics.Insert( ar->ReadString( "unreadTopics" ) ); + + int newTopicsCount = ar->ReadIntSafe( "newTopicsCount" ); + for ( int i = 0; i < newTopicsCount; i++ ) + newTopics.Insert( ar->ReadString( "newTopics" ) ); + } +} \ No newline at end of file diff --git a/zUtilities/LogBook.h b/zUtilities/LogBook.h new file mode 100644 index 0000000..7030415 --- /dev/null +++ b/zUtilities/LogBook.h @@ -0,0 +1,31 @@ +// Supported with union (c) 2020 Union team +// Union HEADER file + +namespace GOTHIC_ENGINE { + namespace Options { + bool LogBookColoring; + + void LogBook() { + LogBookColoring = zoptions->ReadBool( PLUGIN_NAME, "LogBookColoring", true ); + } + } + + class LogBook { + private: + zCOLOR* colorOld; + zCArray unreadTopics; + zCArray newTopics; + + void UpdateColor( zCViewText* view ); + + public: + void UpdateView( zCView* view ); + bool CanColorList( zCMenuItemList* list ); + void AddTopic( oCLogTopic* topic ); + void MarkRead( zSTRING topic ); + void Archive( zCArchiver* ar ); + void Unarchive( zCArchiver* ar ); + }; + + LogBook logBook; +} \ No newline at end of file diff --git a/zUtilities/Meatbug.cpp b/zUtilities/Meatbug.cpp index 2bd43ae..d06e2d8 100644 --- a/zUtilities/Meatbug.cpp +++ b/zUtilities/Meatbug.cpp @@ -2,38 +2,53 @@ // Union SOURCE file namespace GOTHIC_ENGINE { + oCNpc* playerTrfCopy = nullptr; - // Inspiration @G2-Ucieczka - https://github.com/TheKetrab/G2-Ucieczka + HOOK Hook_oCNpc_CopyTransformSpellInvariantValuesTo PATCH( &oCNpc::CopyTransformSpellInvariantValuesTo, &oCNpc::CopyTransformSpellInvariantValuesTo_Union ); + void oCNpc::CopyTransformSpellInvariantValuesTo_Union( oCNpc* npc ) { + if ( this == player ) + playerTrfCopy = this; + + THISCALL( Hook_oCNpc_CopyTransformSpellInvariantValuesTo )(npc); + } + // Inspiration @G2-Ucieczka - https://github.com/TheKetrab/G2-Ucieczka HOOK Hook_oCNpc_OnTouch PATCH( &oCNpc::OnTouch, &oCNpc::OnChrzonszcz ); void oCNpc::OnChrzonszcz( zCVob* vob ) { - oCNpc* npc = vob->CastTo(); + zCVisual* visual = vob->GetVisual(); + + if ( !npc || !visual || !this->IsSelfPlayer() || !this->IsHuman() || vob == playerTrfCopy || npc->guild != NPC_GIL_MEATBUG || npc->HasFlag( NPC_FLAG_IMMORTAL ) || !Options::TrampleMeatbugs ) { + THISCALL( Hook_oCNpc_OnTouch )(vob); + return; + } - if ( !npc || !this->IsSelfPlayer() || !Options::TrampleMeatbugs ) { + bool largeMdlScale = false; + for ( auto i = 0; i < npc->model_scale.Length(); i++ ) + if ( npc->model_scale[i] > 1.0 ) + largeMdlScale = true; + + if ( visual->GetVisualName() != "MEATBUG.MDS" || largeMdlScale ) { THISCALL( Hook_oCNpc_OnTouch )(vob); return; } - if ( npc->guild == NPC_GIL_MEATBUG && npc->GetInstanceName().HasWord( "MEATBUG" ) && npc->attribute[NPC_ATR_HITPOINTSMAX] <= 25 ) { - // Kill and Exp - npc->DoDie( this ); - if ( npc->attribute[NPC_ATR_HITPOINTS] > 0 ) - npc->attribute[NPC_ATR_HITPOINTS] = 0; - - // Sound - if ( zCSoundFX* snd = zsound->LoadSoundFX( "CS_IAM_UD_FLX_0" + Z randomizer.Random( 1, 5 ) + ".WAV" ) ) { - zCSoundSystem::zTSound3DParams params; - zsound->GetSound3DProps( 0, params ); - zsound->PlaySound3D( snd, vob, 0, ¶ms ); - snd->Release(); - } - - //// Blood - //oCVisualFX::CreateAndPlay( "BFX_PRESET2", npc, nullptr, 0, 0, 0, 0 ); + // Kill and Exp + npc->DoDie( this ); + if ( npc->attribute[NPC_ATR_HITPOINTS] > 0 ) + npc->attribute[NPC_ATR_HITPOINTS] = 0; + + // Sound + if ( zCSoundFX* snd = zsound->LoadSoundFX( "CS_IAM_UD_FLX_0" + Z randomizer.Random( 1, 5 ) + ".WAV" ) ) { + zCSoundSystem::zTSound3DParams params; + zsound->GetSound3DProps( 0, params ); + zsound->PlaySound3D( snd, vob, 0, ¶ms ); + snd->Release(); } + //// Blood + //oCVisualFX::CreateAndPlay( "BFX_PRESET2", npc, nullptr, 0, 0, 0, 0 ); + THISCALL( Hook_oCNpc_OnTouch )(vob); } - } \ No newline at end of file diff --git a/zUtilities/Misc.cpp b/zUtilities/Misc.cpp index 3abc897..0de7335 100644 --- a/zUtilities/Misc.cpp +++ b/zUtilities/Misc.cpp @@ -14,4 +14,28 @@ namespace GOTHIC_ENGINE { a.top <= b.bottom && b.top <= a.bottom); } + + string GetArchivePath( string sav ) { + int slotID = SaveLoadGameInfo.slotID; + string savesDir = zoptions->GetDirString( zTOptionPaths::DIR_SAVEGAMES ); + string slotDir = SaveLoadGameInfo.GetSaveSlotName( SaveLoadGameInfo.slotID ); + string archivePath = string::Combine( "%s\\%s\\%s\.sav", savesDir, slotDir, sav ); + return archivePath; + } + + zSTRING GetAttributeName( int att ) { + switch ( att ) + { + case NPC_ATR_HITPOINTSMAX: + return "HP"; + case NPC_ATR_MANAMAX: + return "MANA"; + case NPC_ATR_STRENGTH: + return "STR"; + case NPC_ATR_DEXTERITY: + return "DEX"; + default: + return ""; + } + } } \ No newline at end of file diff --git a/zUtilities/Options.h b/zUtilities/Options.h index 9d8caa4..fac9c34 100644 --- a/zUtilities/Options.h +++ b/zUtilities/Options.h @@ -2,19 +2,67 @@ // Union HEADER file namespace GOTHIC_ENGINE { -#define PLUGIN_NAME "ZUTILITIES" -#define VERSION_NUMBER "0.15" -#define printWin(a) ogame->GetTextView()->Printwin(a) - namespace Options { - int TrampleMeatbugs, CenterInvItems; + bool TrampleMeatbugs, CenterInvItems, RememberLockCombination, ActivateUsedMunition, AlternativeDialogueBoxes; + zCOLOR* SelectedDialogueColor; void Misc() { - TrampleMeatbugs = zoptions->ReadInt( PLUGIN_NAME, "TrampleMeatbugs", true ); - CenterInvItems = zoptions->ReadInt( PLUGIN_NAME, "CenterInvItems", true ); + TrampleMeatbugs = zoptions->ReadBool( PLUGIN_NAME, "TrampleMeatbugs", true ); + CenterInvItems = zoptions->ReadBool( PLUGIN_NAME, "CenterInvItems", true ); + RememberLockCombination = zoptions->ReadBool( PLUGIN_NAME, "RememberLockCombination", false ); + ActivateUsedMunition = zoptions->ReadBool( PLUGIN_NAME, "ActivateUsedMunition", true ); + AlternativeDialogueBoxes = zoptions->ReadBool( PLUGIN_NAME, "AlternativeDialogueBoxes", false ); + + if ( SelectedDialogueColor ) + delete SelectedDialogueColor; + + SelectedDialogueColor = zoptions->ReadColor( PLUGIN_NAME, "SelectedDialogueColor", "" ); + + if ( SelectedDialogueColor ) { + oCInformationManager::GetInformationManager().DlgChoice->ColorSelected = *SelectedDialogueColor; + oCInformationManager::GetInformationManager().DlgStatus->ColorSelected = *SelectedDialogueColor; +#if ENGINE < Engine_G2 + oCInformationManager::GetInformationManager().DlgTrade->DlgChoice->ColorSelected = *SelectedDialogueColor; +#endif + } + } + + void ReadOptions() { + Misc(); + LogBook(); + PlayerStatus(); + StatusBar(); + QuickSave(); + FocusColor(); + ItemLabel(); + DamagePopup(); } void AddTrivias() { - zoptions->AddTrivia( PLUGIN_NAME, "UseQuickSave", "... enables (1) or disables (0) QuickSaving with [F10] and QuickLoading with [F12]" ); + const string nline = "\r\n; "; + + zoptions->AddTrivia( PLUGIN_NAME, "LogBookColoring", "... enables (1) or disables (0) coloring of new and unread topics in logbook" ); + + zoptions->AddTrivia( PLUGIN_NAME, "RecoveryVisualization", "... enables (1) or disables (0) visualization of healing that hovered in the inventory item gives" ); + zoptions->AddTrivia( PLUGIN_NAME, "StatusBarValueMode", "... specifies mode of showing status bar value, (0) - 'Disabled', (1) - 'Above', (2) - 'PointToCenter', (3) - 'Inside'" ); + zoptions->AddTrivia( PLUGIN_NAME, "ShowEnemyBarAboveHim", "... enables (1) or disables (0) showing enemy hp bar above his head" ); + zoptions->AddTrivia( PLUGIN_NAME, "StatusBarNames", "... defines text label for status bars like so: 'Health|Mana|Stamina', leave empty if text is unwanted" ); + zoptions->AddTrivia( PLUGIN_NAME, "HealthBarPos", "... defines position of health bar like so: 'x1|y1|x2|y2'" + nline + "... default position for scale 1 is: '43|7873|1122|8085' and for scale 0: '43|7964|811|8116'" + nline + "... leave empty to use default position" ); + zoptions->AddTrivia( PLUGIN_NAME, "ManaBarPos", "... defines position of mana bar like so: 'x1|y1|x2|y2'" + nline + "... default position for scale 1 is: '7053|7873|8132|8085' and for scale 0: '7381|7964|8149|8116'" + nline + "... leave empty to use default position" ); + zoptions->AddTrivia( PLUGIN_NAME, "SwimBarPos", "... defines position of swim bar like so: 'x1|y1|x2|y2'" + nline + "... default position for scale 1 is: '3556|7873|4635|8085' and for scale 0: '3712|7964|4480|8116'" + nline + "... leave empty to use default position" ); + + zoptions->AddTrivia( PLUGIN_NAME, "ShowGameTime", "... enables (1) or disables (0) on screen display of in game time" ); + zoptions->AddTrivia( PLUGIN_NAME, "ShowMunitionAmount", "... enables (1) or disables (0) on screen display of currently used munition amount" ); + zoptions->AddTrivia( PLUGIN_NAME, "ShowTargetProtection", "... enables (1) or disables (0) protection icon and value next to the focused npc hp bar" ); +#if ENGINE >= Engine_G2 + zoptions->AddTrivia( PLUGIN_NAME, "ShowPickpocketIcon", "... enables (1) or disables (0) coin icon next to the focused npc name when it can be pickpocketed" ); +#endif + zoptions->AddTrivia( PLUGIN_NAME, "UseTimeMultiplier", "... enables (1) or disables (0) time speed multiplier" ); + zoptions->AddTrivia( PLUGIN_NAME, "KeyTimeMultiplier", "... key for cycling time speed" ); + zoptions->AddTrivia( PLUGIN_NAME, "TimeMultipliers", "... defines time multipliers" ); + + zoptions->AddTrivia( PLUGIN_NAME, "QuickSaveMode", "... specifies QuickSave mode, (0) - 'Disabled', (1) - 'Standard', (2) - 'Alternative'" + nline + "... QuickSave with [F10] and QuickLoad with [F12]" ); + zoptions->AddTrivia( PLUGIN_NAME, "KeyQuickSave", "... key for QuickSave" ); + zoptions->AddTrivia( PLUGIN_NAME, "KeyQuickLoad", "... key for QuickLoad" ); zoptions->AddTrivia( PLUGIN_NAME, "MinSaveSlot", "... defines min range of used save slots" ); zoptions->AddTrivia( PLUGIN_NAME, "MaxSaveSlot", "... defines max range of used save slots" ); zoptions->AddTrivia( PLUGIN_NAME, "CantSave", "... text appearing when game cannot be saved" ); @@ -22,17 +70,17 @@ namespace GOTHIC_ENGINE { zoptions->AddTrivia( PLUGIN_NAME, "NoSave", "... text appearing when something went wrong and incorrect save slot tried to be loaded" ); zoptions->AddTrivia( PLUGIN_NAME, "SaveName", "... name used for quicksaves" ); - zoptions->AddTrivia( PLUGIN_NAME, "ColorNpcs", "... enables (1) or disables (0) coloring of focused Npcs" ); - zoptions->AddTrivia( PLUGIN_NAME, "ColorChests", "... enables (1) or disables (0) coloring of focused Chests" ); - zoptions->AddTrivia( PLUGIN_NAME, "ColorDoors", "... enables (1) or disables (0) coloring of focused Doors" ); - zoptions->AddTrivia( PLUGIN_NAME, "ColorItems", "... enables (1) or disables (0) coloring of focused Items" ); + zoptions->AddTrivia( PLUGIN_NAME, "ColorNpcs", "... enables (1) or disables (0) coloring of focused npcs" ); + zoptions->AddTrivia( PLUGIN_NAME, "ColorLockables", "... enables (1) or disables (0) coloring of focused chests, doors and other lockables" ); + zoptions->AddTrivia( PLUGIN_NAME, "ColorItems", "... enables (1) or disables (0) coloring of focused items" ); + zoptions->AddTrivia( PLUGIN_NAME, "ColorInter", "... enables (1) or disables (0) coloring of interactive bookstands" ); zoptions->AddTrivia( PLUGIN_NAME, "LabelItems", "... enables (1) or disables (0) inventory item labeling" ); zoptions->AddTrivia( PLUGIN_NAME, "LabelScale", "... defines scale of the label" ); zoptions->AddTrivia( PLUGIN_NAME, "LabelMissionItems", "... enables (1) or disables (0) labeling of item missions, this will overwrite previous label on any item with ITEM_MISSION flag" ); zoptions->AddTrivia( PLUGIN_NAME, "PutLabelBehind", "... specifies if the label should be rendered behind the item" ); - zoptions->AddTrivia( PLUGIN_NAME, "DamagePopupMode", "... specifies DamagePopup mode, (0) - Disabled, (1) - 'Alter Damage', (2) - 'New World'" ); + zoptions->AddTrivia( PLUGIN_NAME, "DamagePopupMode", "... specifies DamagePopup mode, (0) - 'Disabled', (1) - 'Alter Damage', (2) - 'New World'" ); zoptions->AddTrivia( PLUGIN_NAME, "DamagePopupScale", "... defines base scale of the popup" ); zoptions->AddTrivia( PLUGIN_NAME, "DamagePopupShowIcons", "... enables (1) or disables (0) icons for the popup" ); zoptions->AddTrivia( PLUGIN_NAME, "DamagePopupColorDmgTypes", "... enables (1) or disables (0) popup coloring by the damage type" ); @@ -40,38 +88,12 @@ namespace GOTHIC_ENGINE { zoptions->AddTrivia( PLUGIN_NAME, "TrampleMeatbugs", "... enables (1) or disables (0) a way of killing meatbugs by stepping on them" ); zoptions->AddTrivia( PLUGIN_NAME, "CenterInvItems", "... enables (1) or disables (0) inventory item rendering in the center of the screen instead of the item description box" ); - } - } - - void zCOption::AddTrivia( const string sectionName, const string entryName, string trivia ) { - zCOption* const& option = this; - zCOptionSection* section = option->GetSectionByName( sectionName, true ); - - if ( !section ) return; - - zCOptionEntry* entry = option->GetEntryByName( section, entryName, true ); + zoptions->AddTrivia( PLUGIN_NAME, "RememberLockCombination", "... enables (1) or disables (0) alternative way of opening locks, where discovered combination doesn't reset after fail" ); + zoptions->AddTrivia( PLUGIN_NAME, "ActivateUsedMunition", "... enables (1) or disables (0) highlighting currently used ranged weapon munition in the inventory" ); + zoptions->AddTrivia( PLUGIN_NAME, "AlternativeDialogueBoxes", "... enables (1) or disables (0) alternative dialogue boxes style" ); + zoptions->AddTrivia( PLUGIN_NAME, "SelectedDialogueColor", "... defines color of selected line in dialogues" + nline + "... use 'R|G|B' or 'R|G|B|A' format" + nline + "... leave empty to use default color" ); - if ( !entry ) return; - - zCOptionEntry* triviaEntry = new zCOptionEntry{ "", (A"; " + trivia + "\r\n\n") }; - - int nextPos = section->entryList.Search( entry ) + 1; - - if ( nextPos > section->entryList.GetNumInList() - 1 ) { - section->entryList.InsertEnd( triviaEntry ); - return; - } - - zSTRING nextLine = section->entryList[nextPos]->varValue; - - if ( nextLine.StartWith( "; " + trivia ) ) - return; - - if ( nextLine.StartWith( "; " ) ) { - section->entryList[nextPos] = triviaEntry; - return; + zoptions->AddTrivia( PLUGIN_NAME, "SaveReminder", "... Time in minutes after which the reminder to save the game appears on the screen" + nline + "... set to -1 to disable"); } - - section->entryList.InsertAtPos( triviaEntry, nextPos ); } } \ No newline at end of file diff --git a/zUtilities/PlayerHelper.h b/zUtilities/PlayerHelper.h index 81e9fc0..d56179e 100644 --- a/zUtilities/PlayerHelper.h +++ b/zUtilities/PlayerHelper.h @@ -4,8 +4,6 @@ namespace GOTHIC_ENGINE { class PlayerHelper { public: - bool isSaving = false; - bool IsBusy() { return IsInInfo() || OnPause() || player->inventory2.IsOpen(); } @@ -18,10 +16,6 @@ namespace GOTHIC_ENGINE { return ogame->IsOnPause(); } - bool IsSaving() { - return isSaving; - } - bool IsDead() { return player->attribute[NPC_ATR_HITPOINTS] <= 0; } @@ -29,6 +23,24 @@ namespace GOTHIC_ENGINE { bool IsInCombat() { return !IsDead() && player->enemy != nullptr; } + + int GetSysScale() { + float scale; + Union.GetSysPackOption().Read( scale, "INTERFACE", "Scale", 1.0f ); + return (int)scale; + } + + bool IsConUp() { + for ( int i = 0; i < zCConsole::active_consoles.GetNumInList(); i++ ) + if ( zCConsole::active_consoles[i]->IsVisible() ) + return true; + + return false; + } + + bool LeftInvOpen() { + return player->inventory2.IsOpen() && player->inventory2.GetNextContainerLeft( &player->inventory2 ); + } }; PlayerHelper playerHelper; diff --git a/zUtilities/PlayerStatus.cpp b/zUtilities/PlayerStatus.cpp new file mode 100644 index 0000000..8e863e4 --- /dev/null +++ b/zUtilities/PlayerStatus.cpp @@ -0,0 +1,443 @@ +// Supported with union (c) 2020 Union team +// Union SOURCE file + +namespace GOTHIC_ENGINE { +#if ENGINE >= Engine_G2 + std::vector vfxs; + HOOK Ivk_InitEffect_Union PATCH( &oCVisualFX::InitEffect, &oCVisualFX::InitEffect_Union ); + void oCVisualFX::InitEffect_Union() { + + if ( visName_S.Search( ".SLW", 1 ) == -1 ) + { + THISCALL( Ivk_InitEffect_Union )(); + return; + } + + vfxs.push_back( this ); + playerStatus.ResetTimeMultiplier(); + + THISCALL( Ivk_InitEffect_Union )(); + } + + HOOK Ivk_EndEffect_Union PATCH(&oCVisualFX::EndEffect, &oCVisualFX::EndEffect_Union); + void oCVisualFX::EndEffect_Union( const int kill ) { + if ( visName_S.Search( ".SLW", 1 ) == -1 ) + { + THISCALL( Ivk_EndEffect_Union )( kill ); + return; + } + + auto it = std::find( vfxs.begin(), vfxs.end(), this ); + if (it != vfxs.end()) + { + vfxs.erase( std::remove( vfxs.begin(), vfxs.end(), this ), vfxs.end() ); + } + + THISCALL( Ivk_EndEffect_Union )( kill ); + } +#endif + + bool PlayerStatus::CanChangeZtimer() + { +#if ENGINE >= Engine_G2 + return vfxs.empty(); +#endif + return true; + } + + + HOOK Ivk_CallOnStateFunc_Union PATCH( &oCMobInter::CallOnStateFunc, &oCMobInter::CallOnStateFunc_Union ); + void oCMobInter::CallOnStateFunc_Union( oCNpc* npc, int a1 ) { + THISCALL( Ivk_CallOnStateFunc_Union )(npc, a1); + + if ( npc == player ) + playerStatus.TryAddStateFunc( this ); + } + + HOOK Ivk_GetStateEffectFunc_Union PATCH( &oCItem::GetStateEffectFunc, &oCItem::GetStateEffectFunc_Union ); + int oCItem::GetStateEffectFunc_Union( int a1 ) { + int result = THISCALL( Ivk_GetStateEffectFunc_Union )(a1); + playerStatus.stateFuncItem = (a1 == 0) ? this : nullptr; + return result; + } + + HOOK Ivk_EV_UseItemToState_Union PATCH( &oCNpc::EV_UseItemToState, &oCNpc::EV_UseItemToState_Union ); + int oCNpc::EV_UseItemToState_Union( oCMsgManipulate* msg ) { + int result = THISCALL( Ivk_EV_UseItemToState_Union )(msg); + + if ( this == player && msg && msg->targetVob && playerStatus.stateFuncItem && playerStatus.stateFuncItem == msg->targetVob ) { + playerStatus.TryAddStateFunc( msg->targetVob ); + playerStatus.stateFuncItem = nullptr; + } + + return result; + } + + void PlayerStatus::GetPickpocketInfos() { + auto list = ogame->GetInfoManager()->infoList.next; + while ( list ) { + auto info = list->data; + list = list->next; + + // Whenever the icon will visible or not is based on the npc dialogue including PICKPOCKET word which seems to be used consistently in mods as well. + if ( !info->name.HasWordI( "pickpocket" ) && !info->name.HasWordI( "_steal" ) && !info->name.HasWordI( "pickme" ) ) + continue; + + if ( info->name.HasWordI( "_DOIT" ) || info->name.HasWordI( "_TRY" ) ) + continue; + + // To avoid targeting possible dialogues related to pickpocketing quests or teach options. + if ( parser->GetIndex( info->name + "_DOIT" ) == Invalid && parser->GetIndex( info->name + "_TRY" ) == Invalid ) + continue; + + if ( !pickpocketInfos.IsInList( info ) ) + pickpocketInfos.Insert( info ); + } + } + + bool PlayerStatus::CanPickpocketNpc( oCNpc* npc ) { + //auto sym = parser->GetSymbol( "NPC_TALENT_PICKPOCKET" ); + //if ( !sym ) + // return false; + + //if ( !player->GetTalentSkill( sym->single_intdata ) ) + // return false; + + //if ( npc->GetAivar( "AIV_PLAYERHASPICKEDMYPOCKET" ) ) + // return false; + + if ( npc->attribute[NPC_ATR_HITPOINTS] <= 0 ) + return false; + + for ( int i = 0; i < pickpocketInfos.GetNumInList(); i++ ) { + auto info = pickpocketInfos[i]; + + if ( info->GetNpcID() != npc->GetInstance() ) + continue; + + parser->SetInstance( "SELF", npc ); + parser->SetInstance( "OTHER", player ); + + return info->InfoConditions(); + } + + return false; + } + + bool PlayerStatus::KnowStateFunc( zCVob* vob ) { + if ( !vob ) + return false; + + if ( oCItem* item = vob->CastTo() ) { + if ( stateFuncItems.IsInList( item->GetInstanceName() ) ) + return true; + + int index = item->GetStateFunc(); + if ( index == Invalid ) + return true; + + for ( int i = 0; i < interStateFuncs.GetNumInList(); i++ ) { + int idx = parser->GetIndex( interStateFuncs[i] + "_s1" ); + if ( idx == index ) + return true; + } + } + else if ( oCMobInter* inter = vob->CastTo() ) { + if ( interStateFuncs.IsInList( inter->onStateFuncName ) ) + return true; + + int index = parser->GetIndex( inter->onStateFuncName + "_s1" ); + if ( index == Invalid ) + return true; + + for ( int i = 0; i < stateFuncItems.GetNumInList(); i++ ) { + oCItem* itm = new oCItem( stateFuncItems[i], 1 ); + if ( !itm ) continue; + int idx = itm->GetStateFunc(); + itm->Release(); + if ( idx == index ) + return true; + } + } + + return false; + } + + void PlayerStatus::TryAddStateFunc( zCVob* vob ) { + if ( !vob ) + return; + + if ( KnowStateFunc( vob ) ) + return; + + if ( oCItem* item = vob->CastTo() ) + stateFuncItems.Insert( item->GetInstanceName() ); + else if ( oCMobInter* inter = vob->CastTo() ) + interStateFuncs.Insert( inter->onStateFuncName ); + } + + void PlayerStatus::Archive( zCArchiver* ar ) { + ar->WriteInt( "interStateFuncsCount", interStateFuncs.GetNum() ); + for ( int i = 0; i < interStateFuncs.GetNum(); i++ ) + ar->WriteString( "interStateFuncs", interStateFuncs[i] ); + + ar->WriteInt( "stateFuncItemsCount", stateFuncItems.GetNum() ); + for ( int i = 0; i < stateFuncItems.GetNum(); i++ ) + ar->WriteString( "stateFuncItems", stateFuncItems[i] ); + } + + void PlayerStatus::Unarchive( zCArchiver* ar ) { + interStateFuncs.EmptyList(); + stateFuncItems.EmptyList(); + + if ( !ar ) + return; + + int interStateFuncsCount = ar->ReadIntSafe( "interStateFuncsCount" ); + for ( int i = 0; i < interStateFuncsCount; i++ ) + interStateFuncs.Insert( ar->ReadString( "interStateFuncs" ) ); + + int stateFuncItemsCount = ar->ReadIntSafe( "stateFuncItemsCount" ); + for ( int i = 0; i < stateFuncItemsCount; i++ ) + stateFuncItems.Insert( ar->ReadString( "stateFuncItems" ) ); + } + +#if ENGINE < Engine_G2 + HOOK Hook_zCAICamera_CheckKeys PATCH( &zCAICamera::CheckKeys, &zCAICamera::CheckKeys_Union ); + void zCAICamera::CheckKeys_Union() { + if ( !Options::UseTimeMultiplier || ztimer->factorMotion == 1.0f || !playerStatus.CanChangeZtimer() ) { + THISCALL( Hook_zCAICamera_CheckKeys )(); + return; + } + + float frameTimeOld = ztimer->frameTimeFloat; + float motionFactorOld = ztimer->factorMotion; + ztimer->frameTimeFloat = frameTimeOld / motionFactorOld; + ztimer->factorMotion = 1.0f; + THISCALL( Hook_zCAICamera_CheckKeys )(); + ztimer->frameTimeFloat = frameTimeOld; + ztimer->factorMotion = motionFactorOld; + } + + HOOK Hook_oCAIHuman_PC_Turnings PATCH( &oCAIHuman::PC_Turnings, &oCAIHuman::PC_Turnings_Union ); + void oCAIHuman::PC_Turnings_Union( int forceRotation ) { + if ( !Options::UseTimeMultiplier || ztimer->factorMotion == 1.0f || Pressed( GAME_LEFT ) || Pressed( GAME_RIGHT ) || !playerStatus.CanChangeZtimer() ) { + THISCALL( Hook_oCAIHuman_PC_Turnings )(forceRotation); + return; + } + + float frameTimeOld = ztimer->frameTimeFloat; + float motionFactorOld = ztimer->factorMotion; + ztimer->frameTimeFloat = frameTimeOld / motionFactorOld; + ztimer->factorMotion = 1.0f; + THISCALL( Hook_oCAIHuman_PC_Turnings )(forceRotation); + ztimer->frameTimeFloat = frameTimeOld; + ztimer->factorMotion = motionFactorOld; + }; +#endif + + void PlayerStatus::ResetTimeMultiplier() { + if ( !ztimer ) + return; + + ztimer->factorMotion = 1.0f; + } + + void PlayerStatus::ResetSaveReminder() { + if (SaveLoadGameInfo.changeLevel) + { + return; + } + + lastSaveTime = std::chrono::high_resolution_clock::now(); + } + + void PlayerStatus::FactorMotion() { + if ( !Options::UseTimeMultiplier ) + return; + + if ( !Options::TimeMultipliers.GetNum() || playerHelper.IsConUp() ) + return; + + if ( !CanChangeZtimer() ) + return; + + if ( playerHelper.IsDead() || playerHelper.IsInInfo() || ogame->IsOnPause() ) { + if ( ztimer->factorMotion != 1.0f ) + ztimer->factorMotion = 1.0f; + return; + } + + if ( !zinput->KeyToggled( Options::KeyTimeMultiplier ) ) { + if ( ztimer->factorMotion != Options::TimeMultipliers[multiplierIndex] ) + ztimer->factorMotion = Options::TimeMultipliers[multiplierIndex]; + return; + } + + multiplierIndex++; + if ( multiplierIndex < 0 || multiplierIndex >= Options::TimeMultipliers.GetNum() ) + multiplierIndex = 0; + + ztimer->factorMotion = Options::TimeMultipliers[multiplierIndex]; + } + + void PlayerStatus::ShowGameTime() { + if ( !Options::ShowGameTime && !Options::UseTimeMultiplier ) + return; + + if ( playerHelper.LeftInvOpen() || playerHelper.IsConUp() || !ogame->GetShowPlayerStatus() || !ogame->hpBar ) + return; + + zSTRING str = ""; + zCOLOR color = zCOLOR( 255, 255, 255 ); + + if ( Options::ShowGameTime ) { + int day, hour, min; + ogame->GetTime( day, hour, min ); + str = (min > 9) ? Z hour + ":" + Z min : Z hour + ":0" + Z min; + } + + if ( Options::UseTimeMultiplier && ztimer->factorMotion != 1.0f ) { + color = zCOLOR( 255, 0, 0 ); + if ( str.Length() ) str = str + " "; + str = str + "x" + Z ztimer->factorMotion; + } + + if ( !str.Length() ) + return; + + zSTRING texture = "ICON_CLOCK"; // https://game-icons.net/1x1/lorc/empty-hourglass.html + + infoIcons++; + color.alpha = ogame->hpBar->alpha; + IconInfo icon = IconInfo( screen->FontY(), screen->FontY() * 2.5 * infoIcons, screen->FontY() * 0.9f, color, texture, str ); + } + + void PlayerStatus::ShowMunitionAmount() { + if ( !Options::ShowMunitionAmount ) + return; + + if ( playerHelper.LeftInvOpen() || playerHelper.IsConUp() || !ogame->GetShowPlayerStatus() || !ogame->hpBar ) + return; + + oCItem* weapon = player->GetEquippedRangedWeapon(); + + if ( !weapon ) weapon = player->GetWeapon(); + + if ( !weapon || !weapon->HasFlag( ITM_CAT_FF ) || weapon->munition <= 0 ) + return; + + int amount = 0; + zCOLOR color = zCOLOR( 255, 255, 255 ); + + player->inventory2.UnpackAllItems(); + if ( oCItem* munition = player->IsInInv( weapon->munition, 1 ) ) + amount += munition->amount; + + if ( oCItem* munition = player->GetHandMunition() ) + amount += munition->instanz == weapon->munition; + + if ( amount == 0 ) + color = zCOLOR( 255, 0, 0 ); + else if ( amount < 10 ) + color = zCOLOR( 231, 76, 60 ); + else if ( amount < 25 ) + color = zCOLOR( 255, 175, 0 ); + else if ( amount < 50 ) + color = zCOLOR( 255, 218, 121 ); + + zSTRING texture = (weapon->HasFlag( ITM_FLAG_BOW )) ? "LABEL_MUN_BOW" : "LABEL_MUN_CROSSBOW"; + + infoIcons++; + color.alpha = ogame->hpBar->alpha; + IconInfo icon = IconInfo( screen->FontY(), screen->FontY() * 2.5 * infoIcons, screen->FontY() * 0.9f, color, texture, Z amount ); + } + + void PlayerStatus::ShowSaveReminder() { + if ( + Options::SaveReminder == Invalid + || !ogame + || !player + || playerHelper.IsBusy() + || quickSave->IsBusy() + || playerHelper.IsDead() + || playerHelper.IsConUp() + || !ogame->GetShowPlayerStatus() + || !ogame->game_drawall + ) + { + return; + } + + auto ElapsedTime = std::chrono::high_resolution_clock::now() - lastSaveTime; + auto ElapsedMins = std::chrono::duration_cast(ElapsedTime); + auto ElapsedSeconds = std::chrono::duration_cast(ElapsedTime - ElapsedMins); + if ( ElapsedTime >= static_cast( Options::SaveReminder ) ) + { + zSTRING str = ( ElapsedMins.count() < 10 ? "0" : "" ) + Z ElapsedMins.count() + ":" + ( ElapsedSeconds.count() < 10 ? "0" : "" ) + Z static_cast( ElapsedSeconds.count() ); + + zSTRING texture = "ICON_SAVE"; // https://game-icons.net/1x1/lorc/disc.html + + infoIcons++; + IconInfo icon = IconInfo(screen->FontY(), screen->FontY() * 2.5 * infoIcons, screen->FontY() * 0.9f, GFX_RED, texture, str); + } + } + + void PlayerStatus::StatusBars() { + if ( !hpBar ) + hpBar = new StatusBar( ogame->hpBar ); + + if ( !manaBar ) + manaBar = new StatusBar( ogame->manaBar ); + + if ( !focusBar ) + focusBar = new StatusBar( ogame->focusBar ); + + if ( !swimBar ) + swimBar = new StatusBar( ogame->swimBar ); + + hpBar->Loop(); + manaBar->Loop(); + focusBar->Loop(); + swimBar->Loop(); + } + + void PlayerStatus::Clear() { + focusColor.Clear(); + debugHelper.Clear(); + + if ( hpBar ) + hpBar->Clear(); + + if ( manaBar ) + manaBar->Clear(); + + if ( focusBar ) + focusBar->Clear(); + + if ( swimBar ) + swimBar->Clear(); + } + + void PlayerStatus::Loop() { + if ( !ogame || !player ) + return; + + if ( quickSave->IsBusy() ) { + Clear(); + return; + } + + infoIcons = 0; + + debugHelper.Loop(); + focusColor.Loop(); + StatusBars(); + FactorMotion(); + ShowGameTime(); + ShowMunitionAmount(); + ShowSaveReminder(); + HandleMunitionLoop(); + RenderSelectedItem(); + } +} \ No newline at end of file diff --git a/zUtilities/PlayerStatus.h b/zUtilities/PlayerStatus.h new file mode 100644 index 0000000..a2dc4c8 --- /dev/null +++ b/zUtilities/PlayerStatus.h @@ -0,0 +1,67 @@ +// Supported with union (c) 2020 Union team +// Union HEADER file + +namespace GOTHIC_ENGINE { + namespace Options { + bool ShowGameTime, ShowMunitionAmount, ShowTargetProtection, ShowPickpocketIcon, UseTimeMultiplier; + int KeyTimeMultiplier; + Array TimeMultipliers; + int SaveReminder; + + void PlayerStatus() { + ShowGameTime = zoptions->ReadBool( PLUGIN_NAME, "ShowGameTime", false ); + ShowMunitionAmount = zoptions->ReadBool( PLUGIN_NAME, "ShowMunitionAmount", false ); + ShowTargetProtection = zoptions->ReadBool( PLUGIN_NAME, "ShowTargetProtection", true ); +#if ENGINE >= Engine_G2 + ShowPickpocketIcon = zoptions->ReadBool( PLUGIN_NAME, "ShowPickpocketIcon", true ); +#endif + UseTimeMultiplier = zoptions->ReadBool( PLUGIN_NAME, "UseTimeMultiplier", false ); + KeyTimeMultiplier = GetEmulationKeyCode( zoptions->ReadString( PLUGIN_NAME, "KeyTimeMultiplier", "KEY_Z" ) ); + string MulString = A zoptions->ReadString( PLUGIN_NAME, "TimeMultipliers", "1.0|2.5" ); + + Array MulStrings = MulString.Split( "|" ); + TimeMultipliers.Clear(); + for ( int i = 0; i < MulStrings.GetNum(); i++ ) + TimeMultipliers.Insert( MulStrings[i].Shrink().ToReal32() ); + + SaveReminder = zoptions->ReadInt(PLUGIN_NAME, "SaveReminder", 5); + } + } + + class PlayerStatus { + private: + StatusBar* hpBar; + StatusBar* manaBar; + StatusBar* swimBar; + int multiplierIndex = 0; + int infoIcons = 0; + std::chrono::high_resolution_clock::time_point lastSaveTime; + + void ShowGameTime(); + void ShowMunitionAmount(); + void ShowSaveReminder(); + void StatusBars(); + void FactorMotion(); + + public: + zCArray pickpocketInfos; + zCArray interStateFuncs; + zCArray stateFuncItems; + oCItem* stateFuncItem; + oCNpc* traderNpc; + StatusBar* focusBar; + bool CanPickpocketNpc( oCNpc* npc ); + void GetPickpocketInfos(); + bool CanChangeZtimer(); + bool KnowStateFunc( zCVob* vob ); + void TryAddStateFunc( zCVob* vob ); + void ResetTimeMultiplier(); + void ResetSaveReminder(); + void Clear(); + void Loop(); + void Archive( zCArchiver* ar ); + void Unarchive( zCArchiver* ar ); + }; + + PlayerStatus playerStatus; +} \ No newline at end of file diff --git a/zUtilities/Plugin.cpp b/zUtilities/Plugin.cpp index 155ef8f..e28aa1a 100644 --- a/zUtilities/Plugin.cpp +++ b/zUtilities/Plugin.cpp @@ -7,11 +7,7 @@ namespace GOTHIC_ENGINE { } void Game_Init() { - Options::Misc(); - Options::QuickSave(); - Options::FocusColor(); - Options::ItemLabel(); - Options::DamagePopup(); + Options::ReadOptions(); Options::AddTrivias(); RegisterCommands(); quickSave = new QuickSave(); @@ -27,9 +23,8 @@ namespace GOTHIC_ENGINE { for ( uint i = 0; i < popups.GetNum(); i++ ) popups[i]->Update(); - debugHelper.DebugHelperLoop(); - focusColor.FocusColorLoop(); - quickSave->QuickSaveLoop(); + quickSave->Loop(); + playerStatus.Loop(); } void Game_PostLoop() { @@ -42,21 +37,32 @@ namespace GOTHIC_ENGINE { TSaveLoadGameInfo& SaveLoadGameInfo = UnionCore::SaveLoadGameInfo; void Game_SaveBegin() { - playerHelper.isSaving = true; - debugHelper.Clear(); + quickSave->isSaving = true; + playerStatus.Clear(); } void Game_SaveEnd() { - playerHelper.isSaving = false; + quickSave->saveEnd = true; + Archive(); + playerStatus.ResetSaveReminder(); } void LoadBegin() { - debugHelper.Clear(); + quickSave->isLoading = true; +#if ENGINE >= Engine_G2 + playerStatus.pickpocketInfos.EmptyList(); +#endif + playerStatus.Clear(); for ( uint i = 0; i < popups.GetNum(); i++ ) delete popups[i]; } void LoadEnd() { + Unarchive(); +#if ENGINE >= Engine_G2 + playerStatus.GetPickpocketInfos(); +#endif + playerStatus.ResetSaveReminder(); } void Game_LoadBegin_NewGame() { @@ -93,6 +99,7 @@ namespace GOTHIC_ENGINE { } void Game_Unpause() { + Options::ReadOptions(); } void Game_DefineExternals() { diff --git a/zUtilities/Plugin.h b/zUtilities/Plugin.h index ffbc60d..059da5f 100644 --- a/zUtilities/Plugin.h +++ b/zUtilities/Plugin.h @@ -1,4 +1,3 @@ - // This file added in headers queue // File: "Headers.h" diff --git a/zUtilities/QuickSave.cpp b/zUtilities/QuickSave.cpp index 0e9be7d..ff5ddea 100644 --- a/zUtilities/QuickSave.cpp +++ b/zUtilities/QuickSave.cpp @@ -27,7 +27,7 @@ namespace GOTHIC_ENGINE { } int QuickSave::InInteraction() { - if ( playerHelper.IsSaving() ) return true; + if ( IsBusy() ) return true; if ( playerHelper.IsBusy() ) return true; if ( player->bodyState == BS_TAKEITEM ) return true; if ( player->bodyState == BS_MOBINTERACT ) return true; @@ -36,18 +36,33 @@ namespace GOTHIC_ENGINE { return false; } + bool QuickSave::IsBusy() { + return isSaving || isLoading; + } + int QuickSave::CanSave() { if ( playerHelper.IsDead() ) return false; if ( InInteraction() ) return false; if ( player->GetAnictrl()->state != zCAIPlayer::zMV_STATE_STAND ) return false; + if (player->HasBodyStateModifier(BS_MOD_TRANSFORMED)) return false; //if ( ogame->game_testmode ) return false; //if ( !player->IsInFightMode_S(0) ) return false; + zSTRING saveMenu = gameMan->menu_save_savegame ? gameMan->menu_save_savegame->name : "MENU_SAVEGAME_SAVE"; + + for ( int i = 0; i < zCMenuItem::itemList.GetNum(); i++ ) { + zCMenuItem* item = zCMenuItem::itemList[i]; + if ( item->m_parOnSelAction_S[0] == saveMenu ) { + bool cantSave = item->m_parItemFlags & IT_DISABLED || item->m_parItemFlags & IT_ONLY_OUT_GAME; + return !cantSave; + } + } + return true; } void QuickSave::CheckSave() { - if ( !zinput->KeyToggled( KEY_F10 ) ) + if ( !zinput->KeyToggled( Options::KeyQuickSave ) ) return; if ( !CanSave() ) { @@ -55,21 +70,101 @@ namespace GOTHIC_ENGINE { return; } - iLastSaveSlot++; - iLastSaveNumber++; - if ( iLastSaveSlot > Options::MaxSaveSlot || iLastSaveSlot < Options::MinSaveSlot ) - iLastSaveSlot = Options::MinSaveSlot; + if ( Options::QuickSaveMode == QuickSaveMode::Alternative ) { + // The algorithm looks very like adding numbers in binary. + // The idea behind using a binary addition is too use some SaveSlots + // more frequently then others. for example: + // Slot0 -> will be used 50% + // Slot1 -> will be used 25% + // Slot2 -> will be used 12% + // Slot3 -> will be used 6% + // Slot4 -> will be used 3% + // Slot5 -> will be used 1% + // Thanks to that, we have Slot5, Slot4 keeping the oldest (in actual date time) Saves + // Whiles Slot0, Slot1, keeping the newest (in actual date time) Saves + // This will give the ability to Load old save from Slot5, that was saved (lets say 2 ^ 5 = 32 saves ago) + // And at the same time, we have Slot1, Slot2 with newest saves (lets say last save) + // + // Example of such saving, I will mark a SaveSpot with brackets (numbers are an ID of a save): + // - [1] 1 [3] 3 [5] 5 [7] 7 + // - - [2] 2 2 2 [6] 6 6 + // - - - - [4] 4 4 4 4 + // - - - - - - - - [8] + // + // And their binary representation (numbers are a binary tree that helps me to determine SaveSpot): + // 0 [1] 0 [1] 0 [1] 0 [1] 0 + // 0 0 [1] 1 0 0 [1] 1 0 + // 0 0 0 0 [1] 1 1 1 0 + // 0 0 0 0 0 0 0 0 [1] + // + // And their decimal representation: + // 0 1 2 3 4 5 6 7 8 + // + // As you can see, the SaveSpots (brackets), are in a places where the + // number changed from 0 -> 1, number changing from 1 -> 0 does not matter. + // + // + // The problem in implementing that, is to create a naming system that + // can determine the Spot to Save, at any give point in time. + // Even after exit/restart of the game. + + // We are saving for the first time probably + if ( iLastSaveNumber == Invalid ) { + iLastSaveSlot = Options::MinSaveSlot; + iLastSaveNumber = 1; // I could use ZERO as a first SaveName, it doesn't matter. number ONE is just more pleasant to the eye + } + // we need to figure out, on which slot to put next save. + else { + int const curName = iLastSaveNumber; + int const nextName = curName + 1; + // Now we need to find a change from 0 -> 1 between maxName and nextName + int changeIndex = -1; + int mask = ((int)1); // 0...01 + for ( int i = 0; i < (sizeof( int ) * 8) - 1; ++i ) { + if ( (nextName & mask) > ( curName & mask ) ) { + changeIndex = i; + break; + } + // this operation moves 1 to the right, and resets first bit to 0, in order to check next bit + mask = (mask << 1) & (~((int)1)); // 1...10 + } + + if ( changeIndex != -1 ) { + // We found an index where change happens, but this index is between 0 and 31. + // We need to cap it between Options::MinSaveSlot and Options::MaxSaveSlot + // To do it, I will wrap the number system around + int const slots = Options::MaxSaveSlot - Options::MinSaveSlot; + while ( changeIndex > slots ) { + // this operation moves the index one to the left, in order to fit in number of available slots + changeIndex -= slots; + } + iLastSaveSlot = Options::MinSaveSlot + changeIndex; + iLastSaveNumber++; + } + } + } + else { + iLastSaveSlot++; + iLastSaveNumber++; + if ( iLastSaveSlot > Options::MaxSaveSlot || iLastSaveSlot < Options::MinSaveSlot ) + iLastSaveSlot = Options::MinSaveSlot; + } // Thumbnail zCTextureConvert* thumb = zrenderer->CreateTextureConvert(); zrenderer->Vid_GetFrontBufferCopy( *thumb ); // SaveGame - ToggleShowStatus(); + isSaving = true; + StartSaveLoad(); +#if ENGINE == Engine_G1A ogame->WriteSavegame( iLastSaveSlot, true ); +#else + gameMan->Write_Savegame( iLastSaveSlot ); +#endif // SaveInfo - auto info = ogame->savegameManager->GetSavegame( iLastSaveSlot ); + oCSavegameInfo* info = gameMan->savegameManager->GetSavegame( iLastSaveSlot ); info->m_Name = Z Options::SaveName + Z iLastSaveNumber; info->m_WorldName = ogame->GetGameWorld()->GetWorldName(); @@ -82,11 +177,11 @@ namespace GOTHIC_ENGINE { info->UpdateThumbPic( thumb ); delete thumb; - ogame->savegameManager->SetAndWriteSavegame( iLastSaveSlot, info ); + gameMan->savegameManager->SetAndWriteSavegame( info->m_SlotNr, info ); } void QuickSave::CheckLoad() { - if ( !zinput->KeyToggled( KEY_F12 ) ) + if ( !zinput->KeyToggled( Options::KeyQuickLoad ) ) return; if ( InInteraction() ) { @@ -94,29 +189,47 @@ namespace GOTHIC_ENGINE { return; } - if ( !ogame->savegameManager->GetSavegame( iLastSaveSlot )->DoesSavegameExist() ) { + oCSavegameInfo* info = gameMan->savegameManager->GetSavegame( iLastSaveSlot ); + + if ( !info || !info->DoesSavegameExist() ) { ogame->GetTextView()->Printwin( Z Options::NoSave + " (" + Z iLastSaveSlot + ")" ); return; } - ToggleShowStatus(); - ogame->LoadSavegame( iLastSaveSlot, true ); + isLoading = true; + StartSaveLoad(); +#if ENGINE == Engine_G1A + ogame->LoadSavegame( info->m_SlotNr, true ); +#else + gameMan->Read_Savegame( info->m_SlotNr ); +#endif + } + + void QuickSave::StartSaveLoad() { + if ( ogame->GetShowPlayerStatus() ) { + disabledStatus = true; + ogame->SetShowPlayerStatus( false ); + } } - void QuickSave::ToggleShowStatus() { - if ( !oldShowStatus ) return; + void QuickSave::EndSaveLoad() { + isSaving = false; + isLoading = false; + saveEnd = false; - ogame->SetShowPlayerStatus( toggledShowStatus ); - toggledShowStatus = !toggledShowStatus; + if ( disabledStatus ) { + disabledStatus = false; + ogame->SetShowPlayerStatus( true ); + } } - void QuickSave::QuickSaveLoop() { - if ( !Options::UseQuickSave ) return; + void QuickSave::Loop() { + if ( (isLoading && !ogame->IsOnPause()) || (isSaving && saveEnd) ) + EndSaveLoad(); - if ( !toggledShowStatus ) - oldShowStatus = ogame->GetShowPlayerStatus(); - else - ToggleShowStatus(); + if ( !Options::QuickSaveMode ) return; + + if ( ogame->IsOnPause() ) return; CheckLoad(); CheckSave(); @@ -125,5 +238,4 @@ namespace GOTHIC_ENGINE { QuickSave::QuickSave() { SetSaveSlotAndNr(); } -} - +} \ No newline at end of file diff --git a/zUtilities/QuickSave.h b/zUtilities/QuickSave.h index d97297a..763b88b 100644 --- a/zUtilities/QuickSave.h +++ b/zUtilities/QuickSave.h @@ -3,11 +3,14 @@ namespace GOTHIC_ENGINE { namespace Options { - int UseQuickSave, MinSaveSlot, MaxSaveSlot; + int QuickSaveMode, UseBinarySave, KeyQuickSave, KeyQuickLoad, MinSaveSlot, MaxSaveSlot; string CantSave, CantLoad, NoSave, SaveName; void QuickSave() { - UseQuickSave = zoptions->ReadInt( PLUGIN_NAME, "UseQuickSave", true ); + QuickSaveMode = zoptions->ReadInt( PLUGIN_NAME, "QuickSaveMode", 1 ); + + KeyQuickSave = GetEmulationKeyCode( zoptions->ReadString( PLUGIN_NAME, "KeyQuickSave", "KEY_F10" ) ); + KeyQuickLoad = GetEmulationKeyCode( zoptions->ReadString( PLUGIN_NAME, "KeyQuickLoad", "KEY_F12" ) ); #if ENGINE >= Engine_G2 MinSaveSlot = zoptions->ReadInt( PLUGIN_NAME, "MinSaveSlot", 15 ); @@ -17,7 +20,6 @@ namespace GOTHIC_ENGINE { MaxSaveSlot = zoptions->ReadInt( PLUGIN_NAME, "MaxSaveSlot", 15 ); #endif - switch ( Union.GetSystemLanguage() ) { case Lang_Rus: @@ -25,11 +27,6 @@ namespace GOTHIC_ENGINE { CantLoad = " !"; NoSave = " !"; break; - case Lang_Eng: - CantSave = "The game cannot be saved now!"; - CantLoad = "The game cannot be loaded now!"; - NoSave = "Such a save does not exist!"; - break; case Lang_Ger: CantSave = "Das Spiel kann jetzt nicht gespeichert werden!"; CantLoad = "Das Spiel kann jetzt nicht geladen werden!"; @@ -56,8 +53,7 @@ namespace GOTHIC_ENGINE { class QuickSave { private: - bool oldShowStatus = false; - bool toggledShowStatus = false; + bool disabledStatus = false; int iLastSaveSlot; int iLastSaveNumber; @@ -67,10 +63,21 @@ namespace GOTHIC_ENGINE { int InInteraction(); void CheckSave(); void CheckLoad(); - void ToggleShowStatus(); + void StartSaveLoad(); public: - void QuickSaveLoop(); + enum QuickSaveMode { + Disabled, + Standard, + Alternative + }; + + bool saveEnd = false; + bool isSaving = false; + bool isLoading = false; + void EndSaveLoad(); + bool IsBusy(); + void Loop(); QuickSave(); }; diff --git a/zUtilities/RenderItem.cpp b/zUtilities/RenderItem.cpp index 194c26c..c1a5db7 100644 --- a/zUtilities/RenderItem.cpp +++ b/zUtilities/RenderItem.cpp @@ -13,6 +13,11 @@ namespace GOTHIC_ENGINE { THISCALL( Hook_CMovementTracker_UpdatePlayerPos )(position); } + zCWorld* renderWld = nullptr; + zCViewBase* renderView = nullptr; + float renderRotate = 0; + bool renderNow = false; + HOOK Hook_oCItem_RenderItem PATCH( &oCItem::RenderItem, &oCItem::RenderItem_Union ); void oCItem::RenderItem_Union( zCWorld* wld, zCViewBase* view, float rotate ) { if ( Options::CenterInvItems ) { @@ -28,6 +33,13 @@ namespace GOTHIC_ENGINE { zCView* itemView = static_cast(view); IsCenterItem = true; + if ( !renderNow ) { + renderWld = wld; + renderView = view; + renderRotate = rotate; + return; + } + // Item scale float scale = 2.5; itemView->psizex *= scale; @@ -51,6 +63,7 @@ namespace GOTHIC_ENGINE { RotateForInventory( 1 ); } #endif + renderNow = false; } #if ENGINE >= Engine_G2 @@ -64,13 +77,33 @@ namespace GOTHIC_ENGINE { if ( Options::LabelItems ) { if ( !Options::PutLabelBehind ) { THISCALL( Hook_oCItem_RenderItem )(wld, view, rotate); - new ItemLabel( this, view ); + ItemLabel label = ItemLabel( this, view ); return; } - new ItemLabel( this, view ); + ItemLabel label = ItemLabel( this, view ); } THISCALL( Hook_oCItem_RenderItem )(wld, view, rotate); } + + void RenderSelectedItem() { + if ( !Options::CenterInvItems ) + return; + + if ( player->inventory2.IsOpen() ) { + oCItemContainer* leftInv = player->inventory2.GetNextContainerLeft( &player->inventory2 ); + oCItem* item = (leftInv && leftInv->IsActive()) ? leftInv->GetSelectedItem() : player->inventory2.GetSelectedItem(); + + renderNow = true; + if ( item && renderWld && renderView ) { + item->RenderItem( renderWld, renderView, renderRotate ); + zrenderer->SetViewport( 0, 0, zrenderer->vid_xdim, zrenderer->vid_ydim ); + } + } + + renderWld = nullptr; + renderView = nullptr; + renderRotate = 0; + } } \ No newline at end of file diff --git a/zUtilities/Sources.h b/zUtilities/Sources.h index 65fe48d..27a4aad 100644 --- a/zUtilities/Sources.h +++ b/zUtilities/Sources.h @@ -4,14 +4,23 @@ // Automatically generated block #pragma region Includes #include "Misc.cpp" +#include "User.cpp" #include "Commands.cpp" +#include "IconInfo.cpp" #include "DebugHelper.cpp" #include "FocusColor.cpp" #include "QuickSave.cpp" #include "Meatbug.cpp" +#include "Lockable.cpp" #include "ItemLabel.cpp" #include "RenderItem.cpp" #include "DamagePopup.cpp" +#include "Inventory.cpp" +#include "StatusBar.cpp" +#include "Dialogue.cpp" +#include "LogBook.cpp" +#include "PlayerStatus.cpp" +#include "Archive.cpp" #include "Plugin.cpp" #pragma endregion diff --git a/zUtilities/StatusBar.cpp b/zUtilities/StatusBar.cpp new file mode 100644 index 0000000..3e608c2 --- /dev/null +++ b/zUtilities/StatusBar.cpp @@ -0,0 +1,302 @@ +// Supported with union (c) 2020 Union team +// Union SOURCE file + +namespace GOTHIC_ENGINE { + int oCItem::GetLineTextIsIn( zSTRING str ) { + for ( int i = 0; i < ITM_TEXT_MAX; i++ ) + if ( text[i] == str ) + return i; + + return Invalid; + } + + int StatusBar::GetValueFromItem( oCItem* item, int atr ) { + int healValue = 0; + + for ( int i = 0; i < symbols.GetNumInList(); i++ ) { + auto sym = parser->GetSymbol( symbols[i] ); + if ( !sym ) + continue; + + zSTRING symStr = sym->stringdata; + if ( !symStr.Length() ) + continue; + + int line = item->GetLineTextIsIn( symStr ); + if ( line == Invalid ) + continue; + + if ( symbols[i].EndWith( "_FULL" ) ) { + return player->GetAttribute( atr ); + } + else if ( symbols[i].EndWith( "_PERC" ) ) { + healValue += player->GetAttribute( atr ) * item->count[line] / 100; + } + else { + healValue += item->count[line]; + } + } + + return healValue; + } + + bool StatusBar::IsBarActive() { + return bar->owner; + } + + bool StatusBar::Init() { + if ( bar == ogame->focusBar ) + return true; + + if ( bar == ogame->hpBar ) { + symbols.Insert( "NAME_BONUS_HP_FULL" ); // Full Heal + symbols.Insert( "NAME_BONUS_HP_PERC" ); // Percentage Heal + symbols.Insert( "NAME_BONUS_HP" ); // Flat Heal + if ( Options::StatusBarNames.GetNum() >= 1 ) + name = Z Options::StatusBarNames[0]; + + if ( Options::HealthBarPos.GetNum() == 4 ) + userPos = Options::HealthBarPos; + + return true; + } + + if ( bar == ogame->manaBar ) { + symbols.Insert( "NAME_BONUS_MANA_FULL" ); // Full Heal + symbols.Insert( "NAME_BONUS_MANA_PERC" ); // Percentage Heal + symbols.Insert( "NAME_BONUS_MANA" ); // Flat Heal + if ( Options::StatusBarNames.GetNum() >= 2 ) + name = Z Options::StatusBarNames[1]; + + if ( Options::ManaBarPos.GetNum() == 4 ) + userPos = Options::ManaBarPos; + + return true; + } + + if ( bar == ogame->swimBar ) { + if ( Options::StatusBarNames.GetNum() >= 3 ) + name = Z Options::StatusBarNames[2]; + + if ( Options::SwimBarPos.GetNum() == 4 ) + userPos = Options::SwimBarPos; + + return true; + } + + return false; + } + + int StatusBar::GetHealValue() { + if ( !player->inventory2.IsOpen() ) + return 0; + + if ( (int)bar->currentValue == (int)bar->maxHigh ) + return 0; + + oCItem* item = player->inventory2.GetSelectedItem(); + if ( !item ) + return 0; + + if ( !item->onState[0] ) + return 0; + + if ( !item->HasFlag( ITM_CAT_FOOD ) && !item->HasFlag( ITM_CAT_POTION ) ) + return 0; + + if ( bar == ogame->hpBar ) + return GetValueFromItem( item, NPC_ATR_HITPOINTSMAX ); + + if ( bar == ogame->manaBar ) + return GetValueFromItem( item, NPC_ATR_MANAMAX ); + + return 0; + } + + void StatusBar::DrawPrediction( int value ) { + int current = (int)bar->currentValue * 100 / (int)bar->maxHigh; + int bonus = min( value * 100 / (int)bar->maxHigh, 100 ); + + if ( bonus + current > 100 ) + bonus = 100 - current; + + int start = current * 8192 / 100; + + int x1 = max( start, 0 ); + int y1 = bar->range_bar->py1; + int x2 = min( bonus * 8192 / 100 + start, 8192 ); + int y2 = bar->range_bar->py2; + + predictView = new zCView( x1, y1, x2, y2 ); + predictView->InsertBack( bar->texValue ); + predictView->SetAlphaBlendFunc( zRND_ALPHA_FUNC_BLEND ); + predictView->SetTransparency( 85 ); + bar->range_bar->InsertItem( predictView ); + } + + void StatusBar::PredictHeal() { + if ( !Options::RecoveryVisualization ) + return; + + del( predictView ); + + if ( !IsBarActive() ) + return; + + int value = GetHealValue(); + if ( value <= 0 ) + return; + + DrawPrediction( value ); + } + + void StatusBar::PrintValue( oCNpc* npc ) { + if ( !Options::StatusBarValueMode ) + return; + + del( valueView ); + + if ( !IsBarActive() ) + return; + + valueView = new zCView( 0, 0, 8192, 8192 ); + + zSTRING str; + if ( bar == ogame->swimBar ) + str = Z( int )(bar->currentValue / 100) + "/" + Z( int )(bar->maxHigh / 100); + else + str = Z( int )bar->currentValue + "/" + Z( int )bar->maxHigh; + + if ( name && name.Length() ) + str = name + ": " + str; + + zCView* ownerView = (Options::StatusBarValueMode == Inside) ? bar->range_bar : screen; + ownerView->InsertItem( valueView ); + + if ( Options::StatusBarValueMode != Inside ) { + int offsetY = bar->vsizey / 2 + valueView->FontY(); + int x = bar->vposx + bar->vsizex / 2 - valueView->FontSize( str ) / 2; + int y = bar->vposy; + bool center = false; + + if ( bar == ogame->focusBar && Options::ShowEnemyBarAboveHim ) + y -= offsetY; + else if ( Options::StatusBarValueMode == Above ) + center = true; + else if ( bar->vposx + bar->vsizex < 3072 ) + x = bar->vposx + bar->vsizex + valueView->FontY() / 2; + else if ( bar->vposx > 5120 ) + x = bar->vposx - valueView->FontSize( str ) - valueView->FontY() / 2; + else + center = true; + + if ( center ) + if ( bar->vposy + bar->vsizey > 4092 ) + y -= offsetY; + else + y += offsetY; + + valueView->SetFontColor( zCOLOR( valueView->color.r, valueView->color.g, valueView->color.b, bar->alpha ) ); + valueView->Print( x, y, str ); + return; + } + + valueView->PrintCXY( str ); + } + + void StatusBar::MoveFocusBar( int x, int y, oCNpc* npc ) { + if ( !Options::ShowEnemyBarAboveHim ) + return; + + if ( bar != ogame->focusBar ) + return; + + if ( !IsBarActive() ) + return; + + zCCamera* cam = ogame->GetCamera(); + zVEC3 viewPos = cam->GetTransform( zTCamTrafoType::zCAM_TRAFO_VIEW ) * npc->GetPositionWorld(); + int posx, posy; + cam->Project( &viewPos, posx, posy ); + if ( viewPos[VZ] <= cam->nearClipZ ) + return; + + x = x + screen->FontSize( npc->name[0] ) / 2 - bar->vsizex / 2; + if ( x + bar->vsizex > 8192 ) + x = 8192 - bar->vsizex; + + x = max( 0, x ); + y = max( 0, y - screen->FontY() * 1.75 ); + + bar->SetPos( x, y ); + } + + void StatusBar::ChangeBarPos() { + if ( userPos.GetNum() != 4 ) + return; + + if ( !IsBarActive() ) + return; + + int x1 = userPos[0].ToInt32(); + int y1 = userPos[1].ToInt32(); + + if ( x1 < 0 || x1 > 8192 || y1 < 0 || y1 > 8192 ) + return; + + int x2 = userPos[2].ToInt32() - x1; + int y2 = userPos[3].ToInt32() - y1; + + if ( x2 <= 0 || y2 <= 0 ) + return; + + bar->SetPos( x1, y1 ); + bar->SetSize( x2, y2 ); + } + + bool StatusBar::NeedAdjustPosition( int x, int y, oCNpc* npc ) { + if ( !ogame->focusBar || !npc || npc->attribute[NPC_ATR_HITPOINTS] <= 0 ) + return false; + + playerStatus.focusBar->MoveFocusBar( x, y, npc ); + playerStatus.focusBar->PrintValue( npc ); + return Options::ShowEnemyBarAboveHim; + } + + void StatusBar::Clear() { + if ( !bar ) + return; + + del( valueView ); + del( predictView ); + } + + void StatusBar::Loop() { + if ( !ogame || !player ) + return; + + if ( !bar ) + return; + + if ( bar == ogame->focusBar ) { + if ( valueView ) + valueView->ClrPrintwin(); + + return; + } + + ChangeBarPos(); + PredictHeal(); + PrintValue( player ); + } + + StatusBar::StatusBar( oCViewStatusBar* bar ) { + this->bar = bar; + + if ( !Init() ) + return; + + if ( Options::StatusBarValueMode == Inside && !playerHelper.GetSysScale() ) + this->bar->vsizey *= 1.15; + } +} \ No newline at end of file diff --git a/zUtilities/StatusBar.h b/zUtilities/StatusBar.h new file mode 100644 index 0000000..2fcf616 --- /dev/null +++ b/zUtilities/StatusBar.h @@ -0,0 +1,54 @@ +// Supported with union (c) 2020 Union team +// Union HEADER file + +namespace GOTHIC_ENGINE { + namespace Options { + bool RecoveryVisualization, ShowEnemyBarAboveHim; + int StatusBarValueMode; + Array StatusBarNames, HealthBarPos, ManaBarPos, SwimBarPos; + + void StatusBar() { + RecoveryVisualization = zoptions->ReadBool( PLUGIN_NAME, "RecoveryVisualization", true ); + StatusBarValueMode = zoptions->ReadInt( PLUGIN_NAME, "StatusBarValueMode", 1 ); + ShowEnemyBarAboveHim = zoptions->ReadBool( PLUGIN_NAME, "ShowEnemyBarAboveHim", true ); + StatusBarNames = (A zoptions->ReadString( PLUGIN_NAME, "StatusBarNames", "" )).Split( "|" ); + HealthBarPos = (A zoptions->ReadString( PLUGIN_NAME, "HealthBarPos", "" )).Split( "|" ); + ManaBarPos = (A zoptions->ReadString( PLUGIN_NAME, "ManaBarPos", "" )).Split( "|" ); + SwimBarPos = (A zoptions->ReadString( PLUGIN_NAME, "SwimBarPos", "" )).Split( "|" ); + } + } + + class StatusBar { + private: + oCViewStatusBar* bar; + zCView* valueView; + zCView* predictView; + zCView* focusView; + zCArray symbols; + zSTRING name; + Array userPos; + + bool Init(); + bool IsBarActive(); + int GetValueFromItem( oCItem* item, int atr ); + int GetHealValue(); + void DrawPrediction( int value ); + void PredictHeal(); + void PrintValue( oCNpc* npc ); + void MoveFocusBar( int x, int y, oCNpc* npc ); + void ChangeBarPos(); + + public: + enum ValueMode { + Disabled, + Above, + PointToCenter, + Inside + }; + + bool NeedAdjustPosition( int x, int y, oCNpc* npc ); + void Loop(); + void Clear(); + StatusBar( oCViewStatusBar* bar ); + }; +} \ No newline at end of file diff --git a/zUtilities/User.cpp b/zUtilities/User.cpp new file mode 100644 index 0000000..5295d71 --- /dev/null +++ b/zUtilities/User.cpp @@ -0,0 +1,61 @@ +// Supported with union (c) 2020 Union team +// Union SOURCE file + +namespace GOTHIC_ENGINE { + void zCOption::AddTrivia( const string sectionName, const string entryName, string trivia ) { + zCOption* const& option = this; + zCOptionSection* section = option->GetSectionByName( sectionName, true ); + + if ( !section ) return; + + zCOptionEntry* entry = option->GetEntryByName( section, entryName, true ); + + if ( !entry ) return; + + zCOptionEntry* triviaEntry = new zCOptionEntry{ "", (A"; " + trivia + "\r\n\n") }; + + int nextPos = section->entryList.Search( entry ) + 1; + + if ( nextPos > section->entryList.GetNumInList() - 1 ) { + section->entryList.InsertEnd( triviaEntry ); + return; + } + + zSTRING nextLine = section->entryList[nextPos]->varValue; + + if ( nextLine.StartWith( "; " + trivia ) ) { + delete triviaEntry; + return; + } + + if ( nextLine.StartWith( "; " ) ) { + section->entryList[nextPos] = triviaEntry; + return; + } + + section->entryList.InsertAtPos( triviaEntry, nextPos ); + } + + zCOLOR* zCOption::ReadColor( zSTRING const& sectionName, zSTRING const& entryName, char const* text ) { + Array splitted = (A zoptions->ReadString( sectionName, entryName, text )).Split( "|" ); + Array channels; + + for ( int i = 0; i < splitted.GetNum(); i++ ) { + splitted[i] = splitted[i].Shrink(); + if ( !splitted[i].IsNumber() ) return nullptr; + + int value = splitted[i].ToInt32(); + if ( value < 0 || value > 255 ) return nullptr; + + channels.Insert( value ); + } + + int size = channels.GetNum(); + if ( size != 3 && size != 4 ) + return nullptr; + + zCOLOR* color = new zCOLOR( channels[CR], channels[CG], channels[CB] ); + if ( size == 4 ) color->alpha = channels[CA]; + return color; + } +} \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/oCAIHuman.inl b/zUtilities/ZenGin/Gothic_UserAPI/oCAIHuman.inl index 565289e..15d471d 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/oCAIHuman.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/oCAIHuman.inl @@ -3,3 +3,4 @@ // User API for oCAIHuman // Add your methods here +void PC_Turnings_Union( int forceRotation ); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/oCInformationManager.inl b/zUtilities/ZenGin/Gothic_UserAPI/oCInformationManager.inl index a43283f..7cd6feb 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/oCInformationManager.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/oCInformationManager.inl @@ -3,3 +3,5 @@ // User API for oCInformationManager // Add your methods here +void __fastcall OnTradeBegin_Union(); +void __fastcall OnTradeEnd_Union(); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/oCItem.inl b/zUtilities/ZenGin/Gothic_UserAPI/oCItem.inl index 506dbe0..463fb27 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/oCItem.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/oCItem.inl @@ -4,4 +4,7 @@ // Add your methods here void RenderItem_Union( zCWorld*, zCViewBase*, float ); -int GetHighestCond(); \ No newline at end of file +int GetHighestCond(); +int GetLineTextIsIn( zSTRING ); +int GetStateFunc(); +int GetStateEffectFunc_Union( int ); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/oCItemContainer.inl b/zUtilities/ZenGin/Gothic_UserAPI/oCItemContainer.inl index 78ca3a8..5f596df 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/oCItemContainer.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/oCItemContainer.inl @@ -3,3 +3,6 @@ // User API for oCItemContainer // Add your methods here +void __thiscall Draw_Union(); +void __thiscall DrawItemInfo_Union( oCItem*, zCWorld* ); +void __thiscall Close_Union(); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/oCLogTopic.inl b/zUtilities/ZenGin/Gothic_UserAPI/oCLogTopic.inl index 92e59f9..c8aa1b2 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/oCLogTopic.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/oCLogTopic.inl @@ -3,3 +3,4 @@ // User API for oCLogTopic // Add your methods here +void __fastcall AddEntry_Union( zSTRING const& ); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/oCMobInter.inl b/zUtilities/ZenGin/Gothic_UserAPI/oCMobInter.inl index 7f2d74b..63562bb 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/oCMobInter.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/oCMobInter.inl @@ -3,3 +3,5 @@ // User API for oCMobInter // Add your methods here +void __thiscall CallOnStateFunc_Union( oCNpc*, int ); +void __thiscall StopInteraction_Union( oCNpc* ); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/oCMobLockable.inl b/zUtilities/ZenGin/Gothic_UserAPI/oCMobLockable.inl index fb46c55..234d8dd 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/oCMobLockable.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/oCMobLockable.inl @@ -3,3 +3,4 @@ // User API for oCMobLockable // Add your methods here +int __thiscall PickLock_Union( oCNpc*, char ); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/oCNpc.inl b/zUtilities/ZenGin/Gothic_UserAPI/oCNpc.inl index 7392e56..108f4f4 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/oCNpc.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/oCNpc.inl @@ -4,5 +4,12 @@ // Add your methods here void __thiscall OnChrzonszcz( zCVob* ); -void __thiscall OnDamage_Hit_Union( oSDamageDescriptor& ); -int GetAivar( zSTRING aivar ); \ No newline at end of file +void OnDamage_Hit_Union( oSDamageDescriptor& ); +int GetAivar( zSTRING aivar ); +int EV_UseItemToState_Union( oCMsgManipulate* ); +int GetFistDamageIndex(); +int GetWeaponDamageIndex(); +int GetSpellDamageIndex(); +int GetActiveDamageIndex(); +void CopyTransformSpellInvariantValuesTo_Union( oCNpc* ); +oCItem* GetHandMunition(); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/oCVisualFX.inl b/zUtilities/ZenGin/Gothic_UserAPI/oCVisualFX.inl index 4f58bf6..abdbea8 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/oCVisualFX.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/oCVisualFX.inl @@ -3,3 +3,7 @@ // User API for oCVisualFX // Add your methods here +#if ENGINE >= Engine_G2 +void InitEffect_Union(); +void EndEffect_Union(const int); +#endif \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/zCAICamera.inl b/zUtilities/ZenGin/Gothic_UserAPI/zCAICamera.inl index 9306242..120ed9c 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/zCAICamera.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/zCAICamera.inl @@ -3,3 +3,4 @@ // User API for zCAICamera // Add your methods here +void CheckKeys_Union(); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/zCArchiver.inl b/zUtilities/ZenGin/Gothic_UserAPI/zCArchiver.inl index 2210cdf..caa7e97 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/zCArchiver.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/zCArchiver.inl @@ -3,3 +3,4 @@ // User API for zCArchiver // Add your methods here +int ReadIntSafe( char const* text ); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/zCMenuItemList.inl b/zUtilities/ZenGin/Gothic_UserAPI/zCMenuItemList.inl index ca82e91..b2acbfb 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/zCMenuItemList.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/zCMenuItemList.inl @@ -3,3 +3,5 @@ // User API for zCMenuItemList // Add your methods here +void __thiscall DrawFront_Union(); +void ShowContent_Union(); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/zCOption.inl b/zUtilities/ZenGin/Gothic_UserAPI/zCOption.inl index cc80b89..f6d3a18 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/zCOption.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/zCOption.inl @@ -3,4 +3,5 @@ // User API for zCOption // Add your methods here -void AddTrivia( const string sectionName, const string entryName, string endTrivia ); \ No newline at end of file +void AddTrivia( const string sectionName, const string entryName, string endTrivia ); +zCOLOR* ReadColor( zSTRING const&, zSTRING const&, char const* ); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/zCView.inl b/zUtilities/ZenGin/Gothic_UserAPI/zCView.inl index d8a7ba5..538d42b 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/zCView.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/zCView.inl @@ -3,4 +3,5 @@ // User API for zCView // Add your methods here -void Print_Union( int, int, const zSTRING& ); \ No newline at end of file +void Print_Union( int, int, const zSTRING& ); +void DialogMessageCXY_Union( zSTRING const&, zSTRING const&, float, zCOLOR& ); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/zCViewDialogChoice.inl b/zUtilities/ZenGin/Gothic_UserAPI/zCViewDialogChoice.inl index 37062a2..310d14b 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/zCViewDialogChoice.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/zCViewDialogChoice.inl @@ -3,3 +3,4 @@ // User API for zCViewDialogChoice // Add your methods here +void __fastcall ShowSelected_Union(); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/zCViewPrint.inl b/zUtilities/ZenGin/Gothic_UserAPI/zCViewPrint.inl index 4c105a7..a27bf1a 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/zCViewPrint.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/zCViewPrint.inl @@ -3,3 +3,5 @@ // User API for zCViewPrint // Add your methods here +void __fastcall Blit_Union(); +void __fastcall BlitTextCharacters_Union( zCViewText2*, zCFont*, zCOLOR& ); \ No newline at end of file diff --git a/zUtilities/ZenGin/Gothic_UserAPI/zCVob.inl b/zUtilities/ZenGin/Gothic_UserAPI/zCVob.inl index a40024e..d52eecd 100644 --- a/zUtilities/ZenGin/Gothic_UserAPI/zCVob.inl +++ b/zUtilities/ZenGin/Gothic_UserAPI/zCVob.inl @@ -3,3 +3,6 @@ // User API for zCVob // Add your methods here +oCPortalRoom* GetCurrentPortalRoom(); +bool IsInRoomWith( zCVob* ); +float GetHeightDifferenceToVob( zCVob* ); \ No newline at end of file diff --git a/zUtilities/zUtilities.vcxproj b/zUtilities/zUtilities.vcxproj index e7b2d5b..1ae561c 100644 --- a/zUtilities/zUtilities.vcxproj +++ b/zUtilities/zUtilities.vcxproj @@ -86,121 +86,121 @@ DynamicLibrary true MultiByte - v142 + v143 DynamicLibrary true MultiByte - v142 + v143 DynamicLibrary true MultiByte - v142 + v143 DynamicLibrary true MultiByte - v142 + v143 DynamicLibrary true MultiByte - v142 + v143 DynamicLibrary true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 DynamicLibrary false true MultiByte - v142 + v143 @@ -852,10 +852,22 @@ + + + + + + + + + + + + @@ -872,6 +884,14 @@ + + + + + + + + @@ -880,6 +900,18 @@ + + + + + + + + + + + + @@ -888,14 +920,34 @@ + + + + + + + + + + + + + + + + + + + + @@ -904,6 +956,14 @@ + + + + + + + + @@ -940,6 +1000,14 @@ + + + + + + + + diff --git a/zUtilities/zUtilities.vcxproj.filters b/zUtilities/zUtilities.vcxproj.filters index 61b825b..258c769 100644 --- a/zUtilities/zUtilities.vcxproj.filters +++ b/zUtilities/zUtilities.vcxproj.filters @@ -235,6 +235,21 @@ {73fb9875-d712-4448-bc8b-4e3db8d224e2} + + {1a1d4b3f-f152-4f65-a537-f4f4cb926484} + + + {f5a6fe54-5837-452a-8b39-b2eea83b3d9f} + + + {35e89ac9-bfa9-44ec-aff5-6dc4ea3d4bef} + + + {0ac56923-5c8c-490c-9e49-20bf92031a95} + + + {ad1d68b4-22dc-4e58-914f-444545260f86} + @@ -2802,6 +2817,9 @@ Plugin\Workspace\Misc + + Plugin\Workspace\Misc + Plugin\Workspace\Misc @@ -2814,7 +2832,7 @@ Plugin\Workspace\Features - + Plugin\Workspace\Features @@ -2850,6 +2868,54 @@ Plugin\Workspace\Features\DebugHelper + + Plugin\Workspace\Features\PlayerStatus + + + Plugin\Workspace\Features\PlayerStatus + + + Plugin\Workspace\Features\PlayerStatus\StatusBar + + + Plugin\Workspace\Features\PlayerStatus\StatusBar + + + Plugin\Workspace\Misc + + + Plugin\Workspace\Features\IconInfo + + + Plugin\Workspace\Features\IconInfo + + + Plugin\Workspace\Features\Dialogue + + + Plugin\Workspace\Misc + + + Plugin\Workspace\Features\Inventory + + + Plugin\Workspace\Features\LogBook + + + Plugin\Workspace\Features\LogBook + + + Plugin\Workspace\Misc + + + Plugin\Workspace\Misc + + + Plugin\Workspace\Misc + + + Plugin\Workspace\Misc +