diff --git a/CMakePresets.json b/CMakePresets.json index 2f1e644..da373be 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -24,7 +24,7 @@ "cacheVariables": { "BUILD_SHARED_LIBS": "OFF", "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", - "DEFAULT_OUTPUT_DIR": "C:/Program Files (x86)/Steam/steamapps/common/Half-Life/cstrike/addons/amxmodx/modules" + "DEFAULT_OUTPUT_DIR": "C:\\Users\\fl0wer\\Desktop\\hlds_win\\cstrike\\addons\\amxmodx\\modules" } }, { diff --git a/README.md b/README.md index 2ac4799..d3b1383 100644 --- a/README.md +++ b/README.md @@ -3,43 +3,31 @@ ## What is this? ReZombie is a modification for the Counter-Strike game based on the original Zombie Plague modification using modern technologies and deeper integration over the game library. -## Goals of the project -* Develop a modification architecture from scratch with the experience of previous years. -* Minimum dependencies between plugins. -* Extended API for plugins and minimum boilerplate code coverage. - -## Requirements -ReHLDS, ReGameDLL, Metamod-r (or Metamod-P), AMX Mod X, ReAPI. -* Tip: Recommend using the latest versions. - -## How can I help the project? -Just install it on your game server and report problems you faced. - -## Acknowledgments -Thanks to projects: ReGameDLL_CS, AMX Mod X, ReAPI
-Thanks to humans: wellasgood, Nvoymax, Alex, DANDY, steelzzz, Droads, Nordic Warrior, kostikovkirill, CaHTuK, Bodom, DimaS, bristol, wopox1337, PurposeLess and others.
- Unlimited Player Classes & Sub-Classes
Weapons System (a wrapper for custom weapon based on default weapon) for weapons, knives and grenades.
Advanced Knives System for custom melee and knives
-Grenade System (easy way to createEntities your own grenades)
+Grenade System (easy way to create your own grenades)
## Вопрос - ответ Вопрос: Неправильно работают хитбоксы (например: не попадает в голову, одинаковый урон).
Ответ: https://developer.valvesoftware.com/wiki/$hbox -## Цвета -Возможное использование -> CSSColorParser::parse(" rgba (255, 128, 12, 0.5)"); - Color [ 255, 128, 12, 0.5 ] -> CSSColorParser::parse("#fff"); - Color [ 255, 255, 255, 1 ] -> CSSColorParser::parse("#ff0011"); - Color [ 255, 0, 17, 1 ] -> CSSColorParser::parse("slateblue"); - Color [ 106, 90, 205, 1 ] -> CSSColorParser::parse("blah"); - Color [ 0, 0, 0, 1 ] -> CSSColorParser::parse("ffffff"); - Color [ 0, 0, 0, 1 ] \ No newline at end of file +### Система цветов +Для AMXX API возможно использовать следующие шаблоны значений цветов:\ +Цвета можно указывать следующими методами: +- Шестнадцатеричные цвета: `#fff`, `#ff0011` +- RGB цвета: `rgb(255, 128, 12)` +- RGBA цвета: `rgba(255, 128, 12, 1.0)`, `rgba(255, 128, 12, 100%)` + +Будут интерпретированы как массив значений { 255, 128, 12, 255 } + +**Предопределенные названия цветов**: можно указать конкретное имя цвета из списка [140 названий цветов](https://www.w3schools.com/cssref/css_colors.php)\ +**Создание своих цветов цвета**: создать свой цвет и использовать его в других плагинах.
+create_color("название цвета", "значение цвета") + +_Примечание_: alpha будет интерпретироваться как alpha, brightness или игнорироваться там, где нет возможности указать это значение. + +## Acknowledgments +Thanks to projects: ReGameDLL_CS, AMX Mod X, ReAPI
+Thanks to humans: wellasgood, Nvoymax, Alex, DANDY, steelzzz, Droads, Nordic Warrior, kostikovkirill, CaHTuK, Bodom, DimaS, bristol, wopox1337, PurposeLess and others.
diff --git a/extra/addons/amxmodx/scripting/.vscode/build.sh b/extra/addons/amxmodx/scripting/.vscode/build.sh new file mode 100644 index 0000000..e12677d --- /dev/null +++ b/extra/addons/amxmodx/scripting/.vscode/build.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +# Define color codes +RED="\e[31m" +ORANGE="\e[33m" +GREEN="\e[32m" +WHITE_BG="\e[47m" +RESET="\e[0m" + +# Define directories +destinationDir="C:/Users/fl0wer/Desktop/hlds_win/cstrike/addons/amxmodx" +# destinationDir="D:/Games/SteamLibrary/steamapps/common/Half-Life/cstrike/addons/amxmodx" +scriptingDir="$destinationDir/scripting" +srcDir="$PWD" + +# Function to print colored messages +print_color() { + local color="$1" + local message="$2" + echo -e "${color}${message}${RESET}" +} + +# Function to compile a .sma file +compile_sma() { + local smaFile="$1" + local outputPluginDir="$2" + + pluginName=$(basename "${smaFile%.sma}") + relativeDir=$(dirname "${smaFile#$srcDir}") + + outputPlugin="$outputPluginDir/${pluginName}.amxx" + + # Create the output plugin directory if it doesn't exist + mkdir -p "$outputPluginDir" + + # Print the name of the .sma file with white background + # print_color $WHITE_BG " - Compiling: $(basename $smaFile)" + + # Get the last modification time of the output plugin file + lastModTime=$(stat -c %Y "$smaFile" 2>/dev/null) + now=$(date +%s) + diff=$((now-lastModTime)) + + # Check if the file exists and its last modification time is within the last minute + if ! [ -f $outputPlugin ] || [ $diff -lt 60 ]; then + # Compile the .sma file and capture its output, excluding the lines with version and copyright info + compile_output=$("$scriptingDir/amxxpc" \ + "$smaFile" \ + -i"$srcDir" \ + -i"$srcDir/include" \ + -i"$srcDir/rezombie" \ + -o"$outputPlugin" 2>&1 | grep -vE "AMX Mod X Compiler|Copyright|Could not locate output file") + + # Check if there are any errors or warnings in the compile output + if echo "$compile_output" | grep -qi "error"; then + error_lines=$(echo "$compile_output" | grep -i "error" | sed 's/.*scripting\///') + warning_lines=$(echo "$compile_output" | grep -i "warning" | sed 's/.*scripting\///') + print_color $RED "❌ $error_lines" + if [ -n "$warning_lines" ]; then + print_color $ORANGE "⚠️ $warning_lines" + fi + elif echo "$compile_output" | grep -qi "warning"; then + warning_lines=$(echo "$compile_output" | grep -i "warning" | sed 's/.*scripting\///') + print_color $ORANGE "⚠️ $warning_lines" + else + print_color $GREEN " ✅ Compiled: $(basename $smaFile)" + fi + # else + # Skip processing the file if it has been modified within the last minute + # print_color $ORANGE "Skipped: $(basename $smaFile) (not modified $((diff / 60)) min)" + fi +} + +# Find and compile all .sma files in the source directory and its subdirectories +find "$srcDir" -name "*.sma" -type f | while read smaFile; do + relativeDir=$(dirname "${smaFile#$srcDir}") + outputPluginDir="$destinationDir/plugins$relativeDir" + compile_sma "$smaFile" "$outputPluginDir" +done + +#echo "" + +# Copy directories without confirmation with green messages +#print_color $GREEN " - Copying configs..." +#cp -rf "$srcDir/../configs"/* "$destinationDir/configs" +#print_color $GREEN " - Copying data..." +#cp -rf "$srcDir/../data"/* "$destinationDir/data" \ No newline at end of file diff --git a/extra/addons/amxmodx/scripting/.vscode/tasks.json b/extra/addons/amxmodx/scripting/.vscode/tasks.json new file mode 100644 index 0000000..79839c6 --- /dev/null +++ b/extra/addons/amxmodx/scripting/.vscode/tasks.json @@ -0,0 +1,40 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build AMX Mod X Plugins", + "type": "shell", + "command": "bash", + "args": [".vscode/build.sh"], + "group": { + "kind": "build", + "isDefault": true + } + } + ], + "presentation": { + "echo": false, + "reveal": "always", + "focus": false, + "panel": "dedicated", + "showReuseMessage": false, + "clear": true + }, + "problemMatcher": { + "fileLocation": "autoDetect", + "owner": "problem", + "pattern": { + // Group 1 - filename (absolute path for filename) + // Group 2 - beginning line + // Group 3 - ending line (optional) + // Group 4 - error | warning (severity) + // Group 5 - message + "regexp": "(.+?)\\((\\d+)(?:\\s--\\s(\\d+))?\\)\\s:\\s(warning|error)\\s\\d+:\\s(.*)", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } +} diff --git a/extra/addons/amxmodx/scripting/core/rz_languages_helper.sma b/extra/addons/amxmodx/scripting/core/rz_languages_helper.sma deleted file mode 100644 index a2274f0..0000000 --- a/extra/addons/amxmodx/scripting/core/rz_languages_helper.sma +++ /dev/null @@ -1,52 +0,0 @@ -#include - -new const LANG_SUBFOLDER[] = "rezombie" - -new Array:g_langFiles - -public plugin_precache() { - g_langFiles = ArrayCreate(PLATFORM_MAX_PATH) -} - -public plugin_init() { - register_plugin("[RZ] Languages Helper", "1.0.0", "fl0wer") - - // Lazy loading because AmxModX can't call register_dictionary, get_langsnum and get_lang on plugin_precache - loadLanguages() -} - -loadLanguages() { - new dataFolder[PLATFORM_MAX_PATH] - get_localinfo("amxx_datadir", dataFolder, charsmax(dataFolder)) - new filesCount = ArraySize(g_langFiles) - new langFile[PLATFORM_MAX_PATH] - new langsCount = get_langsnum() - new langNameShort[3] - for (new i = 0; i < filesCount; ++i) { - ArrayGetString(g_langFiles, i, langFile, charsmax(langFile)) - for (new lang = 0; lang < langsCount; ++lang) { - get_lang(lang, langNameShort) - if (!file_exists(fmt("%s/lang/%s/%s/%s", dataFolder, LANG_SUBFOLDER, langNameShort, langFile))) { - continue - } - register_dictionary(fmt("%s/%s/%s", LANG_SUBFOLDER, langNameShort, langFile)) - } - } - ArrayClear(g_langFiles) -} - -public plugin_natives() { - register_native("rz_add_translate", "@native_add_translate") -} - -@native_add_translate(plugin, argc) { - enum { arg_lang_file = 1 } - new langFile[32] - get_string(arg_lang_file, langFile, charsmax(langFile)) - if (!langFile[0]) { - return false - } - static const LANG_FILE_EXTENSION[] = "txt" - ArrayPushString(g_langFiles, fmt("%s.%s", langFile, LANG_FILE_EXTENSION)) - return true -} diff --git a/extra/addons/amxmodx/scripting/include/rezombie.inc b/extra/addons/amxmodx/scripting/include/rezombie.inc new file mode 100644 index 0000000..bd3ba6e --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie.inc @@ -0,0 +1,85 @@ +#if defined _rezombie_included + #endinput +#endif + +#define _rezombie_included + +#pragma reqlib rezombie +#if !defined AMXMODX_NOAUTOLOAD + #pragma loadlib rezombie +#endif + +/** + * Constants + */ +new const any:null = 0; +stock const TO_ALL = 0; + +stock const MAX_HANDLE_LENGTH = 32; +stock const MAX_LANGKEY_LENGTH = 32; +stock const MAX_REFERENCE_LENGTH = 32; +stock const MAX_PLAYER_MODEL_LENGTH = 32; +stock const MAX_RESOURCE_PATH = 64; + +stock const DEFAULT_FOV = 90; + +stock const WEAPON_NOCLIP = -1; + +/** + * Game teams + */ +enum Team { + TEAM_ZOMBIE = 1, + TEAM_HUMAN = 2, + TEAM_SPECTATOR, +}; + +/** + * Forward return types + */ +enum { + RZ_CONTINUE, + RZ_SUPERCEDE, + RZ_BREAK, +}; + +enum HudChannel { + TIMER_CHANNEL, + PLAYER_INFO_CHANNEL, + DAMAGER_CHANNEL, + NOTICE_CHANNEL, +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +stock const CBasePlayerWeapon_Members:m_Weapon_iRemainingShotsFired = m_Weapon_iFamasShotsFired +stock const CBasePlayerWeapon_Members:m_Weapon_flNextRemainingShoot = m_Weapon_flFamasShoot + +stock register_commands(const commands[][], const handler[], const size = sizeof(commands)) { + for (new command = 0; command < size; ++command) { + register_clcmd(commands[command], handler) + } +} + +stock precache_sounds(const sounds[][], const size = sizeof(sounds)) { + for (new sound = 0; sound < size; ++sound) { + precache_sound(sounds[sound]) + } +} + +/** +* You have to create len and text[] variables before call add_formatex +*/ +#define add_formatex(%0) len += formatex(text[len], charsmax(text) - len, %0) + +// bad with string +#define bind_convar(%0,%1,%2) bind_pcvar_%0(create_cvar(%2), %1) diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_common.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_common.inc new file mode 100644 index 0000000..7ccb5f3 --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_common.inc @@ -0,0 +1,91 @@ +#if defined _rz_common_included + #endinput +#endif + +#define _rz_common_included + +native register_translate(const translateFile[]); + +native bool:add_translate(const name[]); + +const MAX_PLURAL_LENGTH = 64; + +enum Plurals { + Plural_One, + Plural_Few, + Plural_Many, +}; + +stock quantity(number, const plurals[Plurals][MAX_PLURAL_LENGTH]) { + new Plurals:plural = Plural_Many; + if (number > 10 && ((number % 100) / 10) == 1) { + plural = Plural_Many; + } else { + switch (number % 10) { + case 1: plural = Plural_One; + case 2, 3, 4: plural = Plural_Few; + } + } + return plurals[plural]; +} + +native create_color(const name[], const color[]) + +enum LogLevel { + Log_Fatal = 100, + Log_Error = 200, + Log_Warning = 300, + Log_Info = 400, +}; + +native log(LogLevel:logLevel, const message[], any:...); + +native print_to_chat(player, sender, const text[], any:...) + +stock Array:get_alive_players(&alivesCount = 0) { + static Array:AlivesArray = Invalid_Array; + if (AlivesArray == Invalid_Array) { + AlivesArray = ArrayCreate(1); + } else { + ArrayClear(AlivesArray); + } + for (new player = 1; player <= MaxClients; ++player) { + if (!is_user_alive(player)) { + continue; + } + ArrayPushCell(AlivesArray, player); + } + alivesCount = ArraySize(AlivesArray); + return AlivesArray; +} + +enum PlayersCountFlags (<<=1) { + PlayersCount_Alive = (1<<0), + PlayersCount_Dead, + PlayersCount_Humans, + PlayersCount_Zombies, +}; + +native get_players_count(PlayersCountFlags:flags = any:0); + +native play_ambience_sound(const soundPath[]); +native stop_ambience_sound(); + +native bool:is_extra_exists(ExtraType:type, const key[]); + +native any:get_extra(ExtraType:type, const key[], any:...); +native set_extra(ExtraType:type, const key[], any:...); + +stock get_extra_string(const key[]) { + new value[MAX_EXTRA_VAR_LENGTH]; + get_extra(extra_string, key, value, charsmax(value)); + return value; +} + +native send_death_msg(receiver, attacker, victim, const weaponName[], bool:isHeadshot = false); +native send_score_attrib(receiver, player, attribFlags = 0); +native send_item_pickup(receiver, const className[]); +native send_money(receiver, amount, bool:isTrackChange = true); +native send_status_icon(receiver, status, const sprite[], const color[] = ""); + +native message_beam_follow(entity, spriteIndex, life, lineWidth, const color[]); diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_currency.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_currency.inc new file mode 100644 index 0000000..350f5da --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_currency.inc @@ -0,0 +1,42 @@ +#if defined _rz_currency_included + #endinput +#endif + +#define _rz_currency_included + +native Currency:create_currency( + const currencyName[], + const getFunction[], + const setFunction[], + const formatFunction[] +); + +const MAX_CURRENCY_FORMAT_LENGTH = 32; + +native [MAX_CURRENCY_FORMAT_LENGTH]format_currency(Currency:currency, amount, bool:isShort = true); + +native Currency:find_currency(const handle[]); + +native add_player_currency(player, Currency:currency, addAmount, const reason[] = "", any:...); + +stock Currency:checkCurrencyExists(const handle[]) { + new Currency:currency = find_currency(handle); + if (currency == null) { + log(Log_Warning, "Currency '%s' not found", handle); + } + return currency; +} + + +native Price:create_price(Currency:currency, amount); + +native any:get_price_var(Price:price, const var[], ...); +native set_price_var(Price:price, const var[], any:...); + +const MAX_PRICE_VAR_LENGTH = 32; + +stock get_price_var_string(Price:price, const var[]) { + new value[MAX_PRICE_VAR_LENGTH]; + get_price_var(price, var, value, charsmax(value)); + return value; +} diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_game_rules.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_game_rules.inc new file mode 100644 index 0000000..99a72db --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_game_rules.inc @@ -0,0 +1,58 @@ +#if defined _rz_game_rules_included + #endinput +#endif + +#define _rz_game_rules_included + +enum GameState { + game_state_warmup, + game_state_need_players, + game_state_playing, + game_state_game_over, // it is round state? + game_state_intermission, // to be deleted +}; + +forward game_state_changed(GameState:oldGameState, GameState:newGameState); + +enum RoundState { + round_state_none, + round_state_prepare, + round_state_playing, + round_state_terminate, +}; + +forward round_state_changed(RoundState:oldRoundState, RoundState:newRoundState); + +forward @round_timer(timer); + +native any:get_game_var(const var[], any:...); +native set_game_var(const var[], any:...); + +forward @round_start(bool:isReset); + +enum EndRoundEvent { // Status? + end_round_none, + end_round_warmup_end, + end_round_game_commence, + end_round_game_restart, + end_round_game_over, + end_round_humans_win, + end_round_zombies_win, + end_round_end_draw, +}; + +forward @round_end(EndRoundEvent:endRoundEvent, GameMode:gameMode, delay); + +/* + +boss support? + +forward rz_next_map() { + return nextMap +} + +forward rz_player_impulse(player, impulse) + +forward rz_weapon_primary_attack(impulse, weapon, player, clip?) + +*/ diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_items.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_items.inc new file mode 100644 index 0000000..c7118ab --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_items.inc @@ -0,0 +1,37 @@ +#if defined _rz_items_included + #endinput +#endif + +#define _rz_items_included + +native Item:create_item(const handle[], const giveForward[]); + +native any:get_item_var(Item:item, const var[], ...); +native set_item_var(Item:item, const var[], any:...); + +const MAX_ITEM_VAR_LENGTH = 32; + +stock get_item_var_string(Item:item, const var[]) { + new value[MAX_ITEM_VAR_LENGTH]; + get_item_var(item, var, value, charsmax(value)); + return value; +} + +native items_count(); +native Item:items_begin(); +native Item:items_end(); +native Item:find_item(const handle[]); + +native bool:give_item(player, const handle[]); +native bool:give_item_by_id(player, Item:item); + +forward @give_item_pre(player, Item:item); +forward @give_item_post(player, Item:item); + +stock Item:checkItemExists(const handle[]) { + new Item:item = find_item(handle); + if (item == null) { + log(Log_Warning, "Item '%s' not found", handle); + } + return item; +} diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_map.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_map.inc new file mode 100644 index 0000000..cb1208f --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_map.inc @@ -0,0 +1,42 @@ +#if defined _rz_map_included + #endinput +#endif + +#define _rz_map_included + +enum WeatherType { + weather_type_none, + weather_type_rain, + weather_type_snow, +}; + +native any:get_env_var(const var[], ...); +native set_env_var(const var[], any:...); + +native any:get_override_env_var(const var[], ...); +native set_override_env_var(const var[], any:...); + +native reset_env(); + +native Fog:create_fog(const color[], densityPercentage); + +native any:get_fog_var(Fog:fog, const var[], ...); +native set_fog_var(Fog:fog, const var[], any:...); + +native any:get_map_camera_var(player, const var[], ...); +native set_map_camera_var(player, const var[], any:...); + +native map_cameras_count(); +native MapCamera:map_cameras_begin(); +native MapCamera:map_cameras_end(); + +native bool:is_map_extra_exists(ExtraType:type, const key[]); + +native any:get_map_extra(ExtraType:type, const key[], any:...); +native set_map_extra(ExtraType:type, const key[], any:...); + +stock get_map_extra_string(const key[]) { + new value[MAX_EXTRA_VAR_LENGTH]; + get_map_extra(extra_string, key, value, charsmax(value)); + return value; +} diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_menu.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_menu.inc new file mode 100644 index 0000000..e534fa6 --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_menu.inc @@ -0,0 +1,175 @@ +#if defined _rz_menu_included + #endinput +#endif + +#define _rz_menu_included + +const MAX_MENU_PAGE_ITEMS = 7; +const MAX_MENU_ID_LENGTH = 64; + +const Page:START_PAGE = any:0; + +enum { + MenuKey_Back = 7, + MenuKey_Next = 8, + MenuKey_Exit = 9, +}; + +stock MenuKeys; +stock MenuLength; +stock MenuText[MAX_MENU_LENGTH]; +stock MenuId[MAX_MENU_ID_LENGTH]; +stock bool:MenuIsSinglePage; +stock MenuMaxPages; +stock MenuItemsCount; +stock MenuItem; +stock MenuStart; +stock MenuEnd; +stock Page:MenuPage[MAX_PLAYERS + 1]; +stock MenuItemsPerPage[MAX_PLAYERS + 1]; +stock Array:MenuItems[MAX_PLAYERS + 1]; + +#define createMenu(%0,%1) MenuText[0] = 0; MenuLength = 0; MenuKeys = 0; \ + copy(MenuId, charsmax(MenuId), %1); \ + ArrayClear(MenuItems[%0]); \ + SetGlobalTransTarget(%0) + +#define addText(%0) MenuLength += formatex(MenuText[MenuLength], charsmax(MenuText) - MenuLength, %0) + +#define addItem(%0,%1) addText(%1); MenuKeys |= %0 + +#define showMenu(%0) show_menu(%0, MenuKeys, MenuText, -1, MenuId) + +#define closeMenu(%0) show_menu(%0, 0, NULL_STRING, 0) + +stock Menu:register_menu(const id[], const handler[], const keys = 1023) { + new Menu:menu = any:register_menuid(id); + register_menucmd(any:menu, keys, handler); + return menu; +} + +stock Menu:get_opened_menu(player) { + new Menu:menu, keys; + get_user_menu(player, any:menu, keys); + return menu; +} + + + + +stock const ITEMS_SINGLE_PAGE_COUNT = 9 +stock const ITEMS_MULTI_PAGE_COUNT = 7 + +stock createMenuItems(Array:items) { + for (new player = 1; player <= MaxClients; ++player) { + MenuItems[player] = ArrayClone(items) + } + ArrayDestroy(items) +} + +stock calculateMenuPage(player, Page:page, itemsPerPage = MAX_MENU_PAGE_ITEMS) { + MenuItem = 0 + MenuItemsPerPage[player] = itemsPerPage + MenuIsSinglePage = MenuItemsCount <= itemsPerPage + if (MenuIsSinglePage) { + MenuStart = 0 + MenuEnd = MenuItemsCount + MenuPage[player] = START_PAGE + } else { + new i = min(_:page * itemsPerPage, MenuItemsCount) + MenuStart = i - (i % itemsPerPage) + MenuEnd = min(MenuStart + itemsPerPage, MenuItemsCount) + MenuMaxPages = ((MenuItemsCount - 1) / itemsPerPage) + 1 + MenuPage[player] = any:(MenuStart / itemsPerPage) + } +} + +/* +stock calculateMenuPage(itemsCount, page, &menuItem, &start, &end, &maxPages, &isSinglePage) { + menuItem = 0 + isSinglePage = itemsCount <= ITEMS_SINGLE_PAGE_COUNT + if (isSinglePage) { + start = 0 + end = itemsCount + return 0 + } else { + new itemsPerPage = ITEMS_MULTI_PAGE_COUNT + new i = min(page * itemsPerPage, itemsCount) + start = i - (i % itemsPerPage) + end = min(start + itemsPerPage, itemsCount) + maxPages = ((itemsCount - 1) / itemsPerPage) + 1 + return start / itemsPerPage + } +} +*/ + +stock addMenuEmptyItem(const itemCapacity[] = "^n") { + addText("%s\d%l", itemCapacity, "EMPTY") +} + +stock addMenuCloseItem() { + addItem(MENU_KEY_0, "^n\r[0] \w%l", "CLOSE") +} + +stock addMenuSpacingAfterItems(player, const itemCapacity[] = "^n") { + if (MenuItemsCount > MenuItemsPerPage[player]) { + for (new i = MenuItem; i <= MenuItemsPerPage[player]; ++i) { + addText(itemCapacity) + } + } +} + +stock addMenuNavigation(player) { + if (MenuItemsCount > MenuItemsPerPage[player]) { + /*if (page) { + addItem(MENU_KEY_8, "^n\r[8] \w%l", "BACK") + } else { + addText("^n\d[8] %l", "BACK") + } + if (MenuEnd < MenuItemsCount) { + addItem(MENU_KEY_9, "^n\r[9] \w%l", "NEXT") + } else { + addText("^n\d[9] %l", "NEXT") + }*/ + addText("^n") + if (MenuPage[player]) { + addItem(MENU_KEY_8, "\r[8] \w«") + } else { + addText("\d[8] «") + } + addText(" \y%d/%d ", _:MenuPage[player] + 1, MenuMaxPages) + if (MenuEnd < MenuItemsCount) { + addItem(MENU_KEY_9, "\w» \r[9]") + } else { + addText("\d» [9]") + } + } + addText("^n") + addMenuCloseItem() +} + +/* +stock addMenuNavigation(itemsCount, page, menuItem, end, &keys, text[MAX_MENU_LENGTH], &len) { + if (itemsCount > ITEMS_SINGLE_PAGE_COUNT) { + for (new i = menuItem; i < ITEMS_MULTI_PAGE_COUNT; ++i) { + addText("^n") + } + if (end < itemsCount) { + addItem(MENU_KEY_8, "^n\r[8] \w%l", "NEXT") + } else { + addText("^n\d[8] %l", "NEXT") + } + if (page) { + addItem(MENU_KEY_9, "^n\r[9] \w%l", "BACK") + } else { + addText("^n\d[9] %l", "BACK") + } + addText("^n") + } + addItem(MENU_KEY_0, "^n\r[0] \w%l", "CLOSE") +} +*/ + +stock any:getMenuItem(player, key) { + return ArrayGetCell(MenuItems[player], _:MenuPage[player] * MenuItemsPerPage[player] + key) +} diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_models.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_models.inc new file mode 100644 index 0000000..5e192d0 --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_models.inc @@ -0,0 +1,12 @@ +#if defined _rz_models_included + #endinput +#endif + +#define _rz_models_included + +native Model:create_model(const path[], body = 0, skin = 0, const handle[] = ""); + +native get_model_var(Model:model, const var[], ...); +native set_model_var(Model:model, const var[], any:...); + +native models_pack_add_model(ModelsPack:modelsPack, Model:model); diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_modes.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_modes.inc new file mode 100644 index 0000000..b645511 --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_modes.inc @@ -0,0 +1,45 @@ +#if defined _rz_game_modes_included + #endinput +#endif + +#define _rz_game_modes_included + +enum RespawnType { + Respawn_Off, + Respawn_ToHumansTeam, + Respawn_ToZombiesTeam, + Respawn_Balance, +}; + +native Mode:create_mode(const handle[], const luanchForward[], bool:isSupportTarget = false); + +native any:get_mode_var(Mode:mode, const var[], any:...); +native set_mode_var(Mode:mode, const var[], any:...); + +const MAX_MODE_VAR_LENGTH = 64; + +stock get_mode_var_string(Mode:mode, const var[]) { + new value[MAX_MODE_VAR_LENGTH]; + get_mode_var(mode, var, value, charsmax(value)); + return value; +} + +native mode_add_ambience_sound(Mode:mode, const path[]); +native [PLATFORM_MAX_PATH]mode_random_ambience_sound(Mode:mode); + +native modes_count(); +native Mode:modes_begin(); +native Mode:modes_end(); +native Mode:find_mode(const handle[]); + +native launch_mode(Mode:mode, target = 0); + +forward @mode_start(Mode:mode, target); + +stock Mode:checkModeExists(const handle[]) { + new Mode:mode = find_mode(handle); + if (mode == null) { + log(Log_Warning, "Mode '%s' not found", handle); + } + return mode; +} diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_player.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_player.inc new file mode 100644 index 0000000..1bed42f --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_player.inc @@ -0,0 +1,247 @@ +#if defined _rz_player_included + #endinput +#endif + +#define _rz_player_included + +const MAX_EXTRA_VAR_LENGTH = 32; + +enum ExtraType { + extra_int, + extra_float, + extra_string, +}; + +native update_player_info(player); + +forward @player_joining(player); +forward @player_joined(player); + + +native any:get_preview_var(player, const var[], ...); +native set_preview_var(player, const var[], any:...); + + +native any:get_player_var(player, const var[], any:...); +native set_player_var(player, const var[], any:...); + +native bool:is_player_extra_exists(player, ExtraType:type, const key[]); + +native any:get_player_extra(player, ExtraType:type, const key[], any:...); +native set_player_extra(player, ExtraType:type, const key[], any:...); + +stock get_player_extra_string(player, const key[]) { + new value[MAX_EXTRA_VAR_LENGTH]; + get_player_extra(player, extra_string, key, value, charsmax(value)); + return value; +} + +native bool:is_valid_attacker(attacker, player, bool:self = false); + +native change_player_class(player, Class:class, attacker = 0); +native change_player_subclass(player, Subclass:subclass); +native change_player_flashlight(player, Flashlight:flashlight); +native change_player_night_vision(player, NightVision:nightVision); + +native player_joined(player); + +native respawn_player(player, timer = 0); + +native bool:freeze_player(player, Float:freezeTime, bool:inAir = true); +native bool:is_player_freeze(player); + +enum LongJumpState { + long_jump_none, + long_jump_cooldown, + long_jump_ready, +}; + +native bool:give_long_jump(player, force = 560, height = 300, cooldown = 0); +native bool:remove_long_jump(player); + +native any:get_long_jump_var(player, const var[], any:...); +native set_long_jump_var(player, const var[], any:...); + +forward @give_long_jump(player); +forward @long_jump_state(player, LongJumpState:longJumpState); +forward @long_jump_activated(player); +forward @long_jump_cooldown_timer(player, timer); + +native any:get_jumps_var(player, const var[], any:...); +native set_jumps_var(player, const var[], any:...); + +forward @player_jump(player, count); + +forward @player_give_default_items(player, Class:class); + + +native Class:create_class(const handle[], const Team:team); + +native any:get_class_var(Class:class, const var[], ...); +native set_class_var(Class:class, const var[], any:...); + +const MAX_CLASS_VAR_LENGTH = 32; + +stock get_class_var_string(Class:class, const var[]) { + new value[MAX_CLASS_VAR_LENGTH]; + get_class_var(class, var, value, charsmax(value)); + return value; +} + +native bool:is_class_extra_exists(Class:class, ExtraType:type, const key[]); + +native any:get_class_extra(Class:class, ExtraType:type, const key[], any:...); +native set_class_extra(Class:class, ExtraType:type, const key[], any:...); + +stock get_class_extra_string(Class:class, const key[]) { + new value[MAX_EXTRA_VAR_LENGTH]; + get_class_extra(class, extra_string, key, value, charsmax(value)); + return value; +} + +native classes_count(); +native Class:classes_begin(); +native Class:classes_end(); +native Class:find_class(const handle[]); + +forward @change_class_pre(player, Class:class, attacker); +forward @change_class_post(player, Class:class, attacker); + +stock Class:checkClassExists(const handle[]) { + new Class:class = find_class(handle); + if (class == null) { + log(Log_Warning, "Class '%s' not found", handle); + } + return class; +} + + +native Subclass:create_subclass(const handle[], Class:class); + +native any:get_subclass_var(Subclass:subclass, const var[], ...); +native set_subclass_var(Subclass:subclass, const var[], any:...); + +const MAX_SUBCLASS_VAR_LENGTH = 32; + +stock get_subclass_var_string(Subclass:sublcass, const var[]) { + new value[MAX_SUBCLASS_VAR_LENGTH]; + get_subclass_var(sublcass, var, value, charsmax(value)); + return value; +} + +native subclasses_count(); +native Subclass:subclasses_begin(); +native Subclass:subclasses_end(); +native Subclass:find_subclass(const handle[]); + +forward @change_subclass_pre(player, Subclass:class, attacker); +forward @change_subclass_post(player, Subclass:class, attacker); + + +native Props:create_props(const handle[]); + +native any:get_props_var(Props:props, const var[], ...); +native set_props_var(Props:props, const var[], any:...); + +// check 120 maybe it 180? +native Flashlight:create_flashlight(const color[], size, fullDrainTime = 120, fullChargeTime = 20); + +native any:get_flashlight_var(Flashlight:flashlight, const var[], any:...); +native set_flashlight_var(Flashlight:flashlight, const var[], any:...); + +const MAX_FLASHLIGHT_VAR_LENGTH = 32; + +stock get_flashlight_var_string(Flashlight:flashlight, const var[]) { + new value[MAX_FLASHLIGHT_VAR_LENGTH]; + get_flashlight_var(flashlight, var, value, charsmax(value)); + return value; +} + + +native NightVision:create_night_vision(const color[], Fog:fog = any:0); + +native any:get_night_vision_var(NightVision:nightVision, const var[], any:...); +native set_night_vision_var(NightVision:nightVision, const var[], any:...); + +const MAX_NIGHT_VISION_VAR_LENGTH = 32; + +stock get_night_vision_var_string(NightVision:nightVision, const var[]) { + new value[MAX_NIGHT_VISION_VAR_LENGTH]; + get_night_vision_var(nightVision, var, value, charsmax(value)); + return value; +} + +enum HudParams { + Float:hud_x, + Float:hud_y, + hud_color1[32], + hud_color2[32], + hud_effect, + Float:hud_fade_in_time, + Float:hud_hold_time, + Float:hud_fade_out_time, + Float:hud_fx_time, +}; + +native send_hud(player, HudChannel:channel, hudParams[HudParams], const text[], any:...); + +enum LargeHudParams { + Float:large_hud_x, + Float:large_hud_y, + large_hud_color[32], + large_hud_effect, + Float:large_hud_fade_in_time, + Float:large_hud_hold_time, + Float:large_hud_fade_out_time, + Float:large_hud_fx_time, +}; + +native send_large_hud(player, hudParams[LargeHudParams], const text[], any:...); + +native send_weapon_anim(player, animNumber, body = 0); + +stock hud_params( + Float:x = -1.0, + Float:y = -1.0, + const color1[] = "", + const color2[] = "", + effect = 0, + Float:fadeInTime = 0.0, + Float:holdTime = 0.0, + Float:fadeOutTime = 0.0, + Float:fxTime = 0.0 +) { + new hudParams[HudParams] + hudParams[hud_x] = x + hudParams[hud_y] = y + copy(hudParams[hud_color1], charsmax(hudParams[hud_color1]), color1) + copy(hudParams[hud_color2], charsmax(hudParams[hud_color2]), color2) + hudParams[hud_effect] = effect + hudParams[hud_fade_in_time] = fadeInTime + hudParams[hud_hold_time] = holdTime + hudParams[hud_fade_out_time] = fadeOutTime + hudParams[hud_fx_time] = fxTime + return hudParams +} + +stock large_hud_params( + Float:x = -1.0, + Float:y = -1.0, + const color[] = "", + effect = 0, + Float:fadeInTime = 0.0, + Float:fadeOutTime = 0.0, + Float:holdTime = 0.0, + Float:fxTime = 0.0 +) { + new hudParams[LargeHudParams] + hudParams[large_hud_x] = x + hudParams[large_hud_y] = y + copy(hudParams[large_hud_color], charsmax(hudParams[large_hud_color]), color) + hudParams[large_hud_effect] = effect + hudParams[large_hud_fade_in_time] = fadeInTime + hudParams[large_hud_hold_time] = holdTime + hudParams[large_hud_fade_out_time] = fadeOutTime + hudParams[large_hud_fx_time] = fxTime + return hudParams +} diff --git a/extra/addons/amxmodx/scripting/include/rezombie/rz_weapons.inc b/extra/addons/amxmodx/scripting/include/rezombie/rz_weapons.inc new file mode 100644 index 0000000..e79f316 --- /dev/null +++ b/extra/addons/amxmodx/scripting/include/rezombie/rz_weapons.inc @@ -0,0 +1,197 @@ +#if defined _rz_weapons_included + #endinput +#endif + +#define _rz_weapons_included + +// Maybe for Ham's hooks +stock const WEAPON_PLACEHOLDER[] = "weapon_ak47"; + +enum WeaponType +{ + weapon_type_primary, + weapon_type_secondary, + weapon_type_melee, + weapon_type_grenade, + weapon_type_extra, +}; + +native Weapon:create_weapon(const handle[], WeaponType:weaponType); + +native any:get_weapon_var(Weapon:weapon, const var[], ...); +native set_weapon_var(Weapon:weapon, const var[], any:...); + +const MAX_WEAPON_VAR_LENGTH = 32; + +stock get_weapon_var_string(Weapon:weapon, const var[]) { + new value[MAX_WEAPON_VAR_LENGTH]; + get_weapon_var(weapon, var, value, charsmax(value)); + return value; +} + +native bool:is_weapon_extra_exists(Weapon:weapon, ExtraType:type, const key[]); + +native any:get_weapon_extra(Weapon:weapon, ExtraType:type, const key[], any:...); +native set_weapon_extra(Weapon:weapon, ExtraType:type, const key[], any:...); + +stock get_weapon_extra_string(Weapon:weapon, const key[]) { + new value[MAX_EXTRA_VAR_LENGTH]; + get_weapon_extra(weapon, extra_string, key, value, charsmax(value)); + return value; +} + +native weapons_count(); +native Weapon:weapons_begin(); +native Weapon:weapons_end(); +native Weapon:find_weapon(const handle[]); + +enum CrosshairSize { + CrosshairSize_None, + CrosshairSize_Size3, + CrosshairSize_Size4, + CrosshairSize_Size5, + CrosshairSize_Size6, + CrosshairSize_Size7, + CrosshairSize_Size8, + CrosshairSize_Size9, +}; + +enum RzGiveType { + GT_Append, + GT_Replace, + GT_DropAndReplace +}; + +native Weapon:is_weapon(weapon); + +// add bpammo last arg (def -1) +native give_weapon(player, const handle[], RzGiveType:giveType = GT_DropAndReplace); +native give_weapon_by_id(player, Weapon:weapon, RzGiveType:giveType = GT_DropAndReplace); + +native bool:weapon_default_deploy(weapon, player, drawAnim, const playerAnim[]); + +native bool:weapon_default_reload(weapon, player, reloadAnim, Float:reloadTime); + +native bool:weapon_default_shotgun_reload( + weapon, + player, + reloadAnim, + reloadStartAnim, + Float:reloadTime, + Float:reloadStartTime, + const reloadSound1[] = "", + const reloadSound2[] = "" +); + +native weapon_kick_back( + weapon, + player, + Float:upBase, + Float:lateralBase, + Float:upModifier, + Float:lateralModifier, + Float:upMax, + Float:lateralMax, + directionChange +); + +// return grenade +native weapon_throw_grenade(weapon, player, Float:origin[3], Float:velocity[3], Float:actionTime); + +enum MeleeAttackResult { + melee_attack_miss, + melee_attack_hit, + melee_attack_hit_wall, +}; + +native MeleeAttackResult:melee_default_attack(weapon, player, damage, distance, Float:backDamageMultiplier = 0.0); + +enum MeleeAttackType { + melee_attack_primary, + melee_attack_secondary, +}; + +forward @melee_attack_pre(player, MeleeAttackType:type); +forward @melee_attack_post(player, MeleeAttackType:type, MeleeAttackResult:result); + +enum MeleeSoundType { + melee_sound_deploy, + melee_sound_hit, + melee_sound_slash, + melee_sound_stab, + melee_sound_hit_wall, +}; + +native melee_add_sound(Weapon:melee, MeleeSoundType:type, const path[]); + +stock Weapon:checkWeaponExists(const handle[]) { + new Weapon:weapon = find_weapon(handle); + if (weapon == null) { + log(Log_Warning, "Weapon '%s' not found", handle); + } + return weapon; +} + +stock getAimingAngle(player, Float:aimingAngle[3]) { + new Float:viewAngle[3] + new Float:punchAngle[3] + get_entvar(player, var_v_angle, viewAngle) + get_entvar(player, var_punchangle, punchAngle) + for (new i = 0; i < sizeof(viewAngle); ++i) { + aimingAngle[i] = viewAngle[i] + punchAngle[i] + } +} + +stock getGunPositionAndAiming(player, Float:src[3], Float:aiming[3]) { + new Float:viewAngle[3] + getAimingAngle(player, viewAngle) + engfunc(EngFunc_MakeVectors, viewAngle) + ExecuteHamB(Ham_Player_GetGunPosition, player, src) + global_get(glb_v_forward, aiming) +} +/* +stock playFireSound(player, const fireSound[]) { + rh_emit_sound2(player, 0, CHAN_WEAPON, fireSound, VOL_NORM, ATTN_NORM, 0, 94 + random_num(0, 15)) +} +*/ +stock play_weapon_sound(player, const sound[]) { + rh_emit_sound2(player, 0, CHAN_WEAPON, sound) +} + +stock play_random_weapon_sound(player, const sounds[][], size = sizeof(sounds)) { + rh_emit_sound2(player, 0, CHAN_WEAPON, sounds[random_num(0, size - 1)]) +} + +stock bool:isEmptyFire(weapon, clip, bool:isShotgun = false) { + if (clip <= 0) { + if (isShotgun) { + if (!get_member(weapon, m_Weapon_fInSpecialReload)) { + ExecuteHamB(Ham_Weapon_PlayEmptySound, weapon) + } + ExecuteHamB(Ham_Weapon_Reload, weapon) + } else { + if (get_member(weapon, m_Weapon_fFireOnEmpty)) { + ExecuteHamB(Ham_Weapon_PlayEmptySound, weapon) + set_member(weapon, m_Weapon_flNextPrimaryAttack, 0.2) + } + } + return true + } + return false +} + +stock Float:playerVelocityLength2d(player) { + new Float:velocity[3] + get_entvar(player, var_velocity, velocity) + velocity[2] = 0.0 + return vector_length(velocity) +} + +stock modifyVelocityByScalar(entity, Float:scalar) { + new Float:velocity[3] + get_entvar(entity, var_velocity, velocity) + for (new i = 0; i < sizeof(velocity); ++i) { + velocity[i] *= scalar + } + set_entvar(entity, var_velocity, velocity) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/addons/damager.sma b/extra/addons/amxmodx/scripting/rezombie/addons/damager.sma new file mode 100644 index 0000000..9100172 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/addons/damager.sma @@ -0,0 +1,220 @@ +#include +#include +#include + +// add total damage for player per death + +new Float:TotalDamage[MAX_PLAYERS + 1][MAX_PLAYERS + 1] +new TotalHits[MAX_PLAYERS + 1][MAX_PLAYERS + 1] + +new Float:LastDamageTime[MAX_PLAYERS + 1] +new Float:VictimsDamage[MAX_PLAYERS + 1] +new VictimsCount[MAX_PLAYERS + 1] + +public plugin_precache() { + register_plugin("Damager", "1.0.0", "fl0wer") + RegisterHookChain(RG_CBasePlayer_Spawn, "@Player_Spawn_Post", true) + RegisterHookChain(RG_CBasePlayer_TakeDamage, "@Player_TakeDamage_Post", true) +} + +public plugin_init() { + register_clcmd("say hud", "@hud") +} + +@hud(player) { + client_print(0, print_chat, "HUD") + new hudParams[HudParams] + hudParams = hud_params( + .color1 = "cyan", + .color2 = "red", + .effect = 2, + .fadeInTime = 0.01, + .holdTime = 15.0, + .fadeOutTime = 0.01, + .fxTime = 0.1 + ) + /*new range[] = { 0x0370, 0x03FF }; + //new range[] = { 0x2600, 0x26FF }; + new maxChars = range[1] - range[0]; + + new text[512] + for (new i = 0; i < maxChars + 1; ++i) { + add(text, charsmax(text), fmt("%c", range[0] + i)) + }*/ + send_hud( + player, + DAMAGER_CHANNEL, + hudParams, + fmt("Text: [ᐄᐂ⇗⬈⬀🡽🢅🡥🡭🡵🡽🢅߽]") + ) + client_print(0, print_chat, "HUD END") +} + +@Player_Spawn_Post(player) { + if (!is_user_alive(player)) { + return + } + for (new target = 1; target <= MaxClients; ++target) { + TotalDamage[target][player] = 0.0 + TotalHits[target][player] = 0 + } +} + +// Can attack another player (attacker, player) + +@Player_TakeDamage_Post(player, inflictor, attacker, Float:damage, damageType) { + if (player == attacker || !is_user_connected(attacker)) { + return + } + if (!rg_is_player_can_takedamage(player, attacker)) { + return + } + TotalHits[attacker][player]++ + new Float:health = get_entvar(player, var_health) + new Float:realDamage + if (is_user_alive(player)) { + realDamage = damage + } else { + realDamage = damage + health + } + new healthInt = max(0, floatround(health, floatround_floor)) + //client_print(0, print_chat, "HP: %.2f DMG: %.2f to %.2f", health, damage, realDamage) + //if (damageInt < 1.0) { + // return + //} + TotalDamage[attacker][player] += realDamage + new Float:time = get_gametime() + if (LastDamageTime[attacker] == time) { + VictimsCount[attacker]++ + VictimsDamage[attacker] += damage + } else { + VictimsCount[attacker] = 1 + VictimsDamage[attacker] = damage + } + LastDamageTime[attacker] = time + new victimsDamageInt = floatround(VictimsDamage[attacker], floatround_floor) + new hudParams[HudParams] + hudParams = hud_params( + .color1 = getHudColorByHitBoxGroup(get_member(player, m_LastHitGroup)), + .color2 = getHudColorByHitBoxGroup(get_member(player, m_LastHitGroup)), + .effect = 2, + .fadeInTime = 0.01, + .holdTime = 1.5, + .fadeOutTime = 0.01, + .fxTime = 0.1 + ) + if (VictimsCount[attacker] <= 1) { + showOnceDamage(attacker, hudParams, realDamage, TotalDamage[attacker][player], player, healthInt) + } else { + showMultiDamage(attacker, hudParams, victimsDamageInt, VictimsCount[attacker]) + } + for (new target = 1; target <= MaxClients; ++target) { + if (target == attacker) { + continue + } + if (!is_user_connected(target)) { + continue + } + if (get_entvar(target, var_iuser1) != OBS_IN_EYE) { + continue + } + if (get_member(target, m_hObserverTarget) != attacker) { + continue + } + if (VictimsCount[attacker] <= 1) { + showOnceDamage(target, hudParams, realDamage, TotalDamage[attacker][player], player, healthInt) + } else { + showMultiDamage(target, hudParams, victimsDamageInt, VictimsCount[attacker]) + } + } + /*if (!is_user_alive(player)) { + new activeItem = get_member(attacker, m_pActiveItem) + if (is_nullent(activeItem)) { + return + } + // check null, add grenade + // multi kills + new Weapon:weapon = get_entvar(activeItem, var_impulse) + new intTotalDamage = floatround(TotalDamage[attacker][player], floatround_floor) + new formatKill[128] + formatex( + formatKill, charsmax(formatKill), + "+1 фраг за раунд^n^nВы убили %s с %L^nУрон: %d (%d попаданий)", + name, LANG_PLAYER, get_weapon_var_string(weapon, "name"), + intTotalDamage, TotalHits[attacker][player] + ) + set_hudmessage(0, 200, 200, 0.6, 0.6, 2, 0.1, 5.0, 0.01, 0.01) + ShowSyncHudMsg(attacker, g_hudSync_KillInfo, formatKill) + }*/ +} + +showOnceDamage(player, hudParams[HudParams], Float:damage, Float:totalDamage, victim, health) { + new damageInt = floatround(damage, floatround_floor) + new totalDamageInt = floatround(totalDamage, floatround_floor) + new damageText[64] + if (damage == totalDamage) { + formatex(damageText, charsmax(damageText), "Σ=%d DMG", damageInt, totalDamageInt) + } else { + formatex(damageText, charsmax(damageText), "%d DMG (Σ=%d)", damageInt, totalDamageInt) + } + if (health) { + send_hud( + player, + DAMAGER_CHANNEL, + hudParams, + "^n^n^nx^n^n%s^n%n: %d HP", + damageText, + victim, health + ) + } else { + send_hud( + player, + DAMAGER_CHANNEL, + hudParams, + "^n^n^nx^n^n%s^nYou killed %n", + damageText, + victim + ) + } +} + +showMultiDamage(player, hudParams[HudParams], victimsDamage, victimsCount) { + send_hud( + player, + DAMAGER_CHANNEL, + hudParams, + "^n^n^n\ /^n^n/ \^n^n%d DMG^n%d victims", + victimsDamage, + victimsCount + ) +} + + // need invert colors effects + + // change hp to sprite + // change colors + + // change colors by 100 200 300 dmg + + // ammo pcaks delta [%d/%d] +getHudColorByHitBoxGroup(HitBoxGroup:hitBoxGroup) { + new color[32] + switch (hitBoxGroup) { + case HITGROUP_GENERIC: { + color = "green" + } + case HITGROUP_HEAD: { + color = "red" + } + case HITGROUP_CHEST, HITGROUP_STOMACH: { + color = "yellow" + } + case HITGROUP_LEFTARM, + HITGROUP_RIGHTARM, + HITGROUP_LEFTLEG, + HITGROUP_RIGHTLEG: { + color = "green" + } + } + return color +} diff --git a/extra/addons/amxmodx/scripting/rezombie/addons/human_weapons.sma b/extra/addons/amxmodx/scripting/rezombie/addons/human_weapons.sma new file mode 100644 index 0000000..0171396 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/addons/human_weapons.sma @@ -0,0 +1,238 @@ +#include +#include + +/** + * Start settings + */ + +new const PRIMARY_WEAPONS[][] = { + "csgo_p90", + "csgo_m4a1s", + "csgo_ak47", + "csgo_awp", + "csgo_negev", +} + +new const SECONDARY_WEAPONS[][] = { + "csgo_glock", + "csgo_usp", + "csgo_deagle", +} + +/** + * End of settings + */ + +new const PRIMARY_MENU_ID[] = "PrimaryWeapon" +new bool:IsRememberPrimary[MAX_PLAYERS + 1] +new Weapon:PrimaryWeapon[MAX_PLAYERS + 1] +new Array:Primaries + +new const SECONDARY_MENU_ID[] = "SecondaryWeapon" +new bool:IsRememberSecondary[MAX_PLAYERS + 1] +new Weapon:SecondaryWeapon[MAX_PLAYERS + 1] +new Array:Secondaries + +new Class:HumanClass + +/* + 1. M4A1-S + 2. M4A4 + 3. AK-47 + 4. MAC-10 + 5. MP7 + 6. MP9 + 7. MP5-SD + 8. PP-Bizon + 9. P90 + 10. UMP-45 + + 1. Glock + 2. USP-S + 3. + 4. + 5. Desert Eagle + 6. Dual Berettas +*/ + +public plugin_precache() { + register_plugin("Human Weapons", "1.0.0", "fl0wer") +} + +public plugin_init() { + HumanClass = checkClassExists("human") + register_menu(PRIMARY_MENU_ID, "@Menu_Primary") + register_menu(SECONDARY_MENU_ID, "@Menu_Secondary") + register_clcmd("radio3", "@Command_Weapons") // to be deleted + parsePrimary() + parseSecondary() + if (!ArraySize(Primaries) && !ArraySize(Secondaries)) { + log(Log_Error, "No weapons found") + } +} + +public client_putinserver(player) { + if (is_user_bot(player)) { + IsRememberPrimary[player] = true + IsRememberSecondary[player] = true + PrimaryWeapon[player] = ArrayGetCell(Primaries, 0) + SecondaryWeapon[player] = ArrayGetCell(Secondaries, 0) + } else { + IsRememberPrimary[player] = false + IsRememberSecondary[player] = false + PrimaryWeapon[player] = null + SecondaryWeapon[player] = null + } +} + +@player_give_default_items(player, Class:class) { + if (class != HumanClass) { + return + } + new bool:primaryOpened + if (IsRememberPrimary[player] && PrimaryWeapon[player] != null) { + give_weapon_by_id(player, PrimaryWeapon[player]) + } else { + primaryOpened = openPrimaryMenu(player) + } + if (IsRememberSecondary[player] && SecondaryWeapon[player] != null) { + give_weapon_by_id(player, SecondaryWeapon[player]) + } else if (!primaryOpened) { + openSecondaryMenu(player) + } +} + +@Command_Weapons(player) { + openPrimaryMenu(player) + return PLUGIN_HANDLED +} + +bool:openPrimaryMenu(player) { + new weaponsCount = ArraySize(Primaries) + if (!weaponsCount) { + return false + } + createMenu(player, PRIMARY_MENU_ID) + //addText("Выберите оружие^n") + addText("Выберите^n\yоружие^n\wиз CS:GO^n") + for (new i = 0; i < weaponsCount; ++i) { + new Weapon:weapon = ArrayGetCell(Primaries, i) + addItem((1< +#include +#include + +new ModelIndex_ShockWave + +public plugin_precache() { + register_plugin("Jumps", "1.0", "fl0wer") + ModelIndex_ShockWave = precache_model("sprites/shockwave.spr") +} + +public plugin_init() { + register_clcmd("radio1", "@p") +} + +@p(player) { + @player_jump(player, 0) +} + +@player_jump(player, count) { + if (!count) { + update_player_info(player) + return + } + new Float:velocity[3] + get_entvar(player, var_velocity, velocity) + velocity[2] = 268.3281573 + set_entvar(player, var_velocity, velocity) + rg_set_animation(player, PLAYER_JUMP) + update_player_info(player) + jumpEffects(player) +} + +jumpEffects(player) { + new Float:origin[3] + new Float:mins[3] + new Float:axis[3] + get_entvar(player, var_origin, origin) + get_entvar(player, var_mins, mins) + origin[2] += mins[2] + axis = origin + axis[2] += 48.0 + message_begin_f(MSG_PVS, SVC_TEMPENTITY, origin) + TE_BeamDisk(origin, axis, ModelIndex_ShockWave, 0, 0, 4, 255, 0, { 200, 0, 0 }, 200, 0) +} + +stock TE_BeamDisk(Float:position[3], Float:axis[3], spriteIndex, startingFrame, frameRate, life, lineWidth, noiseAmplitude, color[3], brightness, scrollSpeed) +{ + write_byte(TE_BEAMDISK); + write_coord_f(position[0]); // position.x + write_coord_f(position[1]); // position.y + write_coord_f(position[2]); // position.z + write_coord_f(axis[0]); // axis.x + write_coord_f(axis[1]); // axis.y + write_coord_f(axis[2]); // axis.z + write_short(spriteIndex); // sprite index + write_byte(startingFrame); // starting frame + write_byte(frameRate); // frame rate in 0.1's + write_byte(life); // life in 0.1's + write_byte(lineWidth); // line width in 0.1's + write_byte(noiseAmplitude); // noise amplitude in 0.01's + write_byte(color[0]); // red + write_byte(color[1]); // green + write_byte(color[2]); // blue + write_byte(brightness); // brightness + write_byte(scrollSpeed); // scroll speed in 0.1's + message_end(); +} diff --git a/extra/addons/amxmodx/scripting/rezombie/addons/long_jump.sma b/extra/addons/amxmodx/scripting/rezombie/addons/long_jump.sma new file mode 100644 index 0000000..852e44c --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/addons/long_jump.sma @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +new const ITEM_LONG_JUMP_SPRITE[] = "item_longjump" +new const STATUS_ICON_SPRITE[] = "item_longjump" +new const ACTIVATE_SOUND[] = "zombie_plague/boss_shokwave.wav" + +new ModelIndex_Trail + +public plugin_precache() { + register_plugin("Long Jump", "1.0", "fl0wer") + precache_sound(ACTIVATE_SOUND) + ModelIndex_Trail = precache_model("sprites/laserbeam.spr") +} + +@give_long_jump(player) { + send_item_pickup(player, ITEM_LONG_JUMP_SPRITE) +} + +@long_jump_state(player, LongJumpState:longJumpState) { + switch (longJumpState) { + case long_jump_none: { + send_status_icon(player, 0, STATUS_ICON_SPRITE) + } + case long_jump_cooldown: { + send_status_icon(player, 1, STATUS_ICON_SPRITE, "grey") + } + case long_jump_ready: { + send_status_icon(player, 1, STATUS_ICON_SPRITE, "rgb(255, 160, 0)") + } + } +} + +@long_jump_activated(player) { + new Float:force = float(get_long_jump_var(player, "force")) + new Float:viewAngle[3] + new Float:velocity[3] + new Float:viewForward[3] + get_entvar(player, var_v_angle, viewAngle) + engfunc(EngFunc_MakeVectors, viewAngle) + global_get(glb_v_forward, viewForward) + velocity[0] = viewForward[0] * force + velocity[1] = viewForward[1] * force + velocity[2] = viewForward[2] * float(get_long_jump_var(player, "height")) + set_entvar(player, var_velocity, velocity) + new cooldown = get_long_jump_var(player, "cooldown") + if (cooldown != 0) { + set_long_jump_var(player, "cooldown_timer", cooldown) + set_long_jump_var(player, "next_state_time", get_gametime() + 1.0) + set_long_jump_var(player, "state", long_jump_cooldown) + } + longJumpEffects(player) +} + +@long_jump_cooldown_timer(player, timer) { + update_player_info(player) +} + +longJumpEffects(player) { + //new Float:origin[3] + new Float:punchAngle[3] + //get_entvar(player, var_origin, origin) + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] = -5.0 + set_entvar(player, var_punchangle, punchAngle) + rg_set_animation(player, PLAYER_SUPERJUMP) + rh_emit_sound2(player, 0, CHAN_ITEM, ACTIVATE_SOUND) + message_begin_f(MSG_PVS, SVC_TEMPENTITY, entity_origin(player)) + message_beam_follow(player, ModelIndex_Trail, 1, 5, "yellow") +} + +Float:entity_origin(entity) { + new Float:origin[3] + get_entvar(entity, var_origin, origin) + return origin +} diff --git a/extra/addons/amxmodx/scripting/rezombie/addons/player_blood.sma b/extra/addons/amxmodx/scripting/rezombie/addons/player_blood.sma new file mode 100644 index 0000000..62e1082 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/addons/player_blood.sma @@ -0,0 +1,215 @@ +#include +#include +#include +#include + +new ModelIndex_BloodSpray +new ModelIndex_BloodDrop + +new Array:BloodDecals + +public plugin_precache() { + register_plugin("[RZ] Player Blood", "1.0", "fl0wer") + ModelIndex_BloodSpray = precache_model("sprites/bloodspray.spr") + ModelIndex_BloodDrop = precache_model("sprites/blood.spr") + BloodDecals = ArrayCreate(1) + for (new i = 1; i <= 6; ++i) { + ArrayPushCell(BloodDecals, engfunc(EngFunc_DecalIndex, fmt("{blood%d", i))) + } +} + +public plugin_init() { + RegisterHookChain(RG_CBasePlayer_TraceAttack, "@Player_TraceAttack_Pre", false) +} + +@Player_TraceAttack_Pre(player, attacker, Float:damage, Float:direction[3], trace, bitsDamageType) { + new bool:shouldBleed = true + new bool:shouldSpark = false + if (is_user_connected(attacker)) { + //if (CSPlayer()->GetProtectionState() == CCSPlayer::ProtectionSt_Active) { + // return + //} + if (!rg_is_player_can_takedamage(player, attacker)) { + shouldBleed = false + } + } + if (Float:get_entvar(player, var_takedamage) == DAMAGE_NO) { + return HC_SUPERCEDE + } + new HitBoxGroup:hitBoxGroup = any:get_tr2(trace, TR_iHitgroup) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + set_member(player, m_LastHitGroup, hitBoxGroup) + switch (hitBoxGroup) { + case HITGROUP_HEAD: { + if (get_member(player, m_iKevlar) == ARMOR_VESTHELM) { + shouldBleed = false + shouldSpark = true + } + damage *= 4.0 + if (shouldBleed) { + punchAngle[0] = floatmax(damage * -0.5, -12.0) + punchAngle[2] = floatclamp(damage * random_float(-1.0, 1.0), -9.0, 9.0) + set_entvar(player, var_punchangle, punchAngle) + } + } + case HITGROUP_CHEST: { + damage *= 1.0 + if (get_member(player, m_iKevlar) != ARMOR_NONE) { + shouldBleed = false + } else if (shouldBleed) { + punchAngle[0] = floatmax(damage * -0.1, -4.0) + set_entvar(player, var_punchangle, punchAngle) + } + } + case HITGROUP_STOMACH: { + damage *= 1.25 + if (get_member(player, m_iKevlar) != ARMOR_NONE) { + shouldBleed = false + } else if (shouldBleed) { + punchAngle[0] = floatmax(damage * -0.1, -4.0) + set_entvar(player, var_punchangle, punchAngle) + } + } + case HITGROUP_LEFTARM, HITGROUP_RIGHTARM: { + if (get_member(player, m_iKevlar) != ARMOR_NONE) { + shouldBleed = false + } + } + case HITGROUP_LEFTLEG, HITGROUP_RIGHTLEG: { + damage *= 0.75 + } + } + new bloodColor = ExecuteHamB(Ham_BloodColor, player) + new Float:endPosition[3] + new Float:planeNormal[3] + get_tr2(trace, TR_vecEndPos, endPosition) + get_tr2(trace, TR_vecPlaneNormal, planeNormal) + if (shouldBleed) { + //BloodSplat(endPosition, direction, hitBoxGroup, damage * 5.0) + SpawnBlood(endPosition, bloodColor, damage) + TraceBleed(player, bloodColor, damage, endPosition, direction, bitsDamageType) + } else if (hitBoxGroup == HITGROUP_HEAD && shouldSpark) { + message_begin_f(MSG_PVS, SVC_TEMPENTITY, endPosition) + write_byte(TE_STREAK_SPLASH) + write_coord_f(endPosition[0]) + write_coord_f(endPosition[1]) + write_coord_f(endPosition[2]) + write_coord_f(planeNormal[0]) + write_coord_f(planeNormal[1]) + write_coord_f(planeNormal[2]) + write_byte(5) // color + write_short(22) // count + write_short(25) // base speed + write_short(65) // random velocity + message_end() + } + rg_multidmg_add(attacker, player, damage, bitsDamageType) + return HC_SUPERCEDE +} + +SpawnBlood(Float:position[3], bloodColor, Float:damage) { + new amount = floatround(damage, floatround_floor) + if (bloodColor == DONT_BLEED || !amount) { + return + } + amount *= 2 + if (amount > 255) { + amount = 255 + } + message_begin_f(MSG_PVS, SVC_TEMPENTITY, position) + TE_BloodSprite(position, ModelIndex_BloodSpray, ModelIndex_BloodDrop, bloodColor, clamp(amount / 10, 3, 16)) +} + +TraceBleed(player, bloodColor, Float:damage, Float:src[3], Float:direction[3], bitsDamageType) { + if (bloodColor == DONT_BLEED || !damage) { + return + } + if (!(bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR))) { + return + } + new count + new Float:noise + if (damage < 10.0) { + count = 1 + noise = 0.1 + } else if (damage < 25.0) { + count = 2 + noise = 0.2 + } else { + count = 4 + noise = 0.3 + } + new Float:bloodDirection[3] + new Float:end[3] + new Float:fraction + for (new i = 0; i < count; ++i) { + for (new j = 0; j < 3; ++j) { + bloodDirection[j] = direction[j] * -1.0 + bloodDirection[j] += random_float(-noise, noise) + end[j] = src[j] + bloodDirection[j] * -172.0 + } + engfunc(EngFunc_TraceLine, src, end, IGNORE_MONSTERS, player, 0) + get_tr2(0, TR_flFraction, fraction) + if (fraction >= 1.0) { + continue + } + //if (random_num(0, 2)) { + // continue + //} + UTIL_DecalTrace(0, ArrayGetCell(BloodDecals, random_num(0, ArraySize(BloodDecals) - 1))) + } +} + +UTIL_DecalTrace(trace, decal) { + if (decal < 0) { + return + } + new Float:fraction + get_tr2(trace, TR_flFraction, fraction) + if (fraction >= 1.0) { + return + } + new entityId + new entity = get_tr2(trace, TR_pHit) + if (entity != NULLENT && !ExecuteHamB(Ham_IsBSPModel, entity)) { + entityId = entity + } + new message = TE_DECAL + if (entityId) { + if (decal > 255) { + message = TE_DECALHIGH + decal -= 256 + } + } else { + message = TE_WORLDDECAL + if (decal > 255) { + message = TE_WORLDDECALHIGH + decal -= 256 + } + } + new Float:endPosition[3] + get_tr2(trace, TR_vecEndPos, endPosition) + message_begin(MSG_BROADCAST, SVC_TEMPENTITY) + write_byte(message) + write_coord_f(endPosition[0]) + write_coord_f(endPosition[1]) + write_coord_f(endPosition[2]) + write_byte(decal) + if (entityId) { + write_short(entityId) + } + message_end() +} + +TE_BloodSprite(Float:position[3], sprite1Index, sprite2Index, color, scale) { + write_byte(TE_BLOODSPRITE) + write_coord_f(position[0]) + write_coord_f(position[1]) + write_coord_f(position[2]) + write_short(sprite1Index) + write_short(sprite2Index) + write_byte(color) + write_byte(scale) + message_end() +} diff --git a/extra/addons/amxmodx/scripting/rezombie/addons/player_info.sma b/extra/addons/amxmodx/scripting/rezombie/addons/player_info.sma new file mode 100644 index 0000000..df02063 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/addons/player_info.sma @@ -0,0 +1,319 @@ +#include +#include +#include + +new Float:g_nextHudInfoTime[MAX_PLAYERS + 1] +new Float:g_lastHudInfoTime[MAX_PLAYERS + 1] + +new Float:rz_playerinfo_hud_pos[2] +new rz_playerinfo_hud_hp + +/** + * Start settings + */ + +new const HUMAN_DAMAGE_DELT = 1000 + +/** + * End of settings + */ + +// Human +// Blue screen fade when frag +// Red screen fade when killed + +// extra jumps to jump? + +new const MAX_SCORE_VALUE = 10000 + +new Class:HumanClass +new Float:HumanDamage[MAX_PLAYERS + 1] + +new Class:ZombieClass +new ZombieHits[MAX_PLAYERS + 1] + +new Currency:MoneyCurrency +new Currency:AmmoPacksCurrency + +public plugin_init() { + register_plugin("Addon: Player Info", "1.0.0", "fl0wer") + + register_message(get_user_msgid("Money"), "@Message_Money") + register_message(get_user_msgid("SpecHealth"), "@Message_SpecHealth") + register_message(get_user_msgid("SpecHealth2"), "@Message_SpecHealth2") + + RegisterHookChain(RG_CBasePlayer_Spawn, "@Player_Spawn_Post", true) + //RegisterHookChain(RG_CBasePlayer_TakeDamage, "@Player_TakeDamage_Post", true) + RegisterHookChain(RG_CBasePlayer_Killed, "@Player_Killed_Post", true) + RegisterHookChain(RG_CBasePlayer_UpdateClientData, "@Player_UpdateClientData_Post", true) + + bind_convar(float, rz_playerinfo_hud_pos[0], "rz_playerinfo_hud_x", "-1.0", _, "", true, -1.0, true, 1.0) + bind_convar(float, rz_playerinfo_hud_pos[1], "rz_playerinfo_hud_y", "0.9", _, "", true, -1.0, true, 1.0) + bind_convar(num, rz_playerinfo_hud_hp, "rz_playerinfo_hud_hp", "1", _, "", true, 0.0, true, 1.0) + + register_message(get_user_msgid("ScoreInfo"), "@Message_ScoreInfo") + RegisterHookChain(RG_CBasePlayer_TakeDamage, "@Player_TakeDamage_Post", true) + + HumanClass = find_class("human") + ZombieClass = find_class("zombie") + + MoneyCurrency = find_currency("money") + AmmoPacksCurrency = find_currency("ammo_packs") + + register_clcmd("say /st", "@s") + //register_message(get_user_msgid("ScreenFade"), "@Message_ScreenFade") +} + +@Message_ScreenFade() { + return PLUGIN_HANDLED +} + +@s(player) { + new text[196] + //formatex(text, charsmax(text), "1 %c1: %p2\n2 %h: %i3%%")//, player, floatround(get_entvar(player, var_health), floatround_floor)) + message_begin(MSG_ONE, get_user_msgid("StatusText"), _, player) + write_byte(0) + write_string("1 %p2^n2 [%i3 HP]") + message_end() + + message_begin(MSG_ONE, get_user_msgid("StatusValue"), _, player) + write_byte(1) + write_short(2) + message_end() + + message_begin(MSG_ONE, get_user_msgid("StatusValue"), _, player) + write_byte(2) + write_short(1) + message_end() + + message_begin(MSG_ONE, get_user_msgid("StatusValue"), _, player) + write_byte(3) + write_short(1) + message_end() +} + +public client_putinserver(player) { + g_nextHudInfoTime[player] = 0.0 + HumanDamage[player] = 0.0 + ZombieHits[player] = 0 +} + +public rz_class_change_post(player, attacker, class) { + g_nextHudInfoTime[player] = get_gametime() + 0.1 +} + +public rz_subclass_change_post(player, subclass) { + g_nextHudInfoTime[player] = get_gametime() + 0.1 +} + +@change_class_post(player, Class:class, attacker) { + sendFakeScoreInfoToCatch(player) +} + +@Message_Money(message, dest, player) { + if (get_msg_arg_int(2) == 0) { + return PLUGIN_CONTINUE + } + return PLUGIN_HANDLED +} + +@Message_SpecHealth(message, dest, player) { + new observerTarget = get_member(player, m_hObserverTarget) + new Float:health = get_entvar(observerTarget, var_health) + new Float:maxHealth = get_entvar(observerTarget, var_max_health) + if (health < 0.0) { + health = 0.0 + } + set_msg_arg_int(1, ARG_BYTE, floatround((health / maxHealth) * 100.0)) +} + +@Message_SpecHealth2(message, dest, player) { + new observerTarget = get_msg_arg_int(2) + new Float:health = get_entvar(observerTarget, var_health) + new Float:maxHealth = get_entvar(observerTarget, var_max_health) + set_msg_arg_int(1, ARG_BYTE, floatround((health / maxHealth) * 100.0)) +} + +@Player_Spawn_Post(player) { + if (!is_user_alive(player)) { + return + } + g_nextHudInfoTime[player] = get_gametime() + 0.2 +} +/* +@Player_TakeDamage_Post(player, inflictor, attacker, Float:damage, bitsDamageType) { + if (!rg_is_player_can_takedamage(player, attacker)) { + return + } + if (!is_user_alive(player)) { + return + } + showPlayerInfoHud(player) +} +*/ +@Player_Killed_Post(player, attacker, gib) { + //ClearSyncHud(player, g_hudSync_Info) +} + +@Player_UpdateClientData_Post(player) { + if (!g_nextHudInfoTime[player]) { + return + } + if (!is_user_alive(player)) { + return + } + new Float:time = get_gametime() + if (g_nextHudInfoTime[player] > time) { + return + } + g_nextHudInfoTime[player] = time + 1.0 + showPlayerInfoHud(player) +} + +showPlayerInfoHud(player) { + new Class:class = get_player_var(player, "class") + if (!class) { + return + } + new len + new text[512] + SetGlobalTransTarget(player) + if (rz_playerinfo_hud_hp) { + add_formatex("%l: %d", "HEALTH", get_player_var(player, "health")) + } + //if (rz_main_ammopacks_enabled()) + // add_formatex("[%l: %d]^n", "RZ_AMMOPACKS", get_member(player, m_iAccount)) + new hudColor[MAX_CLASS_VAR_LENGTH] + new Subclass:subclass = get_player_var(player, "subclass", class) + if (subclass) { + add_formatex("^n%l: %l", get_class_var_string(class, "name"), get_subclass_var_string(subclass, "name")) + hudColor = get_subclass_var_string(subclass, "hud_color") + } else { + add_formatex("^n%l: %l", "CLASS", get_class_var_string(class, "name")) + hudColor = get_class_var_string(class, "hud_color") + } + if (class == HumanClass) { + new humanDamageInt = floatround(HumanDamage[player], floatround_floor) + add_formatex( \ + "^nОчки: %d (урон: %d/%d)", \ + getHumanScore(humanDamageInt), \ + humanDamageInt % HUMAN_DAMAGE_DELT, \ + HUMAN_DAMAGE_DELT \ + ) + if (MoneyCurrency) { + add_formatex("^nДеньги: %d", get_player_var(player, "currency", MoneyCurrency)) + } + } else if (class == ZombieClass) { + add_formatex("^nОчки: %d", ZombieHits[player]) + if (AmmoPacksCurrency) { + add_formatex("^nКредиты: %d", get_player_var(player, "currency", AmmoPacksCurrency)) + } + } + new maxJumps = get_jumps_var(player, "maximum") + if (maxJumps > 1) { + add_formatex("^nПрыжков: %d/%d", get_jumps_var(player, "count"), maxJumps) + } else if (maxJumps == -1) { + add_formatex("^nПрыжков: %d/∞", get_jumps_var(player, "count")) + } + switch (get_long_jump_var(player, "state")) { + case long_jump_cooldown: { + add_formatex("^nДлинный прыжок: через %d сек.", get_long_jump_var(player, "cooldown_timer")) + } + case long_jump_ready: { + add_formatex("^nДлинный прыжок: готов") + } + } + send_hud( + player, + PLAYER_INFO_CHANNEL, + hud_params( + rz_playerinfo_hud_pos[0], + rz_playerinfo_hud_pos[1], + hudColor, + hudColor, + .holdTime = 5.1 + ), + text + ) +} + +@Player_TakeDamage_Post(player, inflictor, attacker, Float:damage, damageType) { + //client_print(0, print_chat, "0") + //new bool:isAlive = bool:is_user_alive(player) + //if (!GetHookChainReturn(ATYPE_INTEGER) && isAlive) { + // return + //} + //client_print(0, print_chat, "1") + if (player == attacker || !is_user_connected(attacker)) { + return + } + //client_print(0, print_chat, "2") + //if (!rg_is_player_can_takedamage(player, attacker)) { + // return + //} + //client_print(0, print_chat, "3") + new Class:class = get_player_var(attacker, "class") + if (class == HumanClass) { + //client_print(0, print_chat, "4") + new Float:realDamage + if (is_user_alive(player)) { + realDamage = damage + } else { + realDamage = damage + Float:get_entvar(player, var_health) + } + new Float:oldHumanDamage = HumanDamage[attacker] + HumanDamage[attacker] += realDamage + new realDamageInt = floatround(realDamage, floatround_floor) + add_player_currency(attacker, MoneyCurrency, realDamageInt) + if (HumanDamage[attacker] - oldHumanDamage >= float(HUMAN_DAMAGE_DELT)) { + sendFakeScoreInfoToCatch(attacker) + } + } else if (class == ZombieClass) { + //client_print(0, print_chat, "5") + ZombieHits[attacker]++ + add_player_currency(attacker, AmmoPacksCurrency, 1) + sendFakeScoreInfoToCatch(attacker) + } + //client_print(0, print_chat, "6") +} + +@Message_ScoreInfo(message, dest, receiver) { + new score = 0 + new player = get_msg_arg_int(1) + new Class:class = get_player_var(player, "class") + if (class == HumanClass) { + new humanDamageInt = floatround(HumanDamage[player], floatround_floor) + score = getHumanScore(humanDamageInt) + } else if (class == ZombieClass) { + score = ZombieHits[player] + } + set_msg_arg_int(2, ARG_SHORT, min(score, MAX_SCORE_VALUE)) +} + +getHumanScore(humanDamage) { + return humanDamage / HUMAN_DAMAGE_DELT +} + +sendFakeScoreInfoToCatch(player) { + emessage_begin(MSG_ALL, get_user_msgid("ScoreInfo")) + ewrite_byte(player) + ewrite_short(0) + ewrite_short(get_member(player, m_iDeaths)) + ewrite_short(0) + ewrite_short(get_member(player, m_iTeam)) + emessage_end() +} + +public plugin_natives() { + register_native("update_player_info", "@update_player_info") +} + +@update_player_info(plugin, argc) { + enum { + arg_player = 1 + } + + new player = get_param(arg_player) + showPlayerInfoHud(player) + return true +} diff --git a/extra/addons/amxmodx/scripting/rezombie/addons/round_info.sma b/extra/addons/amxmodx/scripting/rezombie/addons/round_info.sma new file mode 100644 index 0000000..2878d46 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/addons/round_info.sma @@ -0,0 +1,374 @@ +#include +#include +#include +/* +new RGB_WHITE[3] = { 255, 255, 255 } +new RGB_HUMAN[3] = { 0, 50, 255 } +new RGB_ZOMBIE[3] = { 255, 150, 0 } + +new RGBA_WHITE[4] = { 255, 255, 255, 255 } +new RGBA_RED[4] = { 255, 50, 0, 255 } +new RGBA_HUMAN[4] = { 0, 50, 255, 255 } +new RGBA_ZOMBIE[4] = { 255, 150, 0, 255 } +*/ +// 1 vs %d + +// timer dhud? + +new Mode:SurvivorMode +new Mode:NemesisMode +new Mode:SniperMode +new Mode:AssassinMode +new Mode:SwarmMode +new Mode:PlagueMode +new Mode:ArmageddonMode +new Mode:SvaMode +new Class:SurvivorClass +new Class:NemesisClass +new Class:SniperClass +new Class:AssassinClass +new CurrentModeClassTarget + +new Currency:MoneyCurrency +new Currency:AmmoPacksCurrency + +// add reset target + +public plugin_init() { + register_plugin("Round Info", "1.0.0", "fl0wer") + + SurvivorMode = checkModeExists("survivor") + NemesisMode = checkModeExists("nemesis") + SniperMode = checkModeExists("sniper") + AssassinMode = checkModeExists("assassin") + SwarmMode = checkModeExists("swarm") + PlagueMode = checkModeExists("plague") + ArmageddonMode = checkModeExists("armageddon") + SvaMode = checkModeExists("sva") + SurvivorClass = checkClassExists("survivor") + NemesisClass = checkClassExists("nemesis") + SniperClass = checkClassExists("sniper") + AssassinClass = checkClassExists("assassin") + MoneyCurrency = checkCurrencyExists("money") + AmmoPacksCurrency = checkCurrencyExists("ammo_packs") +} + +new const SOUND_WIN_HUMANS[][] = { "ambience/guit1.wav", "ambience/guit1.wav" }; +new const SOUND_WIN_ZOMBIES[][] = { "ambience/guit1.wav", "ambience/guit1.wav", "ambience/guit1.wav" }; + +public plugin_precache() { + precache_sound(SOUND_WIN_HUMANS[0]) + precache_sound(SOUND_WIN_HUMANS[1]) + precache_sound(SOUND_WIN_ZOMBIES[0]) + precache_sound(SOUND_WIN_ZOMBIES[1]) + precache_sound(SOUND_WIN_ZOMBIES[2]) +} + +@game_state_changed(GameState:oldState, GameState:newState) { + server_print("Game STATE: %d %d", oldState, newState) +} + +@round_state_changed(RoundState:oldState, RoundState:newState) { + server_print("Round STATE: %d %d", oldState, newState) + if (newState == round_state_prepare) { + stop_ambience_sound() + } +} + +@mode_start(Mode:mode, target) { + new sound[PLATFORM_MAX_PATH] + sound = mode_random_ambience_sound(mode) + if (sound[0]) { + play_ambience_sound(sound) + } + new Float:holdTime = 5.0 + send_large_hud( + TO_ALL, + large_hud_params(-1.0, 0.2, get_mode_var_string(mode, "color"), .holdTime = holdTime), + "%l", get_mode_var_string(mode, "name") + ) + new descHudParams[HudParams] + descHudParams = hud_params( + .x = -1.0, + .y = 0.24, + .color1 = "white", + .color2 = "white", + .holdTime = holdTime + ) + new noticeMessage[MAX_MODE_VAR_LENGTH] + get_mode_var(mode, "notice_message", noticeMessage, charsmax(noticeMessage)) + if (noticeMessage[0]) { + if (target) { + send_hud(TO_ALL, NOTICE_CHANNEL, descHudParams, "%l", noticeMessage, target) + } else { + send_hud(TO_ALL, NOTICE_CHANNEL, descHudParams, "%l", noticeMessage) + } + } +} + +@round_end(EndRoundEvent:endRoundEvent, GameMode:gameMode, delay) { + new color[32] + new text[128] + for (new player = 1; player <= MaxClients; ++player) { + if (!is_user_connected(player)) { + continue + } + switch (endRoundEvent) { + case end_round_warmup_end: { + color = "white" + text = "Разминка окончена!" + } + case end_round_game_commence: { + color = "white" + text = "Игроки подключились!" + } + case end_round_game_restart: { + color = "white" + text = "Рестарт игры!" + } + case end_round_game_over: { + color = "white" + text = "Игра окончена!" + } + case end_round_humans_win: { + switch (get_player_var(player, "team")) { + case TEAM_HUMAN: { + color = "green" + text = "ROUND_VICTORY" + add_player_currency(player, MoneyCurrency, 2000, "за победу") + } + case TEAM_ZOMBIE: { + color = "red" + text = "ROUND_DEFEAT" + add_player_currency(player, AmmoPacksCurrency, 2, "за поражение") + } + default: { + color = "blue" + text = "ROUND_HUMANS_WIN" + } + } + } + case end_round_zombies_win: { + switch (get_player_var(player, "team")) { + case TEAM_HUMAN: { + color = "red" + text = "ROUND_DEFEAT" + add_player_currency(player, MoneyCurrency, 500, "за поражение") + } + case TEAM_ZOMBIE: { + color = "green" + text = "ROUND_VICTORY" + add_player_currency(player, AmmoPacksCurrency, 5, "за победу") + } + default: { + color = "blue" + text = "ROUND_ZOMBIES_WIN" + } + } + } + case end_round_end_draw: { + } + default: { + continue + } + } + send_large_hud(player, large_hud_params(-1.0, 0.2, color, .holdTime = float(delay)), "%l", text) + } + switch (endRoundEvent) { + case end_round_warmup_end: { + } + case end_round_game_commence: { + } + case end_round_game_restart: { + } + case end_round_game_over: { + } + case end_round_humans_win: { + play_ambience_sound(SOUND_WIN_HUMANS[random(sizeof(SOUND_WIN_HUMANS))]) + } + case end_round_zombies_win: { + play_ambience_sound(SOUND_WIN_ZOMBIES[random(sizeof(SOUND_WIN_ZOMBIES))]) + } + case end_round_end_draw: { + } + } +} + +@round_timer(timer) { + new Float:holdTime = 1.1 + switch (get_game_var("game_state")) { + case game_state_warmup: { + if (timer == 0) { + return + } + if (get_game_var("round_state") != round_state_terminate) { + send_hud( + TO_ALL, + TIMER_CHANNEL, + hud_params(-1.0, 0.02, "white", "white", .holdTime = holdTime), + "РАЗМИНКА %d:%02d", timer / 60, timer % 60 + ) + } else { + send_hud( + TO_ALL, + TIMER_CHANNEL, + hud_params(-1.0, 0.2, "red", "red", .holdTime = holdTime), + "МАТЧ НАЧНЕТСЯ ЧЕРЕЗ %d...", timer + ) + } + } + case game_state_need_players: { + send_hud( + TO_ALL, + TIMER_CHANNEL, + hud_params(-1.0, 0.02, "white", "white", .holdTime = holdTime), + "ОЖИДАНИЕ ИГРОКОВ" + ) + } + case game_state_playing: { +/* + send_hud( + TO_ALL, + TIMER_CHANNEL, + hud_params(-1.0, 0.01, "white", "white", .holdTime = holdTime), + "%02d | %s | %02d^n\ + людей | %02d | %02d | зомби%s", + humansAlive, roundTimer, zombiesAlive, + humansWins, zombiesWins, + modeFormat + ) +*/ + new RoundState:roundState = get_game_var("round_state") + switch (roundState) { + case round_state_prepare: { + send_hud( + TO_ALL, + TIMER_CHANNEL, + hud_params(-1.0, 0.01, "white", "white", .holdTime = holdTime), + "%02d люди | зомби %02d^n\ + людей Ω: %d/%d^n\ + заражения нет", + get_game_var("team_wins", TEAM_HUMAN), get_game_var("team_wins", TEAM_ZOMBIE), + get_players_count(), MaxClients + ) + } + case round_state_playing: { + new humansAlive = get_players_count(PlayersCount_Alive | PlayersCount_Humans) + new zombiesAlive = get_players_count(PlayersCount_Alive | PlayersCount_Zombies) + send_hud( + TO_ALL, + TIMER_CHANNEL, + hud_params(-1.0, 0.01, "white", "white", .holdTime = holdTime), + "%02d люди [ %d:%02d ] зомби %02d^n\ + %02d Ω | Ω %02d^n\ + %s", + get_game_var("team_wins", TEAM_HUMAN), timer / 60, timer % 60, get_game_var("team_wins", TEAM_ZOMBIE), + humansAlive, zombiesAlive, + getModeFormat(get_game_var("mode")) + ) + } + case round_state_terminate: { + send_hud( + TO_ALL, + TIMER_CHANNEL, + hud_params(-1.0, 0.01, "white", "white", .holdTime = holdTime), + "%02d люди | зомби %02d", + get_game_var("team_wins", TEAM_HUMAN), get_game_var("team_wins", TEAM_ZOMBIE) + ) + } + } + + if (roundState == round_state_prepare) { + if (timer) { + client_print(0, print_center, "Заражение начнется через %d сек.", timer) + } else { + client_print(0, print_center, "") + } + } + } + case game_state_game_over: { + send_hud( + TO_ALL, + TIMER_CHANNEL, + hud_params(-1.0, 0.0, "white", "white", .holdTime = holdTime), + "Игра окончена!^nСмена карты через %d сек.^nСледующая карта: $2000$", + timer + ) + } + } +} + +getModeFormat(Mode:mode) { + new modeFormat[MAX_MODE_VAR_LENGTH] + new Class:class + if (mode == SurvivorMode) { + class = SurvivorClass + } else if (mode == NemesisMode) { + class = NemesisClass + } else if (mode == SniperMode) { + class = SniperClass + } else if (mode == AssassinMode) { + class = AssassinClass + } else if (mode == PlagueMode) { + new survivors = getModeTargets(SurvivorClass) + new nemeses = getModeTargets(NemesisClass) + if (survivors || nemeses) { + formatex( + modeFormat, charsmax(modeFormat), + "%L (%d %L, %d %L)", + LANG_PLAYER, get_mode_var_string(mode, "name"), + survivors, LANG_PLAYER, get_class_var_string(SurvivorClass, "name"), + nemeses, LANG_PLAYER, get_class_var_string(NemesisClass, "name") + ) + } + } + if (class) { + if (!CurrentModeClassTarget || !is_user_alive(CurrentModeClassTarget) || get_player_var(CurrentModeClassTarget, "class") != class) { + CurrentModeClassTarget = getModeSingleTarget(class) + } + if (CurrentModeClassTarget) { + formatex( + modeFormat, charsmax(modeFormat), + "%L: %n - %d HP", + LANG_PLAYER, get_class_var_string(class, "name"), CurrentModeClassTarget, get_player_var(CurrentModeClassTarget, "health") + ) + } + } + if (!modeFormat[0] && mode) { + formatex(modeFormat, charsmax(modeFormat), "%L", LANG_PLAYER, get_mode_var_string(mode, "name")) + } + return modeFormat +} + +getModeSingleTarget(Class:class) { + new candidate + new candidatesCount + for (new player = 1; player <= MaxClients; ++player) { + if (!is_user_alive(player)) { + continue + } + if (get_player_var(player, "class") != class) { + continue + } + candidate = player + candidatesCount++ + } + if (candidatesCount != 1) { + return 0 + } + return candidate +} + +getModeTargets(Class:class) { + new candidatesCount + for (new player = 1; player <= MaxClients; ++player) { + if (!is_user_alive(player)) { + continue + } + if (get_player_var(player, "class") != class) { + continue + } + candidatesCount++ + } + return candidatesCount +} diff --git a/extra/addons/amxmodx/scripting/rezombie/addons/weapons_pickup.sma b/extra/addons/amxmodx/scripting/rezombie/addons/weapons_pickup.sma new file mode 100644 index 0000000..a2c90d2 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/addons/weapons_pickup.sma @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include + +new Array:WorldWeapons +new Float:NextPickupHudTime[MAX_PLAYERS + 1] + +public plugin_init() { + register_plugin("Weapons Pickup", "1.0.0", "fl0wer") + WorldWeapons = ArrayCreate(1) + /*RegisterHookChain(RG_CBasePlayer_PreThink, "@Player_PreThink_Post", true) + RegisterHookChain(RG_CBasePlayer_DropPlayerItem, "@Player_DropPlayerItem_Post", true) + RegisterHam(Ham_Touch, WEAPON_PLACEHOLDER, "@Weapon_Touch_Pre", false) + RegisterHam(Ham_StartSneaking, WEAPON_PLACEHOLDER, "@Weapon_OnCreate_Post", true) + RegisterHam(Ham_StopSneaking, WEAPON_PLACEHOLDER, "@Weapon_OnDestroy_Post", true)*/ +} + +@Player_PreThink_Post(player) { + static Float:time + if (!is_user_alive(player)) { + return + } + if (!(get_entvar(player, var_button) & IN_USE) && get_entvar(player, var_oldbuttons) & IN_USE) { + pickupWeapon(player) + return + } + time = get_gametime() + if (NextPickupHudTime[player] > time) { + return + } + NextPickupHudTime[player] = time + 0.2 + showPickupHud(player) +} + +@Player_DropPlayerItem_Post(player, itemName[]) { + new item = GetHookChainReturn(ATYPE_INTEGER) + if (is_nullent(item)) { + return + } + new Float:velocity[3] + new Float:viewAngle[3] + new Float:viewForward[3] + get_entvar(player, var_v_angle, viewAngle) + angle_vector(viewAngle, ANGLEVECTOR_FORWARD, viewForward) + for (new i = 0; i < sizeof(velocity); i++) { + velocity[i] = viewForward[i] * 300.0 + } + velocity[2] += 100.0 + set_entvar(item, var_velocity, velocity) + set_entvar(item, var_avelocity, Float:{ 0.0, -128.0, 0.0 }) + //ArrayPushCell(WorldWeapons, item) + new Weapon:impulse = get_entvar(item, var_impulse) + // set trans + client_print(player, print_center, "Вы выбросили %l", get_weapon_var_string(impulse, "name")) + set_entvar(item, var_fuser1, get_gametime() + 1.5) + //set_hudmessage(255, 255, 255, -1.0, 0.55, 0, 6.0, 2.0, 0.01, 0.01) + //ShowSyncHudMsg(player, g_hudSync_Pickup, "Вы выбросили %s", WEAPON_NAMES[get_member(item, m_iId)]) +} + +@Weapon_Touch_Pre(weapon, other) { + if (!(get_entvar(weapon, var_flags) & FL_ONGROUND)) { + return HAM_IGNORED + } + if (!is_user_alive(other)) { + return HAM_IGNORED + } + if (get_entvar(weapon, var_owner) != other) { + return HAM_IGNORED + } + if (Float:get_entvar(weapon, var_fuser1) < get_gametime()) { + return HAM_IGNORED + } + return HAM_SUPERCEDE +} + +@Weapon_OnCreate_Post(weapon) { + ArrayPushCell(WorldWeapons, weapon) +} + +@Weapon_OnDestroy_Post(weapon) { + new id = ArrayFindValue(WorldWeapons, weapon) + if (id == -1) { + return + } + ArrayDeleteItem(WorldWeapons, id) +} + +showPickupHud(player) { + static item + static itemSlot + static Weapon:weapon + static playerItem + item = findWorldWeaponByView(player) + if (item == -1) { + return + } + weapon = get_entvar(item, var_impulse) + itemSlot = rg_get_iteminfo(item, ItemInfo_iSlot) + static hudParams[HudParams] + hudParams = hud_params(-1.0, 0.55, "white", "white", .holdTime = 0.21) + if (itemSlot != 0 && itemSlot != 1) { + send_hud(player, NOTICE_CHANNEL, hudParams, "%l", get_weapon_var_string(weapon, "name")) + return + } + playerItem = get_member(player, m_rgpPlayerItems, itemSlot) + if (is_nullent(playerItem) || get_entvar(playerItem, var_impulse) == weapon) { + send_hud(player, NOTICE_CHANNEL, hudParams, "%l", get_weapon_var_string(weapon, "name")) + return + } + send_hud(player, NOTICE_CHANNEL, hudParams, "[E] сменить на %l", get_weapon_var_string(weapon, "name")) +} + +pickupWeapon(player) { + static item + static itemSlot + item = findWorldWeaponByView(player) + if (item == -1) { + return + } + itemSlot = rg_get_iteminfo(item, ItemInfo_iSlot) + if (itemSlot != 0 && itemSlot != 1) { + return + } + rg_drop_items_by_slot(player, any:itemSlot) + set_entvar(item, var_flags, get_entvar(item, var_flags) | FL_ONGROUND) + set_entvar(item, var_fuser1, 0.0) + ExecuteHamB(Ham_Touch, item, player) +} + +findWorldWeaponByView(player) { + static i + static item + static weaponsNum + static Float:src[3] + static Float:end[3] + static Float:viewAngle[3] + static Float:punchAngle[3] + static Float:viewForward[3] + ExecuteHamB(Ham_Player_GetGunPosition, player, src) + get_entvar(player, var_v_angle, viewAngle) + get_entvar(player, var_punchangle, punchAngle) + for (i = 0; i < sizeof(viewAngle); i++) { + viewAngle[i] += punchAngle[i] + } + angle_vector(viewAngle, ANGLEVECTOR_FORWARD, viewForward) + for (i = 0; i < sizeof(end); i++) { + end[i] = src[i] + viewForward[i] * 128.0 + } + weaponsNum = ArraySize(WorldWeapons) + for (i = 0; i < weaponsNum; ++i) { + item = ArrayGetCell(WorldWeapons, i) + if (is_nullent(item)) { + continue + } + engfunc(EngFunc_TraceModel, src, end, HULL_POINT, item, 0) + if (get_tr2(0, TR_pHit) != item) { + continue + } + return item + } + return -1 +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/assassin.sma b/extra/addons/amxmodx/scripting/rezombie/classes/assassin.sma new file mode 100644 index 0000000..2f5e496 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/assassin.sma @@ -0,0 +1,25 @@ +#include +#include + +public plugin_precache() { + register_plugin("Class: Assassin", "1.0.0", "fl0wer") + + new Class:class = create_class("assassin", TEAM_ZOMBIE) + + new Props:props = get_class_var(class, "props") + set_class_var(class, "name", "RZ_ASSASSIN") + set_props_var(props, "health", 2000) + set_props_var(props, "gravity", 0.5) + set_props_var(props, "weapons_interaction", false) + set_props_var(props, "render_fx", kRenderFxDistort) + + new ModelsPack:models = get_class_var(class, "models") + models_pack_add_model(models, create_model("rezombie/players/husk/husk.mdl")) + + new Weapon:melee = get_class_var(class, "melee") + set_weapon_var(melee, "view_model", create_model("rezombie/players/husk/v_husk.mdl")) + set_weapon_var(melee, "always_damage", 1000) + set_weapon_var(melee, "gibs", true) + + add_translate("classes/assassin") +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/human.sma b/extra/addons/amxmodx/scripting/rezombie/classes/human.sma new file mode 100644 index 0000000..dcd989c --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/human.sma @@ -0,0 +1,88 @@ +#include +#include + +new Weapon:HumanKnife +new Flashlight:HumanFlashlight +new NightVision:ZombieNightVision + +public plugin_precache() { + register_plugin("Class: Human", "1.0.0", "fl0wer") + + new Class:class = create_class("human", TEAM_HUMAN) + set_class_var(class, "name", "RZ_HUMAN") + set_class_var(class, "hud_color", "blue") + set_class_var(class, "forward_give_default_items", "@humanGiveDefaultItems") + + new Props:props = get_class_var(class, "props") + set_props_var(props, "health", 1000) + //set_props_var(props, "gravity", 0.5) + + new ModelsPack:models = get_class_var(class, "models") + models_pack_add_model(models, create_model("rezombie/players/human/elite_crew/1.mdl")) + models_pack_add_model(models, create_model("rezombie/players/human/phoenix/1.mdl")) + models_pack_add_model(models, create_model("rezombie/players/human/separatist/1.mdl")) + + new Weapon:melee = get_class_var(class, "melee") + set_weapon_var(melee, "view_model", create_model("rezombie/weapons/knife/v_knife.mdl")) + set_weapon_var(melee, "player_model", create_model("rezombie/weapons/knife/p_knife.mdl")) + set_weapon_var(melee, "world_model", create_model("rezombie/weapons/knife/w_knife.mdl")) + + add_translate("classes/human") + + HumanFlashlight = create_flashlight("yellow", 5, 120, 20) + ZombieNightVision = create_night_vision("rgba(255, 0, 0, 50%)")//, create_fog("darkred", 20)) +} + +public plugin_init() { + HumanKnife = checkWeaponExists("knife_strong") +} + +@humanGiveDefaultItems(player) { + give_weapon_by_id(player, HumanKnife) + change_player_flashlight(player, HumanFlashlight) + change_player_night_vision(player, ZombieNightVision) + set_jumps_var(player, "maximum", -1) + give_long_jump(player, .force = 560, .height = 300, .cooldown = 5) + + if (is_player_extra_exists(player, extra_int, "gender")) { + server_print("gender var exists") + } else { + server_print("gender var not exists") + } + set_player_extra(player, extra_int, "gender", 1) + server_print("gender setted") + if (is_player_extra_exists(player, extra_int, "gender")) { + server_print("gender var exists") + } else { + server_print("gender var not exists") + } + server_print("gender: %d", get_player_extra(player, extra_int, "gender")) + + if (is_player_extra_exists(player, extra_float, "gender")) { + server_print("gender var exists") + } else { + server_print("gender var not exists") + } + set_player_extra(player, extra_float, "gender", 2.0) + server_print("gender setted") + if (is_player_extra_exists(player, extra_float, "gender")) { + server_print("gender var exists") + } else { + server_print("gender var not exists") + } + server_print("gender: %f", get_player_extra(player, extra_float, "gender")) + + if (is_player_extra_exists(player, extra_string, "gender")) { + server_print("gender var exists") + } else { + server_print("gender var not exists") + } + set_player_extra(player, extra_string, "gender", "male") + server_print("gender setted") + if (is_player_extra_exists(player, extra_string, "gender")) { + server_print("gender var exists") + } else { + server_print("gender var not exists") + } + server_print("gender: %s", get_player_extra_string(player, "gender")) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/human_dead.sma b/extra/addons/amxmodx/scripting/rezombie/classes/human_dead.sma new file mode 100644 index 0000000..831315e --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/human_dead.sma @@ -0,0 +1,17 @@ +#include +#include + +public plugin_precache() { + register_plugin("Human: Dead Inside", "1.0.0", "fl0wer") + new Class:class = checkClassExists("human") + add_translate("subclasses/human_dead_inside") + + new Subclass:subclass = create_subclass("human_dead_inside", class) + set_subclass_var(subclass, "name", "RZ_SUBHUMAN_DEAD_NAME") + //rz_subclass_set(subclass, RZ_SUBCLASS_DESC, "RZ_SUBHUMAN_DEAD_DESC") + set_subclass_var(subclass, "model", create_model("rezombie/players/human/elite_crew/1.mdl")) + + new Props:props = get_subclass_var(subclass, "props") + set_props_var(props, "health", 50) + set_props_var(props, "armor", 50) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/human_techno.sma b/extra/addons/amxmodx/scripting/rezombie/classes/human_techno.sma new file mode 100644 index 0000000..cd6a163 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/human_techno.sma @@ -0,0 +1,16 @@ +#include +#include + +public plugin_precache() { + register_plugin("Human: Techno Dancer", "1.0.0", "fl0wer") + new Class:class = checkClassExists("human") + add_translate("subclasses/human_techno_dancer") + + new Subclass:subclass = create_subclass("human_techno_dancer", class) + set_subclass_var(subclass, "name", "RZ_SUBHUMAN_TECHNO_NAME") + //rz_subclass_set(subclass, RZ_SUBCLASS_DESC, "RZ_SUBHUMAN_TECHNO_DESC") + set_subclass_var(subclass, "model", create_model("rezombie/players/human/phoenix/1.mdl")) + + new Props:props = get_subclass_var(subclass, "props") + set_props_var(props, "health", 200) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/nemesis.sma b/extra/addons/amxmodx/scripting/rezombie/classes/nemesis.sma new file mode 100644 index 0000000..ac5eaee --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/nemesis.sma @@ -0,0 +1,52 @@ +#include +#include +#include + +new Class:NemesisClass + +// kRenderFxHologram top + +public plugin_precache() { + register_plugin("Class: Nemesis", "1.0.0", "fl0wer") + + new Class:class = NemesisClass = create_class("nemesis", TEAM_ZOMBIE) + set_class_var(class, "name", "RZ_NEMESIS") + set_class_var(class, "forward_give_default_items", "@nemesisGiveDefaultItems") + + new Props:props = get_class_var(class, "props") + set_props_var(props, "health", 2000) + set_props_var(props, "gravity", 0.5) + set_props_var(props, "weapons_interaction", false) + set_props_var(props, "render_fx", kRenderFxGlowShell) + set_props_var(props, "render_amount", 64) + set_props_var(props, "render_color", "black") + + new ModelsPack:models = get_class_var(class, "models") + models_pack_add_model(models, create_model("rezombie/players/z4hide/z4hide.mdl")) + + new Weapon:melee = get_class_var(class, "melee") + set_weapon_var(melee, "view_model", create_model("rezombie/players/z4hide/v_z4hide.mdl")) + set_weapon_var(melee, "always_damage", 250) + set_weapon_var(melee, "gibs", true) + + add_translate("classes/nemesis") +} + +public plugin_init() { + RegisterHookChain(RG_CBasePlayer_SetAnimation, "@Player_SetAnimation_Pre", false) +} + +@nemesisGiveDefaultItems(player) { + set_jumps_var(player, "maximum", 1) + give_long_jump(player, .force = 560, .height = 300, .cooldown = 5) +} + +@Player_SetAnimation_Pre(player, PLAYER_ANIM:anim) { + if (get_player_var(player, "class") != NemesisClass) { + return HC_CONTINUE + } + if (anim != PLAYER_FLINCH && anim != PLAYER_LARGE_FLINCH) { + return HC_CONTINUE + } + return HC_SUPERCEDE +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/sniper.sma b/extra/addons/amxmodx/scripting/rezombie/classes/sniper.sma new file mode 100644 index 0000000..db6e782 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/sniper.sma @@ -0,0 +1,78 @@ +#include +#include +#include + +new Class:SniperClass +new Weapon:SniperWeapon + +public plugin_precache() { + register_plugin("Class: Sniper", "1.0.0", "fl0wer") + + SniperWeapon = checkWeaponExists("default_awp") + + new Class:class = SniperClass = create_class("sniper", TEAM_HUMAN) + set_class_var(class, "name", "RZ_SNIPER") + set_class_var(class, "melee", null) + set_class_var(class, "forward_give_default_items", "@sniperGiveDefaultItems") + + new Props:props = get_class_var(class, "props") + set_props_var(props, "health", 250) + set_props_var(props, "armor", 100) + set_props_var(props, "gravity", 0.5) + set_props_var(props, "weapons_interaction", false) + + add_translate("classes/sniper") +} + +public plugin_init() { + RegisterHookChain(RG_CBasePlayer_TakeDamage, "@Player_TakeDamage_Pre", false) + RegisterHookChain(RG_CBasePlayer_Killed, "@Player_Killed_Pre", false) +} + +@sniperGiveDefaultItems(player) { + give_weapon_by_id(player, SniperWeapon) +} + +// always damage +@Player_TakeDamage_Pre(player, inflictor, attacker, Float:damage, damageType) { + if (player == attacker || !rg_is_player_can_takedamage(player, attacker)) { + return + } + if (get_player_var(attacker, "class") != SniperClass) { + return + } + // inflictor impulse == ZombieMelee + if (get_player_var(attacker, "active_weapon") != SniperWeapon) { + return + } + SetHookChainArg(4, ATYPE_FLOAT, 1000.0) +} + +@Player_Killed_Pre(player, attacker, gib) { + if (player == attacker || !is_user_connected(attacker)) { + return + } + if (!rg_is_player_can_takedamage(player, attacker)) { + return + } + // inflictor + if (get_player_var(attacker, "class") != SniperClass) { + return + } + if (get_player_var(attacker, "active_weapon") != SniperWeapon) { + return + } + SetHookChainArg(3, ATYPE_INTEGER, GIB_ALWAYS) + new Float:origin[3] + get_entvar(player, var_origin, origin) + message_begin_f(MSG_PVS, SVC_TEMPENTITY, origin) + TE_LavaSplash(origin) +} + +TE_LavaSplash(Float:position[3]) { + write_byte(TE_LAVASPLASH) + write_coord_f(position[0]) + write_coord_f(position[1]) + write_coord_f(position[2]) + message_end() +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/survivor.sma b/extra/addons/amxmodx/scripting/rezombie/classes/survivor.sma new file mode 100644 index 0000000..c6ba213 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/survivor.sma @@ -0,0 +1,29 @@ +#include +#include + +new Weapon:SurvivorWeapon +new Weapon:DualDeagleWeapon + +public plugin_precache() { + register_plugin("Class: Survivor", "1.0.0", "fl0wer") + + SurvivorWeapon = checkWeaponExists("default_m249") + DualDeagleWeapon = checkWeaponExists("cso_dual_deagle") + + new Class:class = create_class("survivor", TEAM_HUMAN) + set_class_var(class, "name", "RZ_SURVIVOR") + set_class_var(class, "melee", null) + set_class_var(class, "forward_give_default_items", "@survivorGiveDefaultItems") + + new Props:props = get_class_var(class, "props") + set_props_var(props, "health", 111) + set_props_var(props, "gravity", 0.5) + set_props_var(props, "weapons_interaction", false) + + add_translate("classes/survivor") +} + +@survivorGiveDefaultItems(player) { + give_weapon_by_id(player, SurvivorWeapon) + give_weapon_by_id(player, DualDeagleWeapon) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/zombie.sma b/extra/addons/amxmodx/scripting/rezombie/classes/zombie.sma new file mode 100644 index 0000000..3303306 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/zombie.sma @@ -0,0 +1,109 @@ +#include +#include +#include + +new const INFECTION_ICON[] = "teammate" + +new Class:ZombieClass +new Melee:ZombieMelee +new NightVision:ZombieNightVision + +public plugin_precache() { + register_plugin("Class: Zombie", "1.0.0", "fl0wer") + + new Class:class = ZombieClass = create_class("zombie", TEAM_ZOMBIE) + set_class_var(class, "name", "RZ_ZOMBIE") + set_class_var(class, "forward_give_default_items", "@zombieGiveDefaultItems") + + new Props:props = get_class_var(class, "props") + set_props_var(props, "health", 500) + set_props_var(props, "gravity", 0.8) + set_props_var(props, "weapons_interaction", false) + + new ModelsPack:models = get_class_var(class, "models") + models_pack_add_model(models, create_model("models/player/leet/leet.mdl")) + + ZombieMelee = get_class_var(class, "melee") + ZombieNightVision = create_night_vision("red", create_fog("darkred", 30)) + + add_translate("classes/zombie") +} + +@zombieGiveDefaultItems(player) { + change_player_night_vision(player, ZombieNightVision) +} + +@change_class_post(player, Class:class, attacker) { + if (class != ZombieClass) { + return + } + if (attacker) { + send_death_msg(TO_ALL, attacker, player, INFECTION_ICON) + send_score_attrib(TO_ALL, player) + } else { + send_death_msg(TO_ALL, attacker, player, INFECTION_ICON) + send_score_attrib(TO_ALL, player) + } + infectionEffects(player) +} + +infectionEffects(player) { + message_begin(MSG_ONE, get_user_msgid("ScreenShake"), _, player) + write_short((1<<12) * 4) + write_short((1<<12) * 2) + write_short((1<<12) * 10) + message_end() + + new Float:origin[3] + get_entvar(player, var_origin, origin) + + message_begin_f(MSG_PVS, SVC_TEMPENTITY, origin) + TE_Implosion(origin, 128, 20, 3) + + message_begin_f(MSG_PVS, SVC_TEMPENTITY, origin) + TE_ParticleBurst(origin, 50, 70, 3) + + new cvar_infect_sparkle_color[3] = { 0, 150, 0 } + + message_begin_f(MSG_PVS, SVC_TEMPENTITY, origin) + TE_DLight(origin, 20, cvar_infect_sparkle_color, 2, 0) +} + +stock TE_Implosion(Float:position[3], radius, count, life) +{ + write_byte(TE_IMPLOSION); + write_coord_f(position[0]); // position.x + write_coord_f(position[1]); // position.y + write_coord_f(position[2]); // position.z + write_byte(radius); // radius + write_byte(count); // count + write_byte(life); // life in 0.1's + message_end(); +} + +stock TE_ParticleBurst(Float:origin[3], radius, particleColor, duration) +{ + write_byte(TE_PARTICLEBURST); + write_coord_f(origin[0]); // origin + write_coord_f(origin[1]); + write_coord_f(origin[2]); + write_short(radius); // radius + write_byte(particleColor); // particle color + write_byte(duration); // duration * 10 (will be randomized a bit) + message_end(); +} + +stock TE_DLight(Float:position[3], radius, color[3], life, decayRate) +{ + write_byte(TE_DLIGHT); + write_coord_f(position[0]); // position.x + write_coord_f(position[1]); // position.y + write_coord_f(position[2]); // position.z + write_byte(radius); // radius in 10's + write_byte(color[0]); // red + write_byte(color[1]); // green + write_byte(color[2]); // blue + write_byte(life); // life in 10's + write_byte(decayRate); // decay rate in 10's + message_end(); +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/zombie_jumper.sma b/extra/addons/amxmodx/scripting/rezombie/classes/zombie_jumper.sma new file mode 100644 index 0000000..cc961f9 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/zombie_jumper.sma @@ -0,0 +1,17 @@ +#include +#include + +public plugin_precache() { + register_plugin("Zombie: Jumper", "1.0.0", "fl0wer") + new Class:class = checkClassExists("zombie") + add_translate("subclasses/zombie_jumper") + + new Subclass:subclass = create_subclass("zombie_jumper", class) + set_subclass_var(subclass, "name", "RZ_SUBZOMBIE_JUMPER_NAME") + //rz_subclass_set(subclass, RZ_SUBCLASS_DESC, "RZ_SUBZOMBIE_JUMPER_DESC") + + new Props:props = get_subclass_var(subclass, "props") + set_props_var(props, "health", 1000) + set_props_var(props, "speed", 250) + set_props_var(props, "gravity", 0.7) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/zombie_sprinter.sma b/extra/addons/amxmodx/scripting/rezombie/classes/zombie_sprinter.sma new file mode 100644 index 0000000..f1a5cbd --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/zombie_sprinter.sma @@ -0,0 +1,17 @@ +#include +#include + +public plugin_precache() { + register_plugin("Zombie: Sprinter", "1.0.0", "fl0wer") + new Class:class = checkClassExists("zombie") + add_translate("subclasses/zombie_sprinter") + + new Subclass:subclass = create_subclass("zombie_sprinter", class) + set_subclass_var(subclass, "name", "RZ_SUBZOMBIE_SPRINTER_NAME") + //rz_subclass_set(subclass, RZ_SUBCLASS_DESC, "RZ_SUBZOMBIE_SPRINTER_DESC") + + new Props:props = get_subclass_var(subclass, "props") + set_props_var(props, "health", 700) + set_props_var(props, "speed", 260) + set_props_var(props, "gravity", 0.9) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/zombie_stone.sma b/extra/addons/amxmodx/scripting/rezombie/classes/zombie_stone.sma new file mode 100644 index 0000000..b2e89c5 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/zombie_stone.sma @@ -0,0 +1,17 @@ +#include +#include + +public plugin_precache() { + register_plugin("Zombie: Stone", "1.0.0", "fl0wer") + new Class:class = checkClassExists("zombie") + add_translate("subclasses/zombie_stone") + + new Subclass:subclass = create_subclass("zombie_stone", class) + set_subclass_var(subclass, "name", "RZ_SUBZOMBIE_STONE_NAME") + //rz_subclass_set(subclass, RZ_SUBCLASS_DESC, "RZ_SUBZOMBIE_STONE_DESC") + + new Props:props = get_subclass_var(subclass, "props") + set_props_var(props, "health", 1500) + set_props_var(props, "speed", 240) + set_props_var(props, "gravity", 0.95) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/classes/zombie_swarm.sma b/extra/addons/amxmodx/scripting/rezombie/classes/zombie_swarm.sma new file mode 100644 index 0000000..b7f0b55 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/classes/zombie_swarm.sma @@ -0,0 +1,26 @@ +#include +#include + +new Subclass:ZombieSwarm + +public plugin_precache() { + register_plugin("Zombie: Swarm", "1.0.0", "fl0wer") + new Class:class = checkClassExists("zombie") + add_translate("subclasses/zombie_swarm") + + new Subclass:subclass = ZombieSwarm = create_subclass("zombie_swarm", class) + set_subclass_var(subclass, "name", "RZ_SUBZOMBIE_SWARM_NAME") + //rz_subclass_set(subclass, RZ_SUBCLASS_DESC, "RZ_SUBZOMBIE_SWARM_DESC") + + new Props:props = get_subclass_var(subclass, "props") + set_props_var(props, "health", 700) + set_props_var(props, "speed", 260) + set_props_var(props, "gravity", 0.9) +} + +@change_class_pre(player, Class:class, attacker) { + if (attacker && get_player_var(attacker, "subclass") == ZombieSwarm) { + return RZ_SUPERCEDE + } + return RZ_CONTINUE +} diff --git a/extra/addons/amxmodx/scripting/rezombie/core/environment.sma b/extra/addons/amxmodx/scripting/rezombie/core/environment.sma new file mode 100644 index 0000000..9992205 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/core/environment.sma @@ -0,0 +1,12 @@ +#include +#include + +// bug when change map have previuous +public plugin_precache() { + register_plugin("Environment", "1.0.0", "fl0wer") + + set_env_var("sky_name", "space") + set_env_var("light", "f") + set_env_var("fog", create_fog("grey", 15)) + set_env_var("weather_type", weather_type_rain) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/core/joining.sma b/extra/addons/amxmodx/scripting/rezombie/core/joining.sma new file mode 100644 index 0000000..e87a914 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/core/joining.sma @@ -0,0 +1,137 @@ +#include +#include + +new const PREVIEW_SKELETON_MODEL[] = "rezombie/other/shop.mdl"; +new const PREVIEW_WEAPON[] = "models/p_m4a1.mdl"; + +new const JOINING_MENU_ID[] = "Joining" + +new Subclass:StartingSubclass + +new Class:HumanClass +new Subclass:SelectedSubclass[MAX_PLAYERS + 1] + +// add 0 - spectating (+flags) + +new Model:SkeletonModel +new Model:WeaponModel + +public plugin_precache() { + register_plugin("Joining", "1.0.0", "fl0wer") + HumanClass = checkClassExists("human") + SkeletonModel = create_model(PREVIEW_SKELETON_MODEL, .handle = "preview_skeleton") + WeaponModel = create_model(PREVIEW_WEAPON, .handle = "preview_weapon") +} + +public plugin_init() { + createMenuItems(ArrayCreate(1)) + register_menu(JOINING_MENU_ID, "@JoiningMenu") + setStartingSubclass() +} + +public client_putinserver(player) { + SelectedSubclass[player] = StartingSubclass + if (is_user_bot(player)) { + return + } + set_player_var(player, "map_camera", map_cameras_begin()) + if (map_cameras_count() > 1) { + set_player_var(player, "next_map_camera_time", get_gametime() + 2.0) + } +} + +// Advice: here you can add your own steps +@player_joining(player) { + if (is_user_bot(player)) { + player_joined(player) + return + } + if (StartingSubclass == null) { + player_joined(player) + return + } + openSubclassMenu(player) +} + +@player_joined(player) { + if (get_player_var(player, "team") == TEAM_SPECTATOR) { + return + } + respawn_player(player, 5) +} + +openSubclassMenu(player, Page:page = START_PAGE) { + set_preview_var(player, "enabled", true) + set_preview_var(player, "parent_model", SkeletonModel) + set_preview_var(player, "attach_model", get_subclass_var(SelectedSubclass[player], "model")) + set_preview_var(player, "extra_attach_model", WeaponModel) + createMenu(player, JOINING_MENU_ID) + addText("\yВыбери подкласс %l^n^n", get_class_var_string(HumanClass, "name")) + addText("\rНажмите ещё раз для выбора.^n") + MenuItemsCount = collectAvailableSubclasses(player) + calculateMenuPage(player, page, 7) + new Subclass:subclass + new name[MAX_SUBCLASS_VAR_LENGTH] + for (new i = MenuStart; i < MenuEnd; ++i) { + subclass = ArrayGetCell(MenuItems[player], i) + name = get_subclass_var_string(subclass, "name") + if (SelectedSubclass[player] == subclass) { + addItem((1<> \r[\w%l\r] \y<<", MenuItem + 1, name) + } else { + addItem((1< +#include +#include + +// fatal not work + +// For example: "^4[RZ] ^1" +new const CHAT_PREFIX[] = "" + +new Array:TranslateFiles + +public plugin_precache() { + register_plugin("[RZ] Main", "1.0.0", "fl0wer") + TranslateFiles = ArrayCreate(PLATFORM_MAX_PATH) + + add_translate("common") + + addColors() +} + +public plugin_init() { + internalLog(Log_Info, "Loaded %d classes, %d subclasses, %d modes, %d weapons, %d items", + classes_count(), + subclasses_count(), + modes_count(), + weapons_count(), + items_count() + ) + // Lazy loading because AmxModX can't call get_langsnum and get_lang on plugin_precache + loadLanguages() +} + +addColors() { + //create_color("team_human", {0, 0, 255, 1}) + //create_color("team_zombie", {255, 255, 0, 1}) +} + +loadLanguages() { + new translatesCount = ArraySize(TranslateFiles) + new translateFile[PLATFORM_MAX_PATH] + new filePath[PLATFORM_MAX_PATH] + new langsCount = get_langsnum() + new langNameShort[3] + for (new i = 0; i < translatesCount; ++i) { + ArrayGetString(TranslateFiles, i, translateFile, charsmax(translateFile)) + for (new lang = 0; lang < langsCount; ++lang) { + get_lang(lang, langNameShort) + format(filePath, charsmax(filePath), "%s/%s", langNameShort, translateFile) + register_translate(filePath) + } + } + ArrayClear(TranslateFiles) +} + +public plugin_natives() { + //ExecuteForward(CreateMultiForward("__rezp_version_check", ET_IGNORE, FP_STRING, FP_STRING), _, REZP_VERSION_MAJOR, REZP_VERSION_MINOR) + + register_native("log", "@log") + register_native("print_to_chat", "@print_to_chat") + register_native("add_translate", "@add_translate") +} + +@log(plugin, argc) { + enum { + arg_level = 1, + arg_message, + arg_arguments, + } + + new level = get_param(arg_level) + new buffer[512] + new fileName[64] + new pluginName[64] + vdformat(buffer, charsmax(buffer), arg_message, arg_arguments) + get_plugin(plugin, fileName, charsmax(fileName), pluginName, charsmax(pluginName)) + switch (level) { + case Log_Fatal: { + dllfunc(DLLFunc_Sys_Error, fmt("[ReZombie] %s (%s): %s", fileName, fileName, buffer)) + } + case Log_Error: { + server_print("[ERROR] %s: %s. Plugin %s has stopped", fileName, buffer, fileName) + pause("c", fileName) + } + case Log_Warning: { + server_print("[WARN] %s: %s", fileName, buffer) + } + case Log_Info: { + server_print("[INFO] %s: %s", fileName, buffer) + } + } +} + +@print_to_chat(plugin, argc) { + enum { + arg_player = 1, + arg_sender, + arg_text, + arg_arguments, + } + + new player = get_param(arg_player) + new sender = get_param(arg_sender) + new buffer[190] + vdformat(buffer, charsmax(buffer), arg_text, arg_arguments) + client_print_color(player, sender, "%s%s", CHAT_PREFIX, buffer) +} + +@add_translate(plugin, argc) { + enum { + arg_translate_file = 1 + } + + new translateFile[PLATFORM_MAX_PATH] + get_string(arg_translate_file, translateFile, charsmax(translateFile)) + if (!translateFile[0]) { + return false + } + ArrayPushString(TranslateFiles, translateFile) + return true +} + +internalLog(LogLevel:level, const message[], any:...) { + // static? + new buffer[512] + vformat(buffer, charsmax(buffer), message, 3) + switch (level) { + case Log_Fatal: { + dllfunc(DLLFunc_Sys_Error, fmt("[ReZombie]: %s", buffer)) + } + case Log_Error: { + server_print("[ERROR] %s", buffer) + } + case Log_Warning: { + server_print("[WARN] %s", buffer) + } + case Log_Info: { + server_print("[INFO] %s", buffer) + } + } +} diff --git a/extra/addons/amxmodx/scripting/rezombie/currencies/ammo_packs.sma b/extra/addons/amxmodx/scripting/rezombie/currencies/ammo_packs.sma new file mode 100644 index 0000000..4f63134 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/currencies/ammo_packs.sma @@ -0,0 +1,77 @@ +#include +#include + +new Currency:AmmoPacksCurrency + +new AmmoPacks[MAX_PLAYERS + 1] + +new ChangingHudParams[HudParams] + +new const AMMO_PACKS_PLURALS[Plurals][MAX_PLURAL_LENGTH] = { "AMMO_PACKS_ONE", "AMMO_PACKS_FEW", "AMMO_PACKS_MANY" } + +public plugin_precache() { + register_plugin("Currency: Ammo Packs", "1.0.0", "fl0wer") + AmmoPacksCurrency = create_currency( + .currencyName = "ammo_packs", + .getFunction = "@getAmmoPacks", + .setFunction = "@setAmmoPacks", + .formatFunction = "@formatAmmoPacks" + ) + ChangingHudParams = hud_params( + .x = 0.6, + .y = 0.6, + .color1 = "red", + .color2 = "red", + .effect = 2, + .fadeInTime = 0.01, + .holdTime = 3.0, + .fadeOutTime = 0.01, + .fxTime = 0.1 + ) + add_translate("currency/ammo_packs") +} + +public client_putinserver(player) { + //set_player_var(player, "currency", AmmoPacksCurrency, 25) +} + +@getAmmoPacks(player) { + return AmmoPacks[player] +} + +@setAmmoPacks(player, amount, const reason[]) { + new oldAmount = AmmoPacks[player] + AmmoPacks[player] = amount + new different + new diffText[MAX_CURRENCY_FORMAT_LENGTH] + if (amount > oldAmount) { + different = amount - oldAmount + copy(ChangingHudParams[hud_color1], charsmax(ChangingHudParams[hud_color1]), "green") + } else if (amount < oldAmount) { + different = oldAmount - amount + copy(ChangingHudParams[hud_color1], charsmax(ChangingHudParams[hud_color1]), "red") + } + diffText = format_currency(AmmoPacksCurrency, different, reason[0] ? true : false) + if (reason[0]) { + if (amount > oldAmount) { + send_hud(player, NOTICE_CHANNEL, ChangingHudParams, "+%s (%s)", diffText, reason) + } else if (amount < oldAmount) { + send_hud(player, NOTICE_CHANNEL, ChangingHudParams, "-%s (%s)", diffText, reason) + } + } else { + if (amount > oldAmount) { + send_hud(player, NOTICE_CHANNEL, ChangingHudParams, "+%s", diffText) + } else if (amount < oldAmount) { + send_hud(player, NOTICE_CHANNEL, ChangingHudParams, "-%s", diffText) + } + } + return true +} + +@formatAmmoPacks(amount, bool:isShort, text[], textLength) { + if (isShort) { + formatex(text, textLength, "%d %l", amount, "AMMO_PACKS_SHORT") + } else { + formatex(text, textLength, "%d %l", amount, quantity(amount, AMMO_PACKS_PLURALS)) + } +} diff --git a/extra/addons/amxmodx/scripting/rezombie/currencies/money.sma b/extra/addons/amxmodx/scripting/rezombie/currencies/money.sma new file mode 100644 index 0000000..3e7aa00 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/currencies/money.sma @@ -0,0 +1,52 @@ +#include +#include +#include + +new Currency:MoneyCurrency + +new Money[MAX_PLAYERS + 1] + +public plugin_precache() { + register_plugin("Currency: Money", "1.0.0", "fl0wer") + MoneyCurrency = create_currency( + .currencyName = "money", + .getFunction = "@getMoney", + .setFunction = "@setMoney", + .formatFunction = "@formatMoney" + ) +} + +public client_putinserver(player) { + //set_player_var(player, "currency", MoneyCurrency, 100) +} + +@getMoney(player) { + return Money[player] +} + +@setMoney(player, amount, const reason[]) { + new oldAmount = Money[player] + Money[player] = amount + set_member(player, m_iAccount, amount) + send_money(player, amount) + if (reason[0]) { + if (amount >= oldAmount) { + print_to_chat( + player, print_team_default, + "^4+%s^1: %s", + format_currency(MoneyCurrency, amount - oldAmount), reason + ) + } else if (amount < oldAmount) { + print_to_chat( + player, print_team_red, + "^3-%s^1: %s", + format_currency(MoneyCurrency, oldAmount - amount), reason + ) + } + } + return true +} + +@formatMoney(amount, bool:isShort, text[], textLength) { + formatex(text, textLength, "$%d", amount) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/items/armor_item.sma b/extra/addons/amxmodx/scripting/rezombie/items/armor_item.sma new file mode 100644 index 0000000..3f93368 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/items/armor_item.sma @@ -0,0 +1,68 @@ +#include +#include +#include + +const GIVE_ARMOR = 100 +new const ARMOR_PICKUP_SOUND[] = "items/ammopickup2.wav" +/* +native ItemFilter:add_item_filter(Item:item, const filter[], any:value); +native ItemRestrict:add_item_restrict(Item:item, const filter[], any:value); + +native Cost:create_cost(const value, const currency[]); +*/ + +new NightVision:HumanNightVision + +public plugin_precache() { + register_plugin("[RZ] Item: Armor", "1.0.0", "fl0wer") + new Class:human = checkClassExists("human") + new Item:item = create_item("human_armor", "@give_armor") + if (!item) { + return + } + add_translate("items/human_armor") + set_item_var(item, "name", "RZ_ITEM_ARMOR") + set_item_var(item, "price", create_price(find_currency("money"), 10)) + /*rz_add_item_filter(item, "minimum_players", 4) + rz_add_item_filter(item, "rounds_delay", 2) + rz_add_item_filter(item, "map_limit", 1) + rz_add_item_filter(item, "@filter") + rz_add_item_filter(item, item_filter_rounds_delay, 2)*/ + //rz_item_command_add(item, "say /armor") + precache_sound(ARMOR_PICKUP_SOUND) + + new Item:item2 = create_item("human_armor2", "@give_armor") + if (!item2) { + return + } + add_translate("items/human_armor") + set_item_var(item2, "name", "RZ_ITEM_ARMOR") + set_item_var(item2, "price", create_price(find_currency("ammo_packs"), 7)) + /*add_item_filter(item2, "class", human) + add_item_restrict(item2, "cost", create_cost(7, "ammo_packs")) + add_item_restrict(item2, "map", 1)*/ + + new Item:item3 = create_item("human_armor3", "@give_armor") + if (!item3) { + return + } + add_translate("items/human_armor") + set_item_var(item3, "name", "RZ_ITEM_ARMOR") + + new Item:item4 = create_item("human_armor4", "@give_night_vision") + if (!item4) { + return + } + add_translate("items/human_armor") + set_item_var(item4, "name", "ITEM_NIGHT_VISION") + HumanNightVision = create_night_vision("blue") +} + +@give_armor(player) { + rg_set_user_armor(player, max(rg_get_user_armor(player), GIVE_ARMOR), ARMOR_VESTHELM) + rh_emit_sound2(player, 0, CHAN_ITEM, ARMOR_PICKUP_SOUND, VOL_NORM, ATTN_NORM) +} + +@give_night_vision(player) { + change_player_night_vision(player, HumanNightVision) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/menus/admin_menu.sma b/extra/addons/amxmodx/scripting/rezombie/menus/admin_menu.sma new file mode 100644 index 0000000..69b9917 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/menus/admin_menu.sma @@ -0,0 +1,485 @@ +#include +#include + +// Возродить за ? + +new const ADMIN_MENU_COMMANDS[][] = { + "admin", +} + +new const ADMIN_MENU_ID[] = "AdminMod" + +enum LaunchModeType { + LaunchMode_AfterPrepare, + LaunchMode_Instantly, + MAX_LAUNCH_MODE_TYPES +} + +new const LAUNCH_MODE_TYPES[MAX_LAUNCH_MODE_TYPES][] = { + "LAUNCH_MODE_AFTER_PREPARE", + "LAUNCH_MODE_AFTER_INSTANTLY", +} + +new const MODES_MENU_ID[] = "Modes" +new Menu:ModesMenu +new Mode:CurrentLaunchMode[MAX_PLAYERS + 1] +new LaunchModeType:CurrentLaunchModeType[MAX_PLAYERS + 1] + +new const SELECT_MODE_TARGET_MENU_ID[] = "ModeTarget" +new Menu:SelectModeTargetMenu + +new const CHANGE_CLASS_MENU_ID[] = "ChangeClass" +new Menu:ChangeClassMenu +new Class:CurrentChangeClass[MAX_PLAYERS + 1] + +new const RESPAWN_MENU_ID[] = "Respawn" +new Menu:RespawnMenu + +new const COMPLETE_ROUND_MENU_ID[] = "CompleteRound" +new Menu:CompleteRoundMenu + +public plugin_precache() { + register_plugin("Menu: Admin", "1.0.0", "fl0wer") + add_translate("menus/admin") +} + +public plugin_init() { + adminInit() + modesInit() + changeClassInit() + respawnInit() + completeRoundInit() + createMenuItems(ArrayCreate(1, MAX_PLAYERS)) +} + +public client_putinserver(player) { + CurrentLaunchModeType[player] = LaunchMode_AfterPrepare + CurrentChangeClass[player] = classes_begin() +} + +adminInit() { + register_menu(ADMIN_MENU_ID, "@AdminMenu") + register_commands(ADMIN_MENU_COMMANDS, "@Command_AdminMenu") +} + +@Command_AdminMenu(player) { + openAdminMenu(player) + return PLUGIN_HANDLED +} + +openAdminMenu(player) { + createMenu(player, ADMIN_MENU_ID) + addText("\y%l", "ADMIN_MENU_TITLE") + addText("^n") + addText("^n\r%l", "ADMIN_GAME_SUBTITLE") + addItem(MENU_KEY_1, "^n\y1. \w%l", "MODES_MENU_ITEM") + if (get_game_var("game_state") == game_state_warmup) { + addItem(MENU_KEY_2, "^n\y2. \w%l", "COMPLETE_WARMUP_ITEM") + } else { + addItem(MENU_KEY_2, "^n\y2. \w%l", "COMPLETE_ROUND_ITEM") + } + addText("^n") + addText("^n\r%l", "ADMIN_PLAYERS_SUBTITLE") + addItem(MENU_KEY_3, "^n\y3. \w%l", "CHANGE_CLASS_MENU_ITEM") + addItem(MENU_KEY_4, "^n\y4. \w%l", "RESPAWN_MENU_ITEM") + addText("^n") + addMenuCloseItem() + showMenu(player) +} + +@AdminMenu(player, key) { + if (key == MenuKey_Exit) { + return PLUGIN_HANDLED + } + switch (key) { + case 0: { + openModesMenu(player) + } + case 1: { + if (get_game_var("game_state") == game_state_warmup) { + } else { + openCompleteRoundMenu(player) + } + } + case 2: { + openChangeClassMenu(player) + } + case 3: { + openRespawnMenu(player) + } + } + return PLUGIN_HANDLED +} + +modesInit() { + ModesMenu = register_menu(MODES_MENU_ID, "@ModesMenu") + SelectModeTargetMenu = register_menu(SELECT_MODE_TARGET_MENU_ID, "@SelectModeTargetMenu") +} + +openModesMenu(player, Page:page = START_PAGE) { + createMenu(player, MODES_MENU_ID) + addText("\y%l", "MODES_MENU_TITLE") + MenuItemsCount = collectAvailableModes(player) + calculateMenuPage(player, page, 4) + if (MenuItemsCount) { + new Mode:mode + new name[MAX_MODE_VAR_LENGTH] + new desc[MAX_MODE_VAR_LENGTH] + for (new i = MenuStart; i < MenuEnd; ++i) { + mode = ArrayGetCell(MenuItems[player], i) + name = get_mode_var_string(mode, "name") + desc = get_mode_var_string(mode, "description") + if (get_mode_var(mode, "support_target")) { + addItem((1<= MAX_LAUNCH_MODE_TYPES) { + CurrentLaunchModeType[player] = any:0 + } + } + case MenuKey_Back: { + --MenuPage[player] + } + case MenuKey_Next: { + ++MenuPage[player] + } + default: { + new Mode:mode = getMenuItem(player, key) + if (get_mode_var(mode, "support_target")) { + CurrentLaunchMode[player] = mode + openSelectModeTargetMenu(player) + } else { + launch_mode(mode) + } + return PLUGIN_HANDLED + } + } + openModesMenu(player, MenuPage[player]) + return PLUGIN_HANDLED +} + +openSelectModeTargetMenu(player, Page:page = START_PAGE) { + new name[MAX_MODE_VAR_LENGTH] + name = get_mode_var_string(CurrentLaunchMode[player], "name") + createMenu(player, SELECT_MODE_TARGET_MENU_ID) + addText("\y%l", "SELECT_MODE_TARGET_TITLE") + addText("^n\w%l", "SELECT_MODE_TARGET_SUBTITLE", name) + addText("^n") + MenuItemsCount = collectAvailableModeTargets(player) + calculateMenuPage(player, page, 6) + if (MenuItemsCount) { + new target + for (new i = MenuStart; i < MenuEnd; ++i) { + target = ArrayGetCell(MenuItems[player], i) + addItem((1<= classes_end()) { + CurrentChangeClass[player] = classes_begin() + } + } + case MenuKey_Back: { + --MenuPage[player] + } + case MenuKey_Next: { + ++MenuPage[player] + } + default: { + new target = getMenuItem(player, key) + change_player_class(target, CurrentChangeClass[player]) + client_print(0, print_chat, "%n", target) + } + } + openChangeClassMenu(player, MenuPage[player]) + return PLUGIN_HANDLED +} + +menuTeamColor(Class:class) { + new color[3] + switch (get_class_var(class, "team")) { + case TEAM_HUMAN: { + color = "\y" + } + case TEAM_ZOMBIE: { + color = "\r" + } + default: { + color = "\d" + } + } + return color +} + +respawnInit() { + RespawnMenu = register_menu(RESPAWN_MENU_ID, "@RespawnMenu") +} + +openRespawnMenu(player, Page:page = START_PAGE) { + createMenu(player, RESPAWN_MENU_ID) + MenuItemsCount = collectAvailableRespawn(player) + addText("\y%l", "RESPAWN_MENU_TITLE") + if (MenuItemsCount) { + addText("^n\w%l", "RESPAWN_MENU_SUBTITLE", MenuItemsCount) + } + addText("^n") + calculateMenuPage(player, page, 4) + if (MenuItemsCount) { + new target + for (new i = MenuStart; i < MenuEnd; ++i) { + target = ArrayGetCell(MenuItems[player], i) + addItem((1< +#include +#include +#include + +// do menu dynamically + +new const ADMIN_MENU_ACCESS_FLAGS[] = "b" + +new const GAME_MENU_COMMANDS[][] = { + "chooseteam", + "gamemenu", + "say /menu", +} + +new const GAME_MENU_ID[] = "RZ_GameMenu" + +new Menu:MenuGame + +new Class:HumanClass +new Class:ZombieClass + +public plugin_precache() { + register_plugin("Menu: Game", "1.0.0", "fl0wer") + add_translate("menus/game") +} + +public plugin_init() { + register_commands(GAME_MENU_COMMANDS, "@Command_GameMenu") + MenuGame = register_menu(GAME_MENU_ID, "@Menu_Game") + createMenuItems(ArrayCreate()) + HumanClass = checkClassExists("human") + ZombieClass = checkClassExists("zombie") +} + +@Command_GameMenu(player) { + if (is_nullent(player)) { + return PLUGIN_CONTINUE + } + if (get_member(player, m_iJoiningState) != JOINED) { + return PLUGIN_CONTINUE + } + if (get_opened_menu(player) != MenuGame) { + openGameMenu(player) + } else { + closeMenu(player) + } + return PLUGIN_HANDLED +} + +openGameMenu(player) { + new bool:isTerminateRoundState = get_game_var("round_state") == round_state_terminate + new bool:isAlive = bool:is_user_alive(player) + createMenu(player, GAME_MENU_ID) + addText("\y%l", "GAME_MENU_TITLE") + addText("^n") + addItem(MENU_KEY_1, "^n\y1. \w%l", "GAME_MENU_SELECT_WPNS") + if (!isTerminateRoundState && isAlive) { + addItem(MENU_KEY_2, "^n\y2. \w%l", "GAME_MENU_BUY_EXTRA") // add available items count + } else { + addText("^n\d2. %l", "GAME_MENU_BUY_EXTRA") + } + addItem(MENU_KEY_3, "^n\y3. \wСменить подкласс %l", get_class_var_string(HumanClass, "name")) + addItem(MENU_KEY_4, "^n\y4. \wСменить подкласс %l", get_class_var_string(ZombieClass, "name")) + // check last + if (get_member(player, m_iTeam) == TEAM_SPECTATOR) { + addItem(MENU_KEY_5, "^n\y5. \w%l", "GAME_MENU_JOIN_GAME") + } else { + addItem(MENU_KEY_5, "^n\y5. \w%l", "GAME_MENU_JOIN_SPECS") + } + addText("^n") + addText("^n") + // always can click + // every item "IsAvaliable" and in handler + if (get_user_flags(player) & read_flags(ADMIN_MENU_ACCESS_FLAGS)) { + addItem(MENU_KEY_9, "^n\y9. \w%l", "ADMIN_MENU_ITEM") + } + addText("^n") + addItem(MENU_KEY_0, "^n\r[0] \w%l \y(M)", "CLOSE") + addText("^n") + addText("^n\d%l", "YOUR_AUTH_ID", getAuthId(player)) + showMenu(player) +} + +@Menu_Game(player, key) { + gameMenuHandler(player, ++key) + return PLUGIN_HANDLED +} + +gameMenuHandler(player, key) { + if (key == 10) { + return + } + switch (key) { + case 1: { + amxclient_cmd(player, "guns") + } + case 2: { + amxclient_cmd(player, "items") + } + case 3: { + amxclient_cmd(player, "human") + } + case 4: { + amxclient_cmd(player, "zombie") + } + case 5: { + if (get_member(player, m_iTeam) == TEAM_SPECTATOR) { + rg_set_user_team(player, TEAM_CT, .check_win_conditions = true) + } else { + if (is_user_alive(player)) { + ExecuteHamB(Ham_Killed, player, player, GIB_NEVER) + } + rg_set_user_team(player, TEAM_SPECTATOR, .check_win_conditions = true) + } + } + case 9: { + amxclient_cmd(player, "admin") + } + } +} + +getAuthId(player) { + new authId[MAX_AUTHID_LENGTH] + get_user_authid(player, authId, charsmax(authId)) + return authId +} diff --git a/extra/addons/amxmodx/scripting/rezombie/menus/items_menu.sma b/extra/addons/amxmodx/scripting/rezombie/menus/items_menu.sma new file mode 100644 index 0000000..27b38f1 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/menus/items_menu.sma @@ -0,0 +1,136 @@ +#include +#include +#include + +new const ITEMS_MENU_COMMANDS[][] = { + "items", + "say /items", +} + +new const ITEMS_MENU_ID[] = "ExtraItems" + +public plugin_precache() { + register_plugin("Menu: Extra Items", "1.0.0", "fl0wer") + register_commands(ITEMS_MENU_COMMANDS, "@Command_Items") + register_menu(ITEMS_MENU_ID, "@ItemsMenu") + createMenuItems(ArrayCreate(1)) + add_translate("menus/items") +} + +@Command_Items(player) { + openItemsMenu(player) + return PLUGIN_HANDLED +} + +openItemsMenu(player, Page:page = START_PAGE) { + if (isTerminateRoundState()) { + return + } + createMenu(player, ITEMS_MENU_ID) + addText("\y%l", "ITEMS_MENU_TITLE") + addText("^n") + MenuItemsCount = collectAvailableItems(player) + calculateMenuPage(player, page) + if (MenuItemsCount) { + new Item:item + new Price:price + new Currency:currency + new name[MAX_ITEM_VAR_LENGTH] + new amount + new priceFormat[MAX_CURRENCY_FORMAT_LENGTH] + for (new i = MenuStart; i < MenuEnd; ++i) { + item = ArrayGetCell(MenuItems[player], i) + name = get_item_var_string(item, "name") + price = get_item_var(item, "price") + if (price) { + currency = get_price_var(price, "currency") + amount = get_price_var(price, "amount") + priceFormat = format_currency(currency, amount) + if (get_player_var(player, "currency", currency) >= amount) {// && rz_item_player_get_status(player, item) == RZ_CONTINUE) + addItem((1<= RZ_BREAK) + // continue + ArrayPushCell(MenuItems[player], item) + } + return ArraySize(MenuItems[player]) +} + +@ItemsMenu(player, key) { + if (key == MenuKey_Exit) { + return PLUGIN_HANDLED + } + switch (key) { + case MenuKey_Back: { + --MenuPage[player] + } + case MenuKey_Next: { + ++MenuPage[player] + } + default: { + new Item:item = getMenuItem(player, key) + processItem(player, item) + return PLUGIN_HANDLED + } + } + openItemsMenu(player, MenuPage[player]) + return PLUGIN_HANDLED +} + +processItem(player, Item:item) { + if (isTerminateRoundState()) { + return + } + new Price:price = get_item_var(item, "price") + new Currency:currency = get_price_var(price, "currency") + new amount = get_price_var(price, "amount") + new playerAmount = get_player_var(player, "currency", currency) + new name[MAX_ITEM_VAR_LENGTH] + new currencyFormat[MAX_CURRENCY_FORMAT_LENGTH] + name = get_item_var_string(item, "name") + if (playerAmount < amount) { + currencyFormat = format_currency(currency, amount - playerAmount) + print_to_chat(player, print_team_red, "%l", "ITEMS_MENU_INSUFFICIENT_FUNDS", name, currencyFormat) + return + } + //if (rz_item_player_get_status(player, i) >= RZ_BREAK) + // continue + if (price && !add_player_currency(player, currency, -amount, "за покупку %l", name)) { + print_to_chat(player, print_team_red, "%l", "ITEMS_MENU_SOMETHING_WENT_WRONG") + return + } + if (!give_item_by_id(player, item)) { + return + } + new Class:class = get_player_var(player, "class") + new className[MAX_ITEM_VAR_LENGTH] + className = get_class_var_string(class, "name") + currencyFormat = format_currency(currency, amount) + if (price) { + print_to_chat(TO_ALL, player, "%l", "ITEMS_MENU_PLAYER_BOUGHT", className, player, name, currencyFormat) + } else { + print_to_chat(TO_ALL, player, "%l", "ITEMS_MENU_PLAYER_TAKEN", className, player, name, currencyFormat) + } +} + +bool:isTerminateRoundState() { + return get_game_var("round_state") == round_state_terminate +} diff --git a/extra/addons/amxmodx/scripting/rezombie/menus/zombie_classes_menu.sma b/extra/addons/amxmodx/scripting/rezombie/menus/zombie_classes_menu.sma new file mode 100644 index 0000000..2f25ec3 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/menus/zombie_classes_menu.sma @@ -0,0 +1,113 @@ +#include +#include + +new const SUBCLASS_MENU_ID[] = "ZombieSubclass" + +new Subclass:StartingSubclass + +new Class:ClassZombie + +new bool:IsSubclassChoosen[MAX_PLAYERS + 1] + +public plugin_precache() { + register_plugin("[RZ] Menu: Zombie Subclass", "1.0.0", "fl0wer") + ClassZombie = checkClassExists("zombie") +} + +public plugin_init() { + register_menu(SUBCLASS_MENU_ID, "@SubclassMenu") + createMenuItems(ArrayCreate(1)) + setStartingSubclass() +} + +public client_putinserver(player) { + if (is_user_bot(player)) { + IsSubclassChoosen[player] = false + } else { + IsSubclassChoosen[player] = false + } + set_player_var(player, "keep_subclass", ClassZombie, StartingSubclass) +} + +@change_class_post(player, Class:class, attacker) { + if (class != ClassZombie) { + return + } + if (IsSubclassChoosen[player]) { + return + } + openSubclassMenu(player) +} + +openSubclassMenu(player, Page:page = START_PAGE) { + createMenu(player, SUBCLASS_MENU_ID) + addText("\yВыбери подкласс %l^n", get_class_var_string(ClassZombie, "name")) + addText("^n") + MenuItemsCount = collectAvailableItems(player) + calculateMenuPage(player, page) + new Subclass:currentSubclass = get_player_var(player, "keep_subclass", ClassZombie) + new Subclass:subclass + new name[MAX_SUBCLASS_VAR_LENGTH] + for (new i = MenuStart; i < MenuEnd; ++i) { + subclass = ArrayGetCell(MenuItems[player], i) + name = get_subclass_var_string(subclass, "name") + if (subclass == currentSubclass) { + addItem((1< +#include +#include + +new Class:SurvivorClass +new Class:SniperClass +new Class:NemesisClass +new Class:AssassinClass +new Fog:Fog + +public plugin_precache() { + register_plugin("Mode: Armageddon", "1.0.0", "fl0wer") + + SurvivorClass = checkClassExists("survivor") + SniperClass = checkClassExists("sniper") + NemesisClass = checkClassExists("nemesis") + AssassinClass = checkClassExists("assassin") + + new Mode:mode = create_mode("armageddon", "@launch_armageddon") + set_mode_var(mode, "name", "MODE_ARMAGEDDON_NAME") + set_mode_var(mode, "description", "MODE_ARMAGEDDON_DESC") + set_mode_var(mode, "notice_message", "MODE_ARMAGEDDON_NOTICE") + set_mode_var(mode, "respawn", Respawn_ToHumansTeam) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_NOTICE, "RZ_GAMEMODE_NOTICE_LNJ") + //rz_gamemode_set(gameMode, RZ_GAMEMODE_HUD_COLOR, { 181, 62, 244 }) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_CHANCE, 20) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_MIN_ALIVES, 16) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_DEATHMATCH, RZ_GM_DEATHMATCH_ONLY_CT) + + Fog = create_fog("black", 15) + + add_translate("modes/armageddon") +} + +// this is with snipers, assassins? +@launch_armageddon() { + new alivesNum + new Array:alivePlayers = get_alive_players(alivesNum) + new maxNemeses = floatround(alivesNum * 0.5, floatround_ceil) + new Float:health + new index + new player + for (new i = 0; i < maxNemeses; ++i) { + index = random(ArraySize(alivePlayers)) + player = ArrayGetCell(alivePlayers, index) + change_player_class(player, NemesisClass) + health = Float:get_entvar(player, var_health) * 0.25 + set_entvar(player, var_health, health) + set_entvar(player, var_max_health, health) + ArrayDeleteItem(alivePlayers, index) + } + alivesNum = ArraySize(alivePlayers) + for (new i = 0; i < alivesNum; ++i) { + player = ArrayGetCell(alivePlayers, i) + change_player_class(player, SurvivorClass) + health = Float:get_entvar(player, var_health) * 0.25 + set_entvar(player, var_health, health) + set_entvar(player, var_max_health, health) + } + set_game_var("override_default_class", TEAM_ZOMBIE, NemesisClass) + set_game_var("override_default_class", TEAM_HUMAN, SurvivorClass) + set_override_env_var("fog", Fog) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/modes/assassin_mode.sma b/extra/addons/amxmodx/scripting/rezombie/modes/assassin_mode.sma new file mode 100644 index 0000000..0e35075 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/modes/assassin_mode.sma @@ -0,0 +1,37 @@ +#include +#include +#include + +new Class:AssassinClass +new Fog:Fog + +public plugin_precache() { + register_plugin("Mode: Assassin", "1.0.0", "fl0wer") + + AssassinClass = checkClassExists("assassin") + + new Mode:mode = create_mode("assassin", "@launch_assassin", true) + set_mode_var(mode, "name", "MODE_ASSASSIN_NAME") + set_mode_var(mode, "description", "MODE_ASSASSIN_DESC") + set_mode_var(mode, "notice_message", "MODE_ASSASSIN_NOTICE") + //rz_gamemode_set(gameMode, RZ_GAMEMODE_NOTICE, "RZ_GAMEMODE_NOTICE_ASSASSIN"); + //rz_gamemode_set(gameMode, RZ_GAMEMODE_HUD_COLOR, { 255, 150, 20 }); + //rz_gamemode_set(gameMode, RZ_GAMEMODE_CHANCE, 20); + + Fog = create_fog("yellow", 15) + + add_translate("modes/assassin") +} + +@launch_assassin(target) { + if (!target) { + new alivesNum + new Array:alivePlayers = get_alive_players(alivesNum) + target = ArrayGetCell(alivePlayers, random(alivesNum)) + } + change_player_class(target, AssassinClass) + set_game_var("override_default_class", TEAM_ZOMBIE, AssassinClass) + set_override_env_var("light", "a") + set_override_env_var("fog", Fog) + return target +} diff --git a/extra/addons/amxmodx/scripting/rezombie/modes/infection_mode.sma b/extra/addons/amxmodx/scripting/rezombie/modes/infection_mode.sma new file mode 100644 index 0000000..24f89f5 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/modes/infection_mode.sma @@ -0,0 +1,86 @@ +#include +#include +#include + +new Mode:InfectionMode +new Class:ZombieClass +new Fog:Fog + +public plugin_precache() { + register_plugin("Mode: Infection", "1.0.0", "fl0wer") + + ZombieClass = checkClassExists("zombie") + + new Mode:mode = InfectionMode = create_mode("multi", "@launch_infection") + set_mode_var(mode, "name", "MODE_INFECTION_NAME") + set_mode_var(mode, "description", "MODE_INFECTION_DESC") + set_mode_var(mode, "notice_message", "MODE_INFECTION_NOTICE") + set_mode_var(mode, "color", "orange") + set_mode_var(mode, "respawn", Respawn_ToZombiesTeam) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_NOTICE, "RZ_GAMEMODE_NOTICE_MULTI") + //rz_gamemode_set(gameMode, RZ_GAMEMODE_HUD_COLOR, { 200, 50, 0 }) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_DEATHMATCH, RZ_GM_DEATHMATCH_ONLY_TR) + + Fog = create_fog("orange", 15) + + add_translate("modes/infection") +} + +public plugin_init() { + RegisterHookChain(RG_CBasePlayer_TakeDamage, "@Player_TakeDamage_Pre", false) +} + +@launch_infection() { + new alivesNum + new Array:alivePlayers = get_alive_players(alivesNum) + new maxZombies = 1 + if (alivesNum > 30) { + maxZombies = 4 + } else if (alivesNum > 20) { + maxZombies = 3 + } else if (alivesNum > 10) { + maxZombies = 2 + } + maxZombies = min(maxZombies, alivesNum) + for (new zombieCount = 0; zombieCount < maxZombies; ++zombieCount) { + new index = random(ArraySize(alivePlayers)) + new player = ArrayGetCell(alivePlayers, index) + change_player_class(player, ZombieClass) + ArrayDeleteItem(alivePlayers, index) + } + set_override_env_var("fog", Fog) +} + +@Player_TakeDamage_Pre(player, inflictor, attacker, Float:damage, damageType) { + if (get_game_var("mode") != InfectionMode) { + return + } + if (!is_valid_attacker(attacker, player)) { + return + } + if (get_player_var(attacker, "class") != ZombieClass) { + return + } + new Weapon:weapon = get_entvar(inflictor, var_impulse) + if (!is_weapon(weapon)) { + return + } + if (get_weapon_var(weapon, "type") != weapon_type_melee) { + return + } + new Float:armor = get_entvar(player, var_armorvalue) + if (armor > 0.0) { + armor = floatmax(armor - damage, 0.0) + set_entvar(player, var_armorvalue, armor) + SetHookChainArg(4, ATYPE_FLOAT, 0.0) + // already played? + //rh_emit_sound2(player, 0, CHAN_BODY, ARMOR_HIT_SOUND) + } + if (armor > 0.0 || (get_member(player, m_iKevlar) == ARMOR_VESTHELM && get_member(player, m_LastHitGroup) == HITGROUP_HEAD)) { + return + } + if (change_player_class(player, ZombieClass, attacker) > RZ_CONTINUE) { + return + } + SetHookChainArg(4, ATYPE_FLOAT, 0.0) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/modes/nemesis_mode.sma b/extra/addons/amxmodx/scripting/rezombie/modes/nemesis_mode.sma new file mode 100644 index 0000000..799e959 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/modes/nemesis_mode.sma @@ -0,0 +1,38 @@ +#include +#include +#include + +new Class:NemesisClass +new Fog:Fog +new NightVision:HumanNightVision + +public plugin_precache() { + register_plugin("Mode: Nemesis", "1.0.0", "fl0wer") + + NemesisClass = checkClassExists("nemesis") + + new Mode:mode = create_mode("nemesis", "@launch_nemesis", true) + set_mode_var(mode, "name", "MODE_NEMESIS_NAME") + set_mode_var(mode, "description", "MODE_NEMESIS_DESC") + set_mode_var(mode, "notice_message", "MODE_NEMESIS_NOTICE") + set_mode_var(mode, "color", "red") + set_mode_var(mode, "respawn", Respawn_ToZombiesTeam) + + Fog = create_fog("red", 15) + HumanNightVision = create_night_vision("red", create_fog("darkred", 30)) + + add_translate("modes/nemesis") +} + +@launch_nemesis(target) { + if (!target) { + new alivesNum + new Array:alivePlayers = get_alive_players(alivesNum) + target = ArrayGetCell(alivePlayers, random(alivesNum)) + } + change_player_class(target, NemesisClass) + set_game_var("override_default_class", TEAM_ZOMBIE, NemesisClass) + set_override_env_var("fog", Fog) + change_player_night_vision(1, HumanNightVision) + return target +} diff --git a/extra/addons/amxmodx/scripting/rezombie/modes/plague_mode.sma b/extra/addons/amxmodx/scripting/rezombie/modes/plague_mode.sma new file mode 100644 index 0000000..d66b246 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/modes/plague_mode.sma @@ -0,0 +1,65 @@ +#include +#include +#include + +new Class:ZombieClass +new Class:NemesisClass +new Class:SurvivorClass +new Fog:Fog + +public plugin_precache() { + register_plugin("Mode: Plague", "1.0.0", "fl0wer") + + ZombieClass = checkClassExists("zombie") + NemesisClass = checkClassExists("nemesis") + SurvivorClass = checkClassExists("survivor") + + new Mode:mode = create_mode("plague", "@launch_plague") + set_mode_var(mode, "name", "MODE_PLAGUE_NAME") + set_mode_var(mode, "description", "MODE_PLAGUE_DESC") + set_mode_var(mode, "notice_message", "MODE_PLAGUE_NOTICE") + //rz_gamemode_set(gameMode, RZ_GAMEMODE_NOTICE, "RZ_GAMEMODE_NOTICE_PLAGUE") + //rz_gamemode_set(gameMode, RZ_GAMEMODE_HUD_COLOR, { 0, 50, 200 }) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_CHANCE, 20) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_MIN_ALIVES, 8) + + Fog = create_fog("aqua", 15) + + add_translate("modes/plague") +} + +@launch_plague() { + new alivesNum + new Array:alivePlayers = get_alive_players(alivesNum) + new maxNemeses = 1 + new maxSurvivors = 1 + new maxZombies = floatround((alivesNum - (maxNemeses + maxSurvivors)) * 0.5, floatround_ceil) + new Float:health + new index + new player + for (new i = 0; i < maxNemeses; ++i) { + index = random(ArraySize(alivePlayers)) + player = ArrayGetCell(alivePlayers, index) + change_player_class(player, NemesisClass) + health = Float:get_entvar(player, var_health) * 0.5 + set_entvar(player, var_health, health) + set_entvar(player, var_max_health, health) + ArrayDeleteItem(alivePlayers, index) + } + for (new i = 0; i < maxSurvivors; ++i) { + index = random(ArraySize(alivePlayers)) + player = ArrayGetCell(alivePlayers, index) + change_player_class(player, SurvivorClass) + health = Float:get_entvar(player, var_health) * 0.5 + set_entvar(player, var_health, health) + set_entvar(player, var_max_health, health) + ArrayDeleteItem(alivePlayers, index) + } + for (new i = 0; i < maxZombies; ++i) { + index = random(ArraySize(alivePlayers)) + player = ArrayGetCell(alivePlayers, index) + change_player_class(player, ZombieClass) + ArrayDeleteItem(alivePlayers, index) + } + set_override_env_var("fog", Fog) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/modes/sniper_mode.sma b/extra/addons/amxmodx/scripting/rezombie/modes/sniper_mode.sma new file mode 100644 index 0000000..0e597cc --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/modes/sniper_mode.sma @@ -0,0 +1,45 @@ +#include +#include + +new Class:SniperClass +new Class:ZombieClass +new Fog:Fog + +public plugin_precache() { + register_plugin("Mode: Sniper", "1.0.0", "fl0wer") + + SniperClass = checkClassExists("sniper") + ZombieClass = checkClassExists("zombie") + + new Mode:mode = create_mode("sniper", "@launch_sniper", true) + set_mode_var(mode, "name", "MODE_SNIPER_NAME") + set_mode_var(mode, "description", "MODE_SNIPER_DESC") + set_mode_var(mode, "notice_message", "MODE_SNIPER_NOTICE") + //rz_gamemode_set(gameMode, RZ_GAMEMODE_NOTICE, "RZ_GAMEMODE_NOTICE_SNIPER") + //rz_gamemode_set(gameMode, RZ_GAMEMODE_HUD_COLOR, { 0, 250, 250 }) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_CHANCE, 20) + + Fog = create_fog("cyan", 15) + + add_translate("modes/sniper") +} + +@launch_sniper(target) { + new alivesNum + new Array:alivePlayers = get_alive_players(alivesNum) + if (!target) { + target = ArrayGetCell(alivePlayers, random(alivesNum)) + } + new player + for (new i = 0; i < alivesNum; ++i) { + player = ArrayGetCell(alivePlayers, i) + if (player == target) { + continue + } + change_player_class(player, ZombieClass) + } + change_player_class(target, SniperClass) + set_game_var("override_default_class", TEAM_HUMAN, SniperClass) + set_override_env_var("fog", Fog) + return target +} diff --git a/extra/addons/amxmodx/scripting/rezombie/modes/survivor_mode.sma b/extra/addons/amxmodx/scripting/rezombie/modes/survivor_mode.sma new file mode 100644 index 0000000..598a4ee --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/modes/survivor_mode.sma @@ -0,0 +1,43 @@ +#include +#include + +new Class:SurvivorClass +new Class:ZombieClass +new Fog:Fog + +public plugin_precache() { + register_plugin("Mode: Survivor", "1.0.0", "fl0wer") + + SurvivorClass = checkClassExists("survivor") + ZombieClass = checkClassExists("zombie") + + new Mode:mode = create_mode("survivor", "@launch_survivor", true) + set_mode_var(mode, "name", "MODE_SURVIVOR_NAME") + set_mode_var(mode, "description", "MODE_SURVIVOR_DESC") + set_mode_var(mode, "notice_message", "MODE_SURVIVOR_NOTICE") + set_mode_var(mode, "color", "blue") + + Fog = create_fog("blue", 15) + + add_translate("modes/survivor") +} + +@launch_survivor(target) { + new alivesNum + new Array:alivePlayers = get_alive_players(alivesNum) + if (!target) { + target = ArrayGetCell(alivePlayers, random(alivesNum)) + } + new player + for (new i = 0; i < alivesNum; ++i) { + player = ArrayGetCell(alivePlayers, i) + if (player == target) { + continue + } + change_player_class(player, ZombieClass) + } + change_player_class(target, SurvivorClass) + set_game_var("override_default_class", TEAM_HUMAN, SurvivorClass) + set_override_env_var("fog", Fog) + return target +} diff --git a/extra/addons/amxmodx/scripting/rezombie/modes/sva_mode.sma b/extra/addons/amxmodx/scripting/rezombie/modes/sva_mode.sma new file mode 100644 index 0000000..0dff14f --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/modes/sva_mode.sma @@ -0,0 +1,57 @@ +#include +#include +#include + +new Class:SniperClass +new Class:AssassinClass +new Fog:Fog + +public plugin_precache() { + register_plugin("Mode: Snipers vs. Assassins", "1.0.0", "fl0wer") + + SniperClass = checkClassExists("sniper") + AssassinClass = checkClassExists("assassin") + + new Mode:mode = create_mode("sva", "@launch_sva") + set_mode_var(mode, "name", "MODE_SVA_NAME") + set_mode_var(mode, "description", "MODE_SVA_DESC") + set_mode_var(mode, "notice_message", "MODE_SVA_NOTICE") + set_mode_var(mode, "respawn", Respawn_ToZombiesTeam) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_NOTICE, "RZ_GAMEMODE_NOTICE_AVS"); + //rz_gamemode_set(gameMode, RZ_GAMEMODE_HUD_COLOR, { 200, 150, 20 }); + //rz_gamemode_set(gameMode, RZ_GAMEMODE_CHANCE, 20); + //rz_gamemode_set(gameMode, RZ_GAMEMODE_MIN_ALIVES, 8); + + Fog = create_fog("white", 15) + + add_translate("modes/snipers_vs_assassins") +} + +@launch_sva() { + new alivesNum + new Array:alivePlayers = get_alive_players(alivesNum) + new maxAssassins = floatround(alivesNum * 0.5, floatround_ceil) + new Float:health + new index + new player + for (new i = 0; i < maxAssassins; ++i) { + index = random(ArraySize(alivePlayers)) + player = ArrayGetCell(alivePlayers, index) + change_player_class(player, AssassinClass) + health = Float:get_entvar(player, var_health) * 0.5 + set_entvar(player, var_health, health) + set_entvar(player, var_max_health, health) + ArrayDeleteItem(alivePlayers, index) + } + alivesNum = ArraySize(alivePlayers) + for (new i = 0; i < alivesNum; ++i) { + player = ArrayGetCell(alivePlayers, i) + change_player_class(player, SniperClass) + health = Float:get_entvar(player, var_health) * 1.5 + set_entvar(player, var_health, health) + set_entvar(player, var_max_health, health) + } + set_game_var("override_default_class", TEAM_HUMAN, SniperClass) + set_game_var("override_default_class", TEAM_ZOMBIE, AssassinClass) + set_override_env_var("fog", Fog) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/modes/swarm_mode.sma b/extra/addons/amxmodx/scripting/rezombie/modes/swarm_mode.sma new file mode 100644 index 0000000..20f11e2 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/modes/swarm_mode.sma @@ -0,0 +1,40 @@ +#include +#include +#include + +new Class:ZombieClass +new Fog:Fog + +public plugin_precache() { + register_plugin("Mode: Swarm", "1.0.0", "fl0wer") + + ZombieClass = checkClassExists("zombie") + + new Mode:mode = create_mode("swarm", "@launch_swarm") + set_mode_var(mode, "name", "MODE_SWARM_NAME") + set_mode_var(mode, "description", "MODE_SWARM_DESC") + set_mode_var(mode, "notice_message", "MODE_SWARM_NOTICE") + set_mode_var(mode, "color", "green") + //rz_gamemode_set(gameMode, RZ_GAMEMODE_NOTICE, "RZ_GAMEMODE_NOTICE_SWARM") + //rz_gamemode_set(gameMode, RZ_GAMEMODE_HUD_COLOR, { 20, 255, 20 }) + //rz_gamemode_set(gameMode, RZ_GAMEMODE_CHANCE, 20) + + Fog = create_fog("green", 15) + + add_translate("modes/swarm") +} + +@launch_swarm() { + new alivesNum + new Array:alivePlayers = get_alive_players(alivesNum) + new maxZombies = alivesNum / 2 + new index + new player + for (new i = 0; i < maxZombies; ++i) { + index = random(ArraySize(alivePlayers)) + player = ArrayGetCell(alivePlayers, index) + change_player_class(player, ZombieClass) + ArrayDeleteItem(alivePlayers, index) + } + set_override_env_var("fog", Fog) +} diff --git a/extra/addons/amxmodx/scripting/rezombie/weapons/csgo_weapons.sma b/extra/addons/amxmodx/scripting/rezombie/weapons/csgo_weapons.sma new file mode 100644 index 0000000..7d363b5 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/weapons/csgo_weapons.sma @@ -0,0 +1,494 @@ +#include +#include +#include +#include +#include + +/* + +new const WEAPON_NAMES[WeaponIdType:MAX_WEAPONS][] = { + "", "228 Compact", "", "SSG 08", "Осколочная граната", "XM1014", "Взрывчатка C4", "MAC-10", "AUG", "Дымовая граната", + "Dual Berettas", "Five-SeveN", "UMP-45", "SG 550", "Galil", "FAMAS", "USP", "Glock-18", "AWP", "MP5", + "M249", "M3", "M4A1", "TMP", "G3SG1", "Световая граната", "Desert Eagle", "SG 552", "AK-47", "Нож", "P90", "", +} + +*/ + +new const GLOCK_SHOOT_SOUND[2][] = { + "weapons/csgo/glock/glock-1.wav", + "weapons/csgo/glock/glock-2.wav", +} +new const USP_SHOOT_SOUND[2][] = { + "weapons/csgo/usp/usp_unsil-1.wav", + "weapons/csgo/usp/usp-1.wav", +} +new const M4A1_SHOOT_SOUND[2][] = { + "weapons/csgo/m4a1/m4a1_unsil-1.wav", + "weapons/csgo/m4a1/m4a1-1.wav", +} +new const AK47_SHOOT_SOUND[] = "weapons/csgo/ak47/ak47-1.wav" +new const AWP_SHOOT_SOUND[] = "weapons/csgo/awp/awp-1.wav" +new const NEGEV_SHOOT_SOUND[] = "weapons/csgo/negev/negev-1.wav" // 2 + +new const ADDITIONAL_SOUNDS[][] = { + "weapons/csgo/glock/glock_clipin.wav", + "weapons/csgo/glock/glock_clipout.wav", + "weapons/csgo/glock/glock_draw.wav", + "weapons/csgo/glock/glock_slideback.wav", + "weapons/csgo/glock/glock_sliderelease.wav", + + "weapons/csgo/usp/usp_silencer_screw_on_start.wav", + "weapons/csgo/usp/usp_silencer_screw1.wav", + "weapons/csgo/usp/usp_silencer_screw2.wav", + "weapons/csgo/usp/usp_silencer_screw3.wav", + "weapons/csgo/usp/usp_silencer_screw4.wav", + "weapons/csgo/usp/usp_silencer_screw5.wav", + + "weapons/csgo/m4a1/m4a1_cliphit.wav", + "weapons/csgo/m4a1/m4a1_clipin.wav", + "weapons/csgo/m4a1/m4a1_clipout.wav", + "weapons/csgo/m4a1/m4a1_draw.wav", + "weapons/csgo/m4a1/m4a1_silencer_boltback.wav", + "weapons/csgo/m4a1/m4a1_silencer_boltforward.wav", + "weapons/csgo/m4a1/m4a1_silencer_screw_1.wav", + "weapons/csgo/m4a1/m4a1_silencer_screw_2.wav", + "weapons/csgo/m4a1/m4a1_silencer_screw_3.wav", + "weapons/csgo/m4a1/m4a1_silencer_screw_4.wav", + "weapons/csgo/m4a1/m4a1_silencer_screw_5.wav", + "weapons/csgo/m4a1/m4a1_silencer_screw_off_end.wav", + "weapons/csgo/m4a1/m4a1_silencer_screw_on_start.wav", + + "weapons/csgo/ak47/ak47_boltpull.wav", + "weapons/csgo/ak47/ak47_clipin.wav", + "weapons/csgo/ak47/ak47_clipout.wav", + "weapons/csgo/ak47/ak47_draw.wav", + + "weapons/csgo/awp/awp_boltback.wav", + "weapons/csgo/awp/awp_boltforward.wav", + "weapons/csgo/awp/awp_cliphit.wav", + "weapons/csgo/awp/awp_clipin.wav", + "weapons/csgo/awp/awp_clipout.wav", + "weapons/csgo/awp/awp_draw.wav", + + "weapons/csgo/negev/negev_boxin.wav", + "weapons/csgo/negev/negev_boxout.wav", + "weapons/csgo/negev/negev_chain.wav", + "weapons/csgo/negev/negev_coverdown.wav", + "weapons/csgo/negev/negev_coverup.wav", + "weapons/csgo/negev/negev_draw.wav", + "weapons/csgo/negev/negev_pump.wav", +} + +new const FLASHLIGHT_IMPULSE = 100 + +new Weapon:glock +new Weapon:usp +new Weapon:deagle +new Weapon:p90 +// m4a1s +new Weapon:m4a1 +new Weapon:ak47 +new Weapon:awp +new Weapon:negev + +public plugin_precache() { + register_plugin("[RZ] CS:GO Weapons", "1.0.0", "fl0wer") + +/* + glock = create_weapon("csgo_glock", weapon_type_secondary) + set_weapon_var(glock, weapon_view_model, "models/rz/glock/v_glock.mdl") + set_weapon_var(glock, weapon_player_model, "models/rz/glock/p_glock.mdl") + set_weapon_var(glock, weapon_world_model, "models/rz/glock/w_glock.mdl") + precache_sound(GLOCK_SHOOT_SOUND[0]) + precache_sound(GLOCK_SHOOT_SOUND[1]) + + usp = create_weapon("csgo_usp", weapon_type_secondary) + set_weapon_var(usp, weapon_view_model, "models/rz/usp/v_usp.mdl") + set_weapon_var(usp, weapon_player_model, "models/rz/usp/p_usp.mdl") + set_weapon_var(usp, weapon_world_model, "models/rz/usp/w_usp.mdl") + precache_sound(USP_SHOOT_SOUND[0]) + precache_sound(USP_SHOOT_SOUND[1]) +*/ + + createDeagle() + + createP90() + +/* + m4a1 = create_weapon("csgo_m4a1", weapon_type_primary) + set_weapon_var(m4a1, weapon_view_model, "models/rz/m4a1/v_m4a1.mdl") + set_weapon_var(m4a1, weapon_player_model, "models/rz/m4a1/p_m4a1.mdl") + set_weapon_var(m4a1, weapon_world_model, "models/rz/m4a1/w_m4a1.mdl") + precache_sound(M4A1_SHOOT_SOUND[0]) + precache_sound(M4A1_SHOOT_SOUND[1]) + + ak47 = create_weapon("csgo_ak47", weapon_type_primary) + set_weapon_var(ak47, weapon_view_model, "models/rz/ak47/v_ak47.mdl") + set_weapon_var(ak47, weapon_player_model, "models/rz/ak47/p_ak47.mdl") + set_weapon_var(ak47, weapon_world_model, "models/rz/ak47/w_ak47.mdl") + precache_sound(AK47_SHOOT_SOUND) + + awp = create_weapon("csgo_awp", weapon_type_primary) + set_weapon_var(awp, weapon_view_model, "models/rz/awp/v_awp.mdl") + set_weapon_var(awp, weapon_player_model, "models/rz/awp/p_awp.mdl") + set_weapon_var(awp, weapon_world_model, "models/rz/awp/w_awp.mdl") + set_weapon_var(awp, weapon_forward_deploy, "@AWP_Deploy") + set_weapon_var(awp, weapon_forward_primary_attack, "@AWP_PrimaryAttack") + set_weapon_var(awp, weapon_forward_secondary_attack, "@AWP_SecondaryAttack") + precache_sound(AWP_SHOOT_SOUND) + + negev = create_weapon("csgo_negev", weapon_type_primary) + set_weapon_var(negev, weapon_view_model, "models/rz/negev/v_negev.mdl") + set_weapon_var(negev, weapon_player_model, "models/rz/negev/p_negev.mdl") + set_weapon_var(negev, weapon_world_model, "models/rz/negev/w_negev.mdl") + precache_sound(NEGEV_SHOOT_SOUND) +*/ +} + +public plugin_init() { + //RegisterHookChain(RG_CBasePlayer_PreThink, "@CBasePlayer_PreTnink_Post", true) +} + +const DEAGLE_MAX_SPEED = 250 +const DEAGLE_WEIGHT = 7 +const DEAGLE_DAMAGE = 54 +const Float:DEAGLE_RANGE_MODIFER = 0.81 +const Float:DEAGLE_RELOAD_TIME = 2.2 +new const DEAGLE_SHOOT_SOUND[] = "weapons/csgo/deagle/deagle-1.wav" +new const DEAGLE_ADDITIONAL_SOUNDS[][] = { + "weapons/csgo/deagle/de_clipin.wav", + "weapons/csgo/deagle/de_clipout.wav", + "weapons/csgo/deagle/de_draw.wav", + "weapons/csgo/deagle/de_slideback.wav", + "weapons/csgo/deagle/de_slideforward.wav", + "weapons/csgo/deagle/deagle_special_lookat_f009.wav", + "weapons/csgo/deagle/deagle_special_lookat_f036.wav", + "weapons/csgo/deagle/deagle_special_lookat_f057.wav", + "weapons/csgo/deagle/deagle_special_lookat_f081.wav", + "weapons/csgo/deagle/deagle_special_lookat_f111.wav", + "weapons/csgo/deagle/deagle_special_lookat_f133.wav", + "weapons/csgo/deagle/deagle_special_lookat_f166.wav", + "weapons/csgo/deagle/deagle_special_lookat_f193.wav", + "weapons/csgo/deagle/deagle_special_lookat_f228.wav", +} + +enum { + DEAGLE_IDLE, + DEAGLE_SHOOT1, + DEAGLE_SHOOT2, + DEAGLE_SHOOT_EMPTY, + DEAGLE_RELOAD, + DEAGLE_DRAW, +} + +createDeagle() { + new Weapon:weapon = create_weapon("csgo_deagle", weapon_type_secondary) + set_weapon_var(weapon, "name", "DEFAULT_DEAGLE") + set_weapon_var(weapon, "view_model", create_model("rezombie/weapons/deagle/v_deagle.mdl")) + set_weapon_var(weapon, "player_model", create_model("rezombie/weapons/deagle/p_deagle.mdl")) + set_weapon_var(weapon, "world_model", create_model("rezombie/weapons/deagle/w_deagle.mdl")) + set_weapon_var(weapon, "hud", "weapon_deagle") + set_weapon_var(weapon, "max_clip", 7) + set_weapon_var(weapon, "max_ammo", 35) + set_weapon_var(weapon, "slot", PISTOL_SLOT) + set_weapon_var(weapon, "weight", DEAGLE_WEIGHT) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@Deagle_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@Deagle_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@Deagle_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@Deagle_Reload") + set_weapon_var(weapon, "forward_idle", "@Deagle_Idle") + precache_sound(DEAGLE_SHOOT_SOUND) + precache_sounds(DEAGLE_ADDITIONAL_SOUNDS) +} + +@Deagle_Deploy(weapon, player) { + set_member(weapon, m_Weapon_flAccuracy, 0.9) + return weapon_default_deploy(weapon, player, DEAGLE_DRAW, "onehanded") +} + +@Deagle_MaxSpeed(weapon, player) { + return DEAGLE_MAX_SPEED +} + +@Deagle_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.5 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.25 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.115 * (1.0 - accuracy) + } else { + spread = 0.13 * (1.0 - accuracy) + } + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + set_member(weapon, m_Weapon_iShotsFired, ++shotsFired) + if (shotsFired > 1) { + return + } + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:time = get_gametime() + if (lastFire != 0.0) { + accuracy -= (0.4 - (time - lastFire)) * 0.35 + if (accuracy > 0.9) { + accuracy = 0.9 + } else if (accuracy < 0.55) { + accuracy = 0.55 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, NORMAL_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + player, // if it's inflictor, maybe weapon? + player, + src, + aiming, + spread, + 4096.0, + 2, + BULLET_PLAYER_50AE, + DEAGLE_DAMAGE, + DEAGLE_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + send_weapon_anim(player, clip ? random_num(DEAGLE_SHOOT1, DEAGLE_SHOOT2) : DEAGLE_SHOOT_EMPTY) + playFireSound(player, DEAGLE_SHOOT_SOUND) + new Float:nextAttack = 0.3 - 0.075 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.8) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} + +@Deagle_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, DEAGLE_RELOAD, DEAGLE_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_flAccuracy, 0.9) +} + +@Deagle_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, DEAGLE_IDLE) +} + +const P90_MAX_SPEED = 230 +const P90_WEIGHT = 26 +const P90_DAMAGE = 25 +const Float:P90_RANGE_MODIFER = 0.86 +const Float:P90_RELOAD_TIME = 3.4 +const Float:P90_BASE_ACCURACY = 0.2 +const Float:P90_ACCURACY_DIVISOR = 175.0 +const Float:P90_INSPECT_TIME = 5.37 +new const P90_SHOOT_SOUND[] = "weapons/csgo/p90/p90-1.wav" +new const P90_ADDITIONAL_SOUNDS[][] = { + "weapons/csgo/p90/p90_boltback.wav", + "weapons/csgo/p90/p90_boltforward.wav", + "weapons/csgo/p90/p90_cliphit.wav", + "weapons/csgo/p90/p90_clipin.wav", + "weapons/csgo/p90/p90_clipout.wav", + "weapons/csgo/p90/p90_cliprelease.wav", + "weapons/csgo/p90/p90_draw.wav", +} + +enum { + P90_IDLE, + P90_RELOAD, + P90_DRAW, + P90_SHOOT1, + P90_SHOOT2, + P90_SHOOT3, + P90_INSPECT, +} + +createP90() { + new Weapon:weapon = create_weapon("csgo_p90", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_P90") + set_weapon_var(weapon, "view_model", create_model("rezombie/weapons/p90/v_p90.mdl")) + set_weapon_var(weapon, "player_model", create_model("rezombie/weapons/p90/p_p90.mdl")) + set_weapon_var(weapon, "world_model", create_model("rezombie/weapons/p90/w_p90.mdl")) + set_weapon_var(weapon, "hud", "weapon_p90") + set_weapon_var(weapon, "max_clip", 50) + set_weapon_var(weapon, "max_ammo", 100) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", P90_WEIGHT) + set_weapon_var(weapon, "base_accuracy", P90_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size7) + set_weapon_var(weapon, "forward_deploy", "@P90_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@P90_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@P90_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@P90_Reload") + set_weapon_var(weapon, "forward_idle", "@P90_Idle") + precache_sound(P90_SHOOT_SOUND) + precache_sounds(P90_ADDITIONAL_SOUNDS) +} + +@P90_Deploy(weapon, player) { + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_flAccuracy, P90_BASE_ACCURACY) + return weapon_default_deploy(weapon, player, P90_DRAW, "carbine") +} + +@P90_MaxSpeed(weapon, player) { + return P90_MAX_SPEED +} + +@P90_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + new Float:playerVelocityLength = playerVelocityLength2d(player) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.3 * accuracy + } else if (playerVelocityLength > 170.0) { + spread = 0.115 * accuracy + } else { + spread = 0.045 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = (shotsFired * shotsFired / P90_ACCURACY_DIVISOR) + 0.45 + if (accuracy > 1.0) { + accuracy = 1.0 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + player, // if it's inflictor, maybe weapon? + player, + src, + aiming, + spread, + 8192.0, + 2, + BULLET_PLAYER_57MM, + P90_DAMAGE, + P90_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(P90_SHOOT1, P90_SHOOT3)) + playFireSound(player, P90_SHOOT_SOUND) + new Float:nextAttack = 0.066 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 0.9, 0.45, 0.35, 0.04, 5.25, 3.5, 4) + } else if (playerVelocityLength > 0.0) { + weapon_kick_back(weapon, player, 0.45, 0.3, 0.2, 0.0275, 4.0, 2.25, 7) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.275, 0.2, 0.125, 0.02, 3.0, 1.0, 9) + } else { + weapon_kick_back(weapon, player, 0.3, 0.225, 0.125, 0.02, 3.25, 1.25, 8) + } +} + +@P90_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, P90_RELOAD, P90_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, P90_BASE_ACCURACY) +} + +@P90_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, P90_IDLE) +} + +@CBasePlayer_PreTnink_Post(player) { + if (!is_user_alive(player)) { + return + } + if (get_entvar(player, var_impulse) != FLASHLIGHT_IMPULSE) { + return + } + set_entvar(player, var_impulse, 0) + if (get_member(player, m_iFOV) != DEFAULT_NO_ZOOM) { + return + } + new activeItem = get_member(player, m_pActiveItem) + if (is_nullent(activeItem)) { + return + } + if (get_member(activeItem, m_Weapon_fInReload) || get_member(activeItem, m_Weapon_fInSpecialReload)) { + return + } + new Weapon:impulse = get_entvar(activeItem, var_impulse) + new animNumber + new Float:animTime + if (impulse == glock) { + animNumber = 13 + animTime = 6.47 + } else if (impulse == usp) { + animNumber = get_member(activeItem, m_Weapon_iWeaponState) ? 16 : 17 + animTime = 6.45 + } else if (impulse == deagle) { + animNumber = 6 + animTime = 5.7 // two + } else if (impulse == p90) { + animNumber = P90_INSPECT + animTime = P90_INSPECT_TIME + } else if (impulse == m4a1) { + animNumber = get_member(activeItem, m_Weapon_iWeaponState) ? 14 : 15 + animTime = 5.34 + } else if (impulse == ak47) { + animNumber = 6 + animTime = 4.6 + } else if (impulse == awp) { + animNumber = 6 + animTime = 5.0 + } else if (impulse == negev) { + animNumber = 5 + animTime = 6.9 + } else { + return + } + if (get_entvar(player, var_weaponanim) != animNumber) { + set_member(activeItem, m_Weapon_flTimeWeaponIdle, animTime) + send_weapon_anim(player, animNumber) + } +} diff --git a/extra/addons/amxmodx/scripting/rezombie/weapons/default_weapons.sma b/extra/addons/amxmodx/scripting/rezombie/weapons/default_weapons.sma new file mode 100644 index 0000000..c8cf879 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/weapons/default_weapons.sma @@ -0,0 +1,3846 @@ +#include +#include +#include +#include +#include + +// rework fire anim with empty +// muzzeflash +// decals +// eject brass + +public plugin_precache() { + register_plugin("Default Weapons Pack", "1.0.0", "fl0wer") + add_translate("weapons/default") + + createGlock18() + createUSP() + createP228() + createFiveSeven() + createDeagle() + createElite() + + createM3() + createXM1014() + + createMAC10() + createTMP() + createMP5() + createUMP45() + createP90() + + createGalil() + createFamas() + createAK47() + createM4A1() + createSG552() + createAUG() + + createScout() + createAWP() + createG3SG1() + createSG550() + + createM249() + + createHeGrenade() +} + +const GLOCK18_MAX_SPEED = 250 +const GLOCK18_WEIGHT = 5 +const GLOCK18_DAMAGE = 25 +const GLOCK18_DAMAGE_BURST = 18 +const Float:GLOCK18_RANGE_MODIFER = 0.75 +const Float:GLOCK18_RANGE_MODIFER_BURST = 0.9 +const Float:GLOCK18_RELOAD_TIME = 2.2 +new const GLOCK18_SHOOT_SOUND[2][] = { + "weapons/glock18-1.wav", + "weapons/glock18-2.wav", +} + +enum { + GLOCK18_IDLE1, + GLOCK18_IDLE2, + GLOCK18_IDLE3, + GLOCK18_SHOOT1, + GLOCK18_SHOOT2, + GLOCK18_SHOOT3, + GLOCK18_SHOOT_EMPTY, + GLOCK18_RELOAD, + GLOCK18_DRAW, + GLOCK18_HOLSTER, + GLOCK18_ADD_SILENCER, + GLOCK18_DRAW2, + GLOCK18_RELOAD2, +} + +createGlock18() { + new Weapon:weapon = create_weapon("default_glock18", weapon_type_secondary) + set_weapon_var(weapon, "name", "DEFAULT_GLOCK18") + set_weapon_var(weapon, "view_model", create_model("models/v_glock18.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_glock18.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_glock18.mdl")) + set_weapon_var(weapon, "hud", "weapon_glock18") + set_weapon_var(weapon, "max_clip", 20) + set_weapon_var(weapon, "max_ammo", 120) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", GLOCK18_WEIGHT) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@Glock18_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@Glock18_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@Glock18_PrimaryAttack") + set_weapon_var(weapon, "forward_fire_remaining", "@Glock18_FireRemaining") + set_weapon_var(weapon, "forward_secondary_attack", "@Glock18_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@Glock18_Reload") + set_weapon_var(weapon, "forward_idle", "@Glock18_Idle") + precache_sounds(GLOCK18_SHOOT_SOUND) +} + +@Glock18_Deploy(weapon, player) { + set_member(weapon, m_Weapon_flAccuracy, 0.9) + set_member(weapon, m_Weapon_iRemainingShotsFired, 0) + set_member(weapon, m_Weapon_flNextRemainingShoot, 0.0) + new anim = random_num(0, 1) ? GLOCK18_DRAW : GLOCK18_DRAW2 + return weapon_default_deploy(weapon, player, anim, "onehanded") +} + +@Glock18_MaxSpeed(weapon, player) { + return GLOCK18_MAX_SPEED +} + +@Glock18_PrimaryAttack(weapon, player, clip, ammo) { + new bool:isBurstMode = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_GLOCK18_BURST_MODE) ? true : false + new Float:nextAttack = isBurstMode ? 0.5 : (0.2 - 0.05) + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (isBurstMode) { + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.2 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.185 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.095 * (1.0 - accuracy) + } else { + spread = 0.3 * (1.0 - accuracy) + } + } else { + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.0 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.165 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.075 * (1.0 - accuracy) + } else { + spread = 0.1 * (1.0 - accuracy) + } + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + set_member(weapon, m_Weapon_iShotsFired, ++shotsFired) + if (shotsFired > 1) { + return + } + } + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:time = get_gametime() + if (lastFire != 0.0) { + accuracy -= (0.325 - (time - lastFire)) * 0.275 + if (accuracy > 0.9) { + accuracy = 0.9 + } else if (accuracy < 0.6) { + accuracy = 0.6 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, NORMAL_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 1, + BULLET_PLAYER_9MM, + GLOCK18_DAMAGE, + GLOCK18_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + if (isBurstMode) { + send_weapon_anim(player, clip ? GLOCK18_SHOOT1 : GLOCK18_SHOOT_EMPTY) + playFireSound(player, GLOCK18_SHOOT_SOUND[0]) + } else { + send_weapon_anim(player, clip ? GLOCK18_SHOOT3 : GLOCK18_SHOOT_EMPTY) + playFireSound(player, GLOCK18_SHOOT_SOUND[1]) + } + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.5) + if (isBurstMode) { + set_member(weapon, m_Weapon_iRemainingShotsFired, 1) + set_member(weapon, m_Weapon_flNextRemainingShoot, time + 0.1) + } +} + +@Glock18_FireRemaining(weapon, player, clip, shotsFired) { + // refactoring from 1 to 3 + if (--clip < 0) { + set_member(weapon, m_Weapon_iClip, 0) + set_member(weapon, m_Weapon_iRemainingShotsFired, 3) + set_member(weapon, m_Weapon_flNextRemainingShoot, 0.0) + return + } + set_member(weapon, m_Weapon_iClip, clip) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + 0.05, + 8192.0, + 1, + BULLET_PLAYER_9MM, + GLOCK18_DAMAGE_BURST, + GLOCK18_RANGE_MODIFER_BURST, + true, + get_member(player, random_seed) + ) + send_weapon_anim(player, clip ? GLOCK18_SHOOT1 : GLOCK18_SHOOT_EMPTY) + playFireSound(player, GLOCK18_SHOOT_SOUND[0]) + set_member(weapon, m_Weapon_iRemainingShotsFired, ++shotsFired) + if (shotsFired != 3) { + set_member(weapon, m_Weapon_flNextRemainingShoot, get_gametime() + 0.1) + } else { + set_member(weapon, m_Weapon_flNextRemainingShoot, 0.0) + } +} + +@Glock18_SecondaryAttack(weapon, player, WeaponState:weaponState) { + if (weaponState & WPNSTATE_GLOCK18_BURST_MODE) { + set_member(weapon, m_Weapon_iWeaponState, weaponState & ~WPNSTATE_GLOCK18_BURST_MODE) + client_print(player, print_center, "#Cstrike_TitlesTXT_Switch_To_SemiAuto") + } else { + set_member(weapon, m_Weapon_iWeaponState, weaponState | WPNSTATE_GLOCK18_BURST_MODE) + client_print(player, print_center, "#Cstrike_TitlesTXT_Switch_To_BurstFire") + } + set_member(weapon, m_Weapon_flNextSecondaryAttack, 0.3) +} + +@Glock18_Reload(weapon, player) { + new anim = random_num(0, 1) ? GLOCK18_RELOAD : GLOCK18_RELOAD2 + if (!weapon_default_reload(weapon, player, anim, GLOCK18_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_flAccuracy, 0.9) +} + +@Glock18_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + if (!get_member(weapon, m_Weapon_iClip)) { + return + } + new Float:random = random_float(0.0, 1.0) + new anim + new Float:time + if (random <= 0.3) { + anim = GLOCK18_IDLE3 + time = 3.0625 + } else if (random <= 0.6) { + anim = GLOCK18_IDLE1 + time = 3.75 + } else { + anim = GLOCK18_IDLE2 + time = 2.5 + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, time) + send_weapon_anim(player, anim) +} + +const USP_MAX_SPEED = 250 +const USP_WEIGHT = 5 +const USP_DAMAGE = 34 +const USP_DAMAGE_SILENCER = 30 +const Float:USP_RANGE_MODIFER = 0.79 +const Float:USP_RELOAD_TIME = 2.7 +const Float:USP_ADJUST_SILENCER_TIME = 3.13 +new const USP_SHOOT_SOUND[3][] = { + "weapons/usp1.wav", + "weapons/usp1.wav", + "weapons/usp_unsil-1.wav", +} + +enum { + USP_SILENCER_IDLE, + USP_SILENCER_SHOOT1, + USP_SILENCER_SHOOT2, + USP_SILENCER_SHOOT3, + USP_SILENCER_SHOOT_EMPTY, + USP_SILENCER_RELOAD, + USP_SILENCER_DRAW, + USP_ATTACH_SILENCER, + USP_IDLE, + USP_SHOOT1, + USP_SHOOT2, + USP_SHOOT3, + USP_SHOOT_EMPTY, + USP_RELOAD, + USP_DRAW, + USP_DETACH_SILENCER, +} + +createUSP() { + new Weapon:weapon = create_weapon("default_usp", weapon_type_secondary) + set_weapon_var(weapon, "name", "DEFAULT_USP") + set_weapon_var(weapon, "view_model", create_model("models/v_usp.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_usp.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_usp.mdl")) + set_weapon_var(weapon, "hud", "weapon_usp") + set_weapon_var(weapon, "max_clip", 12) + set_weapon_var(weapon, "max_ammo", 100) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", USP_WEIGHT) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@USP_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@USP_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@USP_PrimaryAttack") + set_weapon_var(weapon, "forward_secondary_attack", "@USP_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@USP_Reload") + set_weapon_var(weapon, "forward_idle", "@USP_Idle") + precache_sounds(USP_SHOOT_SOUND) +} + +@USP_Deploy(weapon, player) { + set_member(weapon, m_Weapon_flAccuracy, 0.92) + new anim = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_USP_SILENCED) ? USP_SILENCER_DRAW : USP_DRAW + return weapon_default_deploy(weapon, player, anim, "onehanded") +} + +@USP_MaxSpeed(weapon, player) { + return USP_MAX_SPEED +} + +@USP_PrimaryAttack(weapon, player, clip, ammo) { + new bool:isSilenced = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_USP_SILENCED) ? true : false + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (isSilenced) { + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.3 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.25 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.125 * (1.0 - accuracy) + } else { + spread = 0.15 * (1.0 - accuracy) + } + } else { + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.2 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.225 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.08 * (1.0 - accuracy) + } else { + spread = 0.1 * (1.0 - accuracy) + } + } + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + set_member(weapon, m_Weapon_iShotsFired, ++shotsFired) + if (shotsFired > 1) { + return + } + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:time = get_gametime() + if (lastFire != 0.0) { + accuracy -= (0.3 - (time - lastFire)) * 0.275 + if (accuracy > 0.92) { + accuracy = 0.92 + } else if (accuracy < 0.6) { + accuracy = 0.6 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 4096.0, + 1, + BULLET_PLAYER_45ACP, + isSilenced ? USP_DAMAGE_SILENCER : USP_DAMAGE, + USP_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + if (isSilenced) { + send_weapon_anim(player, clip ? random_num(USP_SILENCER_SHOOT1, USP_SILENCER_SHOOT3) : USP_SILENCER_SHOOT_EMPTY) + playFireSound(player, USP_SHOOT_SOUND[random_num(0, 1)]) + } else { + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + send_weapon_anim(player, clip ? random_num(USP_SHOOT1, USP_SHOOT3) : USP_SHOOT_EMPTY) + playFireSound(player, USP_SHOOT_SOUND[2]) + } + new Float:nextAttack = 0.225 - 0.075 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} + +@USP_SecondaryAttack(weapon, player, WeaponState:weaponState) { + if (weaponState & WPNSTATE_USP_SILENCED) { + set_member(weapon, m_Weapon_iWeaponState, weaponState & ~WPNSTATE_USP_SILENCED) + send_weapon_anim(player, USP_DETACH_SILENCER) + } else { + set_member(weapon, m_Weapon_iWeaponState, weaponState | WPNSTATE_USP_SILENCED) + send_weapon_anim(player, USP_ATTACH_SILENCER) + } + set_member(weapon, m_Weapon_flNextPrimaryAttack, USP_ADJUST_SILENCER_TIME) + set_member(weapon, m_Weapon_flNextSecondaryAttack, USP_ADJUST_SILENCER_TIME) + set_member(weapon, m_Weapon_flTimeWeaponIdle, USP_ADJUST_SILENCER_TIME) +} + +@USP_Reload(weapon, player) { + new anim = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_USP_SILENCED) ? USP_SILENCER_RELOAD : USP_RELOAD + if (!weapon_default_reload(weapon, player, anim, USP_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_flAccuracy, 0.92) +} + +@USP_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + if (!get_member(weapon, m_Weapon_iClip)) { + return + } + new anim = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_USP_SILENCED) ? USP_SILENCER_IDLE : USP_IDLE + set_member(weapon, m_Weapon_flTimeWeaponIdle, 60.0) + send_weapon_anim(player, anim) +} + +const P228_MAX_SPEED = 250 +const P228_WEIGHT = 5 +const P228_DAMAGE = 32 +const Float:P228_RANGE_MODIFER = 0.8 +const Float:P228_RELOAD_TIME = 2.7 +new const P228_SHOOT_SOUND[] = "weapons/p228-1.wav" + +enum { + P228_IDLE, + P228_SHOOT1, + P228_SHOOT2, + P228_SHOOT3, + P228_SHOOT_EMPTY, + P228_RELOAD, + P228_DRAW, +} + +createP228() { + new Weapon:weapon = create_weapon("default_p228", weapon_type_secondary) + set_weapon_var(weapon, "name", "DEFAULT_P228") + set_weapon_var(weapon, "view_model", create_model("models/v_p228.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_p228.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_p228.mdl")) + set_weapon_var(weapon, "hud", "weapon_p228") + set_weapon_var(weapon, "max_clip", 13) + set_weapon_var(weapon, "max_ammo", 52) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", P228_WEIGHT) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@P228_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@P228_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@P228_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@P228_Reload") + set_weapon_var(weapon, "forward_idle", "@P228_Idle") + precache_sound(P228_SHOOT_SOUND) +} + +@P228_Deploy(weapon, player) { + set_member(weapon, m_Weapon_flAccuracy, 0.9) + return weapon_default_deploy(weapon, player, P228_DRAW, "onehanded") +} + +@P228_MaxSpeed(weapon, player) { + return P228_MAX_SPEED +} + +@P228_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.5 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.255 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.075 * (1.0 - accuracy) + } else { + spread = 0.15 * (1.0 - accuracy) + } + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + set_member(weapon, m_Weapon_iShotsFired, ++shotsFired) + if (shotsFired > 1) { + return + } + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:time = get_gametime() + if (lastFire != 0.0) { + accuracy -= (0.325 - (time - lastFire)) * 0.3 + if (accuracy > 0.9) { + accuracy = 0.9 + } else if (accuracy < 0.6) { + accuracy = 0.6 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 4096.0, + 1, + BULLET_PLAYER_357SIG, + P228_DAMAGE, + P228_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + send_weapon_anim(player, clip ? random_num(P228_SHOOT1, P228_SHOOT3) : P228_SHOOT_EMPTY) + playFireSound(player, P228_SHOOT_SOUND) + new Float:nextAttack = 0.2 - 0.05 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} + +@P228_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, P228_RELOAD, P228_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_flAccuracy, 0.9) +} + +@P228_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + if (!get_member(weapon, m_Weapon_iClip)) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 3.0625) + send_weapon_anim(player, P228_IDLE) +} + +const FIVESEVEN_MAX_SPEED = 250 +const FIVESEVEN_WEIGHT = 5 +const FIVESEVEN_DAMAGE = 20 +const Float:FIVESEVEN_RANGE_MODIFER = 0.885 +const Float:FIVESEVEN_RELOAD_TIME = 2.7 +new const FIVESEVEN_SHOOT_SOUND[] = "weapons/fiveseven-1.wav" + +enum { + FIVESEVEN_IDLE, + FIVESEVEN_SHOOT1, + FIVESEVEN_SHOOT2, + FIVESEVEN_SHOOT_EMPTY, + FIVESEVEN_RELOAD, + FIVESEVEN_DRAW, +} + +createFiveSeven() { + new Weapon:weapon = create_weapon("default_fiveseven", weapon_type_secondary) + set_weapon_var(weapon, "name", "DEFAULT_FIVESEVEN") + set_weapon_var(weapon, "view_model", create_model("models/v_fiveseven.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_fiveseven.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_fiveseven.mdl")) + set_weapon_var(weapon, "hud", "weapon_fiveseven") + set_weapon_var(weapon, "max_clip", 20) + set_weapon_var(weapon, "max_ammo", 100) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", FIVESEVEN_WEIGHT) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@FiveSeven_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@FiveSeven_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@FiveSeven_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@FiveSeven_Reload") + set_weapon_var(weapon, "forward_idle", "@FiveSeven_Idle") + precache_sound(P228_SHOOT_SOUND) +} + +@FiveSeven_Deploy(weapon, player) { + set_member(weapon, m_Weapon_flAccuracy, 0.92) + return weapon_default_deploy(weapon, player, FIVESEVEN_DRAW, "onehanded") +} + +@FiveSeven_MaxSpeed(weapon, player) { + return FIVESEVEN_MAX_SPEED +} + +@FiveSeven_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.5 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.255 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.075 * (1.0 - accuracy) + } else { + spread = 0.15 * (1.0 - accuracy) + } + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + set_member(weapon, m_Weapon_iShotsFired, ++shotsFired) + if (shotsFired > 1) { + return + } + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:time = get_gametime() + if (lastFire != 0.0) { + accuracy -= (0.275 - (time - lastFire)) * 0.25 + if (accuracy > 0.92) { + accuracy = 0.92 + } else if (accuracy < 0.725) { + accuracy = 0.725 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 4096.0, + 1, + BULLET_PLAYER_57MM, + FIVESEVEN_DAMAGE, + FIVESEVEN_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, clip ? random_num(FIVESEVEN_SHOOT1, FIVESEVEN_SHOOT2) : FIVESEVEN_SHOOT_EMPTY) + playFireSound(player, FIVESEVEN_SHOOT_SOUND) + new Float:nextAttack = 0.2 - 0.05 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} + +@FiveSeven_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, FIVESEVEN_RELOAD, FIVESEVEN_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_flAccuracy, 0.92) +} + +@FiveSeven_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + if (!get_member(weapon, m_Weapon_iClip)) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 3.0625) + send_weapon_anim(player, FIVESEVEN_IDLE) +} + +const DEAGLE_MAX_SPEED = 250 +const DEAGLE_WEIGHT = 7 +const DEAGLE_DAMAGE = 54 +const Float:DEAGLE_RANGE_MODIFER = 0.81 +const Float:DEAGLE_RELOAD_TIME = 2.2 +new const DEAGLE_SHOOT_SOUND[2][] = { + "weapons/deagle-1.wav", + "weapons/deagle-2.wav", +} + +enum { + DEAGLE_IDLE, + DEAGLE_SHOOT1, + DEAGLE_SHOOT2, + DEAGLE_SHOOT_EMPTY, + DEAGLE_RELOAD, + DEAGLE_DRAW, +} + +createDeagle() { + new Weapon:weapon = create_weapon("default_deagle", weapon_type_secondary) + set_weapon_var(weapon, "name", "DEFAULT_DEAGLE") + set_weapon_var(weapon, "view_model", create_model("models/v_deagle.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_deagle.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_deagle.mdl")) + set_weapon_var(weapon, "hud", "weapon_deagle") + set_weapon_var(weapon, "max_clip", 7) + set_weapon_var(weapon, "max_ammo", 35) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", DEAGLE_WEIGHT) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@Deagle_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@Deagle_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@Deagle_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@Deagle_Reload") + set_weapon_var(weapon, "forward_idle", "@Deagle_Idle") + precache_sounds(DEAGLE_SHOOT_SOUND) +} + +@Deagle_Deploy(weapon, player) { + set_member(weapon, m_Weapon_flAccuracy, 0.9) + return weapon_default_deploy(weapon, player, DEAGLE_DRAW, "onehanded") +} + +@Deagle_MaxSpeed(weapon, player) { + return DEAGLE_MAX_SPEED +} + +@Deagle_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.5 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.25 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.115 * (1.0 - accuracy) + } else { + spread = 0.13 * (1.0 - accuracy) + } + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + set_member(weapon, m_Weapon_iShotsFired, ++shotsFired) + if (shotsFired > 1) { + return + } + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:time = get_gametime() + if (lastFire != 0.0) { + accuracy -= (0.4 - (time - lastFire)) * 0.35 + if (accuracy > 0.9) { + accuracy = 0.9 + } else if (accuracy < 0.55) { + accuracy = 0.55 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, NORMAL_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 4096.0, + 2, + BULLET_PLAYER_50AE, + DEAGLE_DAMAGE, + DEAGLE_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + send_weapon_anim(player, clip ? random_num(DEAGLE_SHOOT1, DEAGLE_SHOOT2) : DEAGLE_SHOOT_EMPTY) + playFireSound(player, DEAGLE_SHOOT_SOUND[random(sizeof(DEAGLE_SHOOT_SOUND))]) + new Float:nextAttack = 0.3 - 0.075 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.8) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} + +@Deagle_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, DEAGLE_RELOAD, DEAGLE_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_flAccuracy, 0.9) +} + +@Deagle_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, DEAGLE_IDLE) +} + +const ELITE_MAX_SPEED = 250 +const ELITE_WEIGHT = 5 +const ELITE_DAMAGE = 36 +const Float:ELITE_RANGE_MODIFER = 0.75 +const Float:ELITE_RELOAD_TIME = 4.5 +new const ELITE_SHOOT_SOUND[] = "weapons/elite_fire.wav" + +enum { + ELITE_IDLE, + ELITE_IDLE_LEFTEMPTY, + ELITE_SHOOTLEFT1, + ELITE_SHOOTLEFT2, + ELITE_SHOOTLEFT3, + ELITE_SHOOTLEFT4, + ELITE_SHOOTLEFT5, + ELITE_SHOOTLEFTLAST, + ELITE_SHOOTRIGHT1, + ELITE_SHOOTRIGHT2, + ELITE_SHOOTRIGHT3, + ELITE_SHOOTRIGHT4, + ELITE_SHOOTRIGHT5, + ELITE_SHOOTRIGHTLAST, + ELITE_RELOAD, + ELITE_DRAW, +} + +createElite() { + new Weapon:weapon = create_weapon("default_elite", weapon_type_secondary) + set_weapon_var(weapon, "name", "DEFAULT_ELITE") + set_weapon_var(weapon, "view_model", create_model("models/v_elite.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_elite.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_elite.mdl")) + set_weapon_var(weapon, "hud", "weapon_elite") + set_weapon_var(weapon, "max_clip", 30) + set_weapon_var(weapon, "max_ammo", 120) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", ELITE_WEIGHT) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size4) + set_weapon_var(weapon, "forward_deploy", "@Elite_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@Elite_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@Elite_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@Elite_Reload") + set_weapon_var(weapon, "forward_idle", "@Elite_Idle") + precache_sound(ELITE_SHOOT_SOUND) +} + +@Elite_Deploy(weapon, player) { + set_member(weapon, m_Weapon_flAccuracy, 0.88) + if (!(get_member(weapon, m_Weapon_iClip) & 1)) { + set_member(weapon, m_Weapon_iWeaponState, WPNSTATE_ELITE_LEFT) + } + return weapon_default_deploy(weapon, player, ELITE_DRAW, "dualpistols") +} + +@Elite_MaxSpeed(weapon, player) { + return ELITE_MAX_SPEED +} + +@Elite_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.3 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.175 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.08 * (1.0 - accuracy) + } else { + spread = 0.1 * (1.0 - accuracy) + } + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + set_member(weapon, m_Weapon_iShotsFired, ++shotsFired) + if (shotsFired > 1) { + return + } + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:time = get_gametime() + if (lastFire != 0.0) { + accuracy -= (0.325 - (time - lastFire)) * 0.275 + if (accuracy > 0.88) { + accuracy = 0.88 + } else if (accuracy < 0.55) { + accuracy = 0.55 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new WeaponState:weaponState = get_member(weapon, m_Weapon_iWeaponState) + new Float:aiming[3] + new Float:src[3] + new Float:viewRight[3] + getGunPositionAndAiming(player, src, aiming) + global_get(glb_v_right, viewRight) + if (weaponState & WPNSTATE_ELITE_LEFT) { + rg_set_animation(player, PLAYER_ATTACK1) + set_member(weapon, m_Weapon_iWeaponState, weaponState & ~WPNSTATE_ELITE_LEFT) + for (new i = 0; i < sizeof(src); ++i) { + src[i] -= viewRight[i] * 5.0 + } + send_weapon_anim(player, random_num(ELITE_SHOOTLEFT1, ELITE_SHOOTLEFT4)) + } else { + rg_set_animation(player, PLAYER_ATTACK2) + set_member(weapon, m_Weapon_iWeaponState, weaponState | WPNSTATE_ELITE_LEFT) + for (new i = 0; i < sizeof(src); ++i) { + src[i] += viewRight[i] * 5.0 + } + send_weapon_anim(player, random_num(ELITE_SHOOTRIGHT1, ELITE_SHOOTRIGHT4)) + } + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 1, + BULLET_PLAYER_9MM, + ELITE_DAMAGE, + ELITE_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + playFireSound(player, ELITE_SHOOT_SOUND) + new Float:nextAttack = 0.2 - 0.078 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} + +@Elite_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, ELITE_RELOAD, ELITE_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_flAccuracy, 0.88) +} + +@Elite_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + new clip = get_member(weapon, m_Weapon_iClip) + if (!clip) { + return + } + new anim = (clip == 1) ? ELITE_IDLE_LEFTEMPTY : ELITE_IDLE + set_member(weapon, m_Weapon_flTimeWeaponIdle, 60.0) + send_weapon_anim(player, anim) +} + +const M3_MAX_SPEED = 230 +const M3_WEIGHT = 20 +const M3_DAMAGE = 20 +new Float:M3_CONE_VECTOR[3] = { 0.0675, 0.0675, 0.0 } +new const M3_SHOOT_SOUND[] = "weapons/m3-1.wav" + +enum { + M3_IDLE, + M3_SHOOT1, + M3_SHOOT2, + M3_RELOAD, + M3_PUMP, + M3_START_RELOAD, + M3_DRAW, + M3_HOLSTER, +} + +createM3() { + new Weapon:weapon = create_weapon("default_m3", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_M3") + set_weapon_var(weapon, "view_model", create_model("models/v_m3.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_m3.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_m3.mdl")) + set_weapon_var(weapon, "hud", "weapon_m3") + set_weapon_var(weapon, "max_clip", 8) + set_weapon_var(weapon, "max_ammo", 32) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", M3_WEIGHT) + set_weapon_var(weapon, "flags", ITEM_FLAG_NOFIREUNDERWATER) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@M3_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@M3_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@M3_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@M3_Reload") + set_weapon_var(weapon, "forward_idle", "@M3_Idle") + precache_sound(M3_SHOOT_SOUND) +} + +@M3_Deploy(weapon, player) { + return weapon_default_deploy(weapon, player, M3_DRAW, "shotgun") +} + +@M3_MaxSpeed(weapon, player) { + return M3_MAX_SPEED +} + +/* +BOOL CM3::PlayEmptySound() +{ + BOOL result = CBasePlayerWeapon::PlayEmptySound(); + m_iPlayEmptySound = 0; + return result; +} +*/ + +@M3_PrimaryAttack(weapon, player, clip, ammo) { + if (isEmptyFire(weapon, clip, true)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, LOUD_GUN_VOLUME) + set_member(player, m_iWeaponFlash, BRIGHT_GUN_FLASH) + set_member(player, m_flEjectBrass, get_gametime() + 0.45) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_buckshots( + weapon, + player, + 9, + src, + aiming, + M3_CONE_VECTOR, + 3000.0, + 0, + M3_DAMAGE + ) + send_weapon_anim(player, random_num(M3_SHOOT1, M3_SHOOT2)) + playFireSound(player, M3_SHOOT_SOUND) + new Float:nextAttack = 0.875 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, clip ? 2.5 : 0.875) + set_member(weapon, m_Weapon_fInSpecialReload, 0) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + if (get_entvar(player, var_flags) & FL_ONGROUND) { + punchAngle[0] -= random_float(4.0, 6.0) + } else { + punchAngle[0] -= random_float(8.0, 11.0) + } + set_entvar(player, var_punchangle, punchAngle) +} + +@M3_Reload(weapon, player) { + weapon_default_shotgun_reload( + weapon, + player, + M3_RELOAD, + M3_START_RELOAD, + 0.45, + 0.55 + ) +} + +@M3_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + //if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) + if (Float:get_member(weapon, m_Weapon_flTimeWeaponIdle) > 0.0) { + return + } + new maxClip = rg_get_iteminfo(weapon, ItemInfo_iMaxClip) + new ammo = get_player_var(player, "ammo", weapon) + if (!get_member(weapon, m_Weapon_iClip) && !get_member(weapon, m_Weapon_fInSpecialReload) && ammo) { + ExecuteHamB(Ham_Weapon_Reload, weapon) + } else if (get_member(weapon, m_Weapon_fInSpecialReload)) { + if (get_member(weapon, m_Weapon_iClip) != maxClip && ammo) { + ExecuteHamB(Ham_Weapon_Reload, weapon) + } else { + set_member(weapon, m_Weapon_fInSpecialReload, 0) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.5) + send_weapon_anim(player, M3_PUMP) + } + } else { + send_weapon_anim(player, M3_IDLE) + } +} + +const XM1014_MAX_SPEED = 240 +const XM1014_WEIGHT = 20 +const XM1014_DAMAGE = 20 +new Float:XM1014_CONE_VECTOR[3] = { 0.0725, 0.0725, 0.0 } +new const XM1014_SHOOT_SOUND[] = "weapons/xm1014-1.wav" +new const XM1014_RELOAD_SOUND[2][] = { + "weapons/reload1.wav", + "weapons/reload3.wav", +} + +enum { + XM1014_IDLE, + XM1014_FIRE1, + XM1014_FIRE2, + XM1014_RELOAD, + XM1014_PUMP, + XM1014_START_RELOAD, + XM1014_DRAW, +} + +createXM1014() { + new Weapon:weapon = create_weapon("default_xm1014", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_XM1014") + set_weapon_var(weapon, "view_model", create_model("models/v_xm1014.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_xm1014.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_xm1014.mdl")) + set_weapon_var(weapon, "hud", "weapon_xm1014") + set_weapon_var(weapon, "max_clip", 7) + set_weapon_var(weapon, "max_ammo", 32) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", XM1014_WEIGHT) + set_weapon_var(weapon, "flags", ITEM_FLAG_NOFIREUNDERWATER) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size9) + set_weapon_var(weapon, "forward_deploy", "@XM1014_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@XM1014_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@XM1014_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@XM1014_Reload") + set_weapon_var(weapon, "forward_idle", "@XM1014_Idle") + precache_sound(XM1014_SHOOT_SOUND) +} + +@XM1014_Deploy(weapon, player) { + return weapon_default_deploy(weapon, player, XM1014_DRAW, "m249") +} + +@XM1014_MaxSpeed(weapon, player) { + return XM1014_MAX_SPEED +} + +/* +BOOL CXM1014::PlayEmptySound() +{ + BOOL result = CBasePlayerWeapon::PlayEmptySound(); + m_iPlayEmptySound = 0; + return result; +} +*/ + +@XM1014_PrimaryAttack(weapon, player, clip, ammo) { + if (isEmptyFire(weapon, clip, true)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, LOUD_GUN_VOLUME) + set_member(player, m_iWeaponFlash, BRIGHT_GUN_FLASH) + // where is EjectBrass? + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_buckshots( + weapon, + player, + 6, + src, + aiming, + XM1014_CONE_VECTOR, + 3048.0, + 0, + XM1014_DAMAGE + ) + send_weapon_anim(player, random_num(XM1014_FIRE1, XM1014_FIRE2)) + playFireSound(player, XM1014_SHOOT_SOUND) + new Float:nextAttack = 0.25 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, clip ? 2.25 : 0.75) + set_member(weapon, m_Weapon_fInSpecialReload, 0) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + if (get_entvar(player, var_flags) & FL_ONGROUND) { + punchAngle[0] -= random_float(3.0, 5.0) + } else { + punchAngle[0] -= random_float(7.0, 10.0) + } + set_entvar(player, var_punchangle, punchAngle) +} + +@XM1014_Reload(weapon, player) { + weapon_default_shotgun_reload( + weapon, + player, + XM1014_RELOAD, + XM1014_START_RELOAD, + 0.3, + 0.55, + XM1014_RELOAD_SOUND[0], + XM1014_RELOAD_SOUND[1] + ) +} + +@XM1014_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + //if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) + if (Float:get_member(weapon, m_Weapon_flTimeWeaponIdle) > 0.0) { + return + } + new maxClip = rg_get_iteminfo(weapon, ItemInfo_iMaxClip) + new ammo = get_player_var(player, "ammo", weapon) + if (!get_member(weapon, m_Weapon_iClip) && !get_member(weapon, m_Weapon_fInSpecialReload) && ammo) { + ExecuteHamB(Ham_Weapon_Reload, weapon) + } else if (get_member(weapon, m_Weapon_fInSpecialReload)) { + if (get_member(weapon, m_Weapon_iClip) != maxClip && ammo) { + ExecuteHamB(Ham_Weapon_Reload, weapon) + } else { + set_member(weapon, m_Weapon_fInSpecialReload, 0) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.5) + send_weapon_anim(player, XM1014_PUMP) + } + } else { + send_weapon_anim(player, XM1014_IDLE) + } +} + +const MAC10_MAX_SPEED = 250 +const MAC10_WEIGHT = 25 +const MAC10_DAMAGE = 29 +const Float:MAC10_RANGE_MODIFER = 0.82 +const Float:MAC10_RELOAD_TIME = 3.15 +const Float:MAC10_BASE_ACCURACY = 0.15 +const Float:MAC10_ACCURACY_DIVISOR = 200.0 +new const MAC10_SHOOT_SOUND[] = "weapons/mac10-1.wav" + +enum { + MAC10_IDLE, + MAC10_RELOAD, + MAC10_DRAW, + MAC10_SHOOT1, + MAC10_SHOOT2, + MAC10_SHOOT3, +} + +createMAC10() { + new Weapon:weapon = create_weapon("default_mac10", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_MAC10") + set_weapon_var(weapon, "view_model", create_model("models/v_mac10.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_mac10.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_mac10.mdl")) + set_weapon_var(weapon, "hud", "weapon_mac10") + set_weapon_var(weapon, "max_clip", 30) + set_weapon_var(weapon, "max_ammo", 100) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", MAC10_WEIGHT) + set_weapon_var(weapon, "base_accuracy", MAC10_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size9) + set_weapon_var(weapon, "forward_deploy", "@MAC10_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@MAC10_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@MAC10_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@MAC10_Reload") + set_weapon_var(weapon, "forward_idle", "@MAC10_Idle") + precache_sound(MAC10_SHOOT_SOUND) +} + +@MAC10_Deploy(weapon, player) { + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_flAccuracy, MAC10_BASE_ACCURACY) + return weapon_default_deploy(weapon, player, MAC10_DRAW, "onehanded") +} + +@MAC10_MaxSpeed(weapon, player) { + return MAC10_MAX_SPEED +} + +@MAC10_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.375 * accuracy + } else { + spread = 0.03 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = (shotsFired * shotsFired * shotsFired / MAC10_ACCURACY_DIVISOR) + 0.6 + if (accuracy > 1.65) { + accuracy = 1.65 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 1, + BULLET_PLAYER_45ACP, + MAC10_DAMAGE, + MAC10_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(MAC10_SHOOT1, MAC10_SHOOT3)) + playFireSound(player, MAC10_SHOOT_SOUND) + new Float:nextAttack = 0.07 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 1.3, 0.55, 0.4, 0.05, 4.75, 3.75, 5) + } else if (playerVelocityLength2d(player) > 0.0) { + weapon_kick_back(weapon, player, 0.9, 0.45, 0.25, 0.035, 3.5, 2.75, 7) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.75, 0.4, 0.175, 0.03, 2.75, 2.5, 10) + } else { + weapon_kick_back(weapon, player, 0.775, 0.425, 0.2, 0.03, 3.0, 2.75, 9) + } +} + +@MAC10_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, MAC10_RELOAD, MAC10_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, 0.0) // why not 0.15? +} + +@MAC10_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, MAC10_IDLE) +} + +const TMP_MAX_SPEED = 250 +const TMP_WEIGHT = 25 +const TMP_DAMAGE = 20 +const Float:TMP_RANGE_MODIFER = 0.85 +const Float:TMP_RELOAD_TIME = 2.12 +const Float:TMP_BASE_ACCURACY = 0.2 +const Float:TMP_ACCURACY_DIVISOR = 200.0 +new const TMP_SHOOT_SOUND[2][] = { + "weapons/tmp-1.wav", + "weapons/tmp-2.wav", +} + +enum { + TMP_IDLE, + TMP_RELOAD, + TMP_DRAW, + TMP_SHOOT1, + TMP_SHOOT2, + TMP_SHOOT3, +} + +createTMP() { + new Weapon:weapon = create_weapon("default_tmp", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_TMP") + set_weapon_var(weapon, "view_model", create_model("models/v_tmp.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_tmp.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_tmp.mdl")) + set_weapon_var(weapon, "hud", "weapon_tmp") + set_weapon_var(weapon, "max_clip", 30) + set_weapon_var(weapon, "max_ammo", 120) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", TMP_WEIGHT) + set_weapon_var(weapon, "base_accuracy", TMP_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size7) + set_weapon_var(weapon, "forward_deploy", "@TMP_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@TMP_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@TMP_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@TMP_Reload") + set_weapon_var(weapon, "forward_idle", "@TMP_Idle") + precache_sounds(TMP_SHOOT_SOUND) +} + +@TMP_Deploy(weapon, player) { + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, TMP_BASE_ACCURACY) + return weapon_default_deploy(weapon, player, TMP_DRAW, "onehanded") +} + +@TMP_MaxSpeed(weapon, player) { + return TMP_MAX_SPEED +} + +@TMP_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.25 * accuracy + } else { + spread = 0.03 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = (shotsFired * shotsFired * shotsFired / TMP_ACCURACY_DIVISOR) + 0.55 + if (accuracy > 1.4) { + accuracy = 1.4 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + //set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 1, + BULLET_PLAYER_9MM, + TMP_DAMAGE, + TMP_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(TMP_SHOOT1, TMP_SHOOT3)) + playFireSound(player, TMP_SHOOT_SOUND[random(sizeof(TMP_SHOOT_SOUND))]) + new Float:nextAttack = 0.07 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 1.1, 0.5, 0.35, 0.045, 4.5, 3.5, 6) + } else if (playerVelocityLength2d(player) > 0.0) { + weapon_kick_back(weapon, player, 0.8, 0.4, 0.2, 0.03, 3.0, 2.5, 7) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.7, 0.35, 0.125, 0.025, 2.5, 2.0, 10) + } else { + weapon_kick_back(weapon, player, 0.725, 0.375, 0.15, 0.025, 2.75, 2.25, 9) + } +} + +@TMP_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, TMP_RELOAD, TMP_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, TMP_BASE_ACCURACY) +} + +@TMP_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, TMP_IDLE) +} + +const MP5_MAX_SPEED = 250 +const MP5_WEIGHT = 25 +const MP5_DAMAGE = 26 +const Float:MP5_RANGE_MODIFER = 0.84 +const Float:MP5_RELOAD_TIME = 2.63 +const Float:MP5_BASE_ACCURACY = 0.0 +const Float:MP5_ACCURACY_DIVISOR = 220.1 +new const MP5_SHOOT_SOUND[2][] = { + "weapons/mp5-1.wav", + "weapons/mp5-2.wav", +} + +enum { + MP5_IDLE, + MP5_RELOAD, + MP5_DRAW, + MP5_SHOOT1, + MP5_SHOOT2, + MP5_SHOOT3, +} + +createMP5() { + new Weapon:weapon = create_weapon("default_mp5navy", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_MP5") + set_weapon_var(weapon, "view_model", create_model("models/v_mp5.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_mp5.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_mp5.mdl")) + set_weapon_var(weapon, "hud", "weapon_mp5navy") + set_weapon_var(weapon, "max_clip", 30) + set_weapon_var(weapon, "max_ammo", 120) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", MP5_WEIGHT) + set_weapon_var(weapon, "base_accuracy", MP5_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size6) + set_weapon_var(weapon, "forward_deploy", "@MP5_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@MP5_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@MP5_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@MP5_Reload") + set_weapon_var(weapon, "forward_idle", "@MP5_Idle") + precache_sounds(MP5_SHOOT_SOUND) +} + +@MP5_Deploy(weapon, player) { + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_flAccuracy, MP5_BASE_ACCURACY) + return weapon_default_deploy(weapon, player, MP5_DRAW, "mp5") +} + +@MP5_MaxSpeed(weapon, player) { + return MP5_MAX_SPEED +} + +@MP5_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.2 * accuracy + } else { + spread = 0.04 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = (shotsFired * shotsFired / MP5_ACCURACY_DIVISOR) + 0.45 + if (accuracy > 0.75) { + accuracy = 0.75 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 1, + BULLET_PLAYER_9MM, + MP5_DAMAGE, + MP5_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(MP5_SHOOT1, MP5_SHOOT3)) + playFireSound(player, MP5_SHOOT_SOUND[random(sizeof(MP5_SHOOT_SOUND))]) + new Float:nextAttack = 0.075 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 0.9, 0.475, 0.35, 0.0425, 5.0, 3.0, 6) + } else if (playerVelocityLength2d(player) > 0.0) { + weapon_kick_back(weapon, player, 0.5, 0.275, 0.2, 0.03, 3.0, 2.0, 10) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.225, 0.15, 0.1, 0.015, 2.0, 1.0, 10) + } else { + weapon_kick_back(weapon, player, 0.25, 0.175, 0.125, 0.02, 2.25, 1.25, 10) + } +} + +@MP5_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, MP5_RELOAD, MP5_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, MP5_BASE_ACCURACY) +} + +@MP5_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, MP5_IDLE) +} + +const UMP45_MAX_SPEED = 250 +const UMP45_WEIGHT = 25 +const UMP45_DAMAGE = 30 +const Float:UMP45_RANGE_MODIFER = 0.82 +const Float:UMP45_RELOAD_TIME = 3.5 +const Float:UMP45_BASE_ACCURACY = 0.0 +const Float:UMP45_ACCURACY_DIVISOR = 210.0 +new const UMP45_SHOOT_SOUND[] = "weapons/ump45-1.wav" + +enum { + UMP45_IDLE, + UMP45_RELOAD, + UMP45_DRAW, + UMP45_SHOOT1, + UMP45_SHOOT2, + UMP45_SHOOT3, +} + +createUMP45() { + new Weapon:weapon = create_weapon("default_ump45", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_UMP45") + set_weapon_var(weapon, "view_model", create_model("models/v_ump45.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_ump45.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_ump45.mdl")) + set_weapon_var(weapon, "hud", "weapon_ump45") + set_weapon_var(weapon, "max_clip", 25) + set_weapon_var(weapon, "max_ammo", 100) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", UMP45_WEIGHT) + set_weapon_var(weapon, "base_accuracy", UMP45_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size6) + set_weapon_var(weapon, "forward_deploy", "@UMP45_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@UMP45_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@UMP45_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@UMP45_Reload") + set_weapon_var(weapon, "forward_idle", "@UMP45_Idle") + precache_sound(UMP45_SHOOT_SOUND) +} + +@UMP45_Deploy(weapon, player) { + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_flAccuracy, UMP45_BASE_ACCURACY) + return weapon_default_deploy(weapon, player, UMP45_DRAW, "carbine") +} + +@UMP45_MaxSpeed(weapon, player) { + return UMP45_MAX_SPEED +} + +@UMP45_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.24 * accuracy + } else { + spread = 0.04 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = (shotsFired * shotsFired / UMP45_ACCURACY_DIVISOR) + 0.5 + if (accuracy > 1.0) { + accuracy = 1.0 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 1, + BULLET_PLAYER_45ACP, + UMP45_DAMAGE, + UMP45_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(UMP45_SHOOT1, UMP45_SHOOT3)) + playFireSound(player, UMP45_SHOOT_SOUND) + new Float:nextAttack = 0.1 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 0.125, 0.65, 0.55, 0.0475, 5.5, 4.0, 10) + } else if (playerVelocityLength2d(player) > 0.0) { + weapon_kick_back(weapon, player, 0.55, 0.3, 0.225, 0.03, 3.5, 2.5, 10) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.25, 0.175, 0.125, 0.02, 2.25, 1.25, 10) + } else { + weapon_kick_back(weapon, player, 0.275, 0.2, 0.15, 0.0225, 2.5, 1.5, 10) + } +} + +@UMP45_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, UMP45_RELOAD, UMP45_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, UMP45_BASE_ACCURACY) +} + +@UMP45_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, UMP45_IDLE) +} + +const P90_MAX_SPEED = 245 +const P90_WEIGHT = 26 +const P90_DAMAGE = 21 +const Float:P90_RANGE_MODIFER = 0.885 +const Float:P90_RELOAD_TIME = 3.4 +const Float:P90_BASE_ACCURACY = 0.2 +const Float:P90_ACCURACY_DIVISOR = 175.0 +new const P90_SHOOT_SOUND[] = "weapons/p90-1.wav" + +enum { + P90_IDLE, + P90_RELOAD, + P90_DRAW, + P90_SHOOT1, + P90_SHOOT2, + P90_SHOOT3, +} + +createP90() { + new Weapon:weapon = create_weapon("default_p90", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_P90") + set_weapon_var(weapon, "view_model", create_model("models/v_p90.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_p90.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_p90.mdl")) + set_weapon_var(weapon, "hud", "weapon_p90") + set_weapon_var(weapon, "max_clip", 50) + set_weapon_var(weapon, "max_ammo", 100) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", P90_WEIGHT) + set_weapon_var(weapon, "base_accuracy", P90_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size7) + set_weapon_var(weapon, "forward_deploy", "@P90_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@P90_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@P90_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@P90_Reload") + set_weapon_var(weapon, "forward_idle", "@P90_Idle") + precache_sound(P90_SHOOT_SOUND) +} + +@P90_Deploy(weapon, player) { + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_flAccuracy, P90_BASE_ACCURACY) + return weapon_default_deploy(weapon, player, P90_DRAW, "carbine") +} + +@P90_MaxSpeed(weapon, player) { + return P90_MAX_SPEED +} + +@P90_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + new Float:playerVelocityLength = playerVelocityLength2d(player) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.3 * accuracy + } else if (playerVelocityLength > 170.0) { + spread = 0.115 * accuracy + } else { + spread = 0.045 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = (shotsFired * shotsFired / P90_ACCURACY_DIVISOR) + 0.45 + if (accuracy > 1.0) { + accuracy = 1.0 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 1, + BULLET_PLAYER_57MM, + P90_DAMAGE, + P90_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(P90_SHOOT1, P90_SHOOT3)) + playFireSound(player, P90_SHOOT_SOUND) + new Float:nextAttack = 0.066 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 0.9, 0.45, 0.35, 0.04, 5.25, 3.5, 4) + } else if (playerVelocityLength > 0.0) { + weapon_kick_back(weapon, player, 0.45, 0.3, 0.2, 0.0275, 4.0, 2.25, 7) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.275, 0.2, 0.125, 0.02, 3.0, 1.0, 9) + } else { + weapon_kick_back(weapon, player, 0.3, 0.225, 0.125, 0.02, 3.25, 1.25, 8) + } +} + +@P90_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, P90_RELOAD, P90_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, P90_BASE_ACCURACY) +} + +@P90_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, P90_IDLE) +} + +const GALIL_MAX_SPEED = 240 +const GALIL_WEIGHT = 25 +const GALIL_DAMAGE = 30 +const Float:GALIL_RANGE_MODIFER = 0.98 +const Float:GALIL_RELOAD_TIME = 2.45 +const Float:GALIL_BASE_ACCURACY = 0.2 +const Float:GALIL_ACCURACY_DIVISOR = 200.0 +new const GALIL_SHOOT_SOUND[2][] = { + "weapons/galil-1.wav", + "weapons/galil-2.wav", +} + +enum { + GALIL_IDLE, + GALIL_RELOAD, + GALIL_DRAW, + GALIL_SHOOT1, + GALIL_SHOOT2, + GALIL_SHOOT3, +} + +createGalil() { + new Weapon:weapon = create_weapon("default_galil", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_GALIL") + set_weapon_var(weapon, "view_model", create_model("models/v_galil.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_galil.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_galil.mdl")) + set_weapon_var(weapon, "hud", "weapon_galil") + set_weapon_var(weapon, "max_clip", 35) + set_weapon_var(weapon, "max_ammo", 90) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", GALIL_WEIGHT) + set_weapon_var(weapon, "flags", ITEM_FLAG_NOFIREUNDERWATER) + set_weapon_var(weapon, "base_accuracy", GALIL_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size4) + set_weapon_var(weapon, "forward_deploy", "@Galil_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@Galil_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@Galil_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@Galil_Reload") + set_weapon_var(weapon, "forward_idle", "@Galil_Idle") + precache_sounds(GALIL_SHOOT_SOUND) +} + +@Galil_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, GALIL_DRAW, "ak47")) { + return false + } + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, GALIL_BASE_ACCURACY) + return true +} + +@Galil_MaxSpeed(weapon, player) { + return GALIL_MAX_SPEED +} + +@Galil_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + new Float:playerVelocityLength = playerVelocityLength2d(player) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.04 + (0.3 * accuracy) + } else if (playerVelocityLength > 140.0) { + spread = 0.04 + (0.07 * accuracy) + } else { + spread = 0.0375 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = ((shotsFired * shotsFired * shotsFired) / GALIL_ACCURACY_DIVISOR) + 0.35 + if (accuracy > 1.25) { + accuracy = 1.25 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, BRIGHT_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 2, + BULLET_PLAYER_556MM, + GALIL_DAMAGE, + GALIL_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(GALIL_SHOOT1, GALIL_SHOOT3)) + playFireSound(player, GALIL_SHOOT_SOUND[random(sizeof(GALIL_SHOOT_SOUND))]) + new Float:nextAttack = 0.0875 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.28) + if (playerVelocityLength > 0.0) { // why it first + weapon_kick_back(weapon, player, 1.0, 0.45, 0.28, 0.045, 3.75, 3.0, 7) + } else if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 1.2, 0.5, 0.23, 0.15, 5.5, 3.5, 6) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.6, 0.3, 0.2, 0.0125, 3.25, 2.0, 7) + } else { + weapon_kick_back(weapon, player, 0.65, 0.35, 0.25, 0.015, 3.5, 2.25, 7) + } +} + +@Galil_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, GALIL_RELOAD, GALIL_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_flAccuracy, GALIL_BASE_ACCURACY) + set_member(weapon, m_Weapon_iShotsFired, 0) +} + +@Galil_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, GALIL_IDLE) +} + +const FAMAS_MAX_SPEED = 240 +const FAMAS_WEIGHT = 75 // lol wtf so high +const FAMAS_DAMAGE = 30 +const FAMAS_DAMAGE_BURST = 34 +const Float:FAMAS_RANGE_MODIFER = 0.96 +const Float:FAMAS_RELOAD_TIME = 3.3 +const Float:FAMAS_BASE_ACCURACY = 0.2 +const Float:FAMAS_ACCURACY_DIVISOR = 215.0 +new const FAMAS_SHOOT_SOUND[2][] = { + "weapons/famas-1.wav", + "weapons/famas-2.wav", +} + +enum { + FAMAS_IDLE, + FAMAS_RELOAD, + FAMAS_DRAW, + FAMAS_SHOOT1, + FAMAS_SHOOT2, + FAMAS_SHOOT3, +} + +createFamas() { + new Weapon:weapon = create_weapon("default_famas", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_FAMAS") + set_weapon_var(weapon, "view_model", create_model("models/v_famas.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_famas.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_famas.mdl")) + set_weapon_var(weapon, "hud", "weapon_famas") + set_weapon_var(weapon, "max_clip", 25) + set_weapon_var(weapon, "max_ammo", 90) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", FAMAS_WEIGHT) + set_weapon_var(weapon, "flags", ITEM_FLAG_NOFIREUNDERWATER) + set_weapon_var(weapon, "base_accuracy", FAMAS_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size4) + set_weapon_var(weapon, "forward_deploy", "@Famas_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@Famas_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@Famas_PrimaryAttack") + set_weapon_var(weapon, "forward_fire_remaining", "@Famas_FireRemaining") + set_weapon_var(weapon, "forward_secondary_attack", "@Famas_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@Famas_Reload") + set_weapon_var(weapon, "forward_idle", "@Famas_Idle") + precache_sounds(FAMAS_SHOOT_SOUND) +} + +@Famas_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, FAMAS_DRAW, "carbine")) { + return false + } + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, FAMAS_BASE_ACCURACY) + set_member(weapon, m_Weapon_iRemainingShotsFired, 0) + set_member(weapon, m_Weapon_flNextRemainingShoot, 0.0) + return true +} + +@Famas_MaxSpeed(weapon, player) { + return FAMAS_MAX_SPEED +} + +@Famas_PrimaryAttack(weapon, player, clip, ammo) { + new bool:isBurstMode = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_FAMAS_BURST_MODE) ? true : false + new Float:nextAttack = isBurstMode ? 0.55 : 0.0825 + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + new Float:playerVelocityLength = playerVelocityLength2d(player) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.03 + (0.3 * accuracy) + } else if (playerVelocityLength > 140.0) { + spread = 0.03 + (0.07 * accuracy) + } else { + spread = 0.02 * accuracy + } + if (!isBurstMode) { + spread += 0.01 + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = ((shotsFired * shotsFired * shotsFired) / FAMAS_ACCURACY_DIVISOR) + 0.3 + if (accuracy > 1.0) { + accuracy = 1.0 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, BRIGHT_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 2, + BULLET_PLAYER_556MM, + isBurstMode ? FAMAS_DAMAGE_BURST : FAMAS_DAMAGE, + FAMAS_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(FAMAS_SHOOT1, FAMAS_SHOOT3)) + playFireSound(player, FAMAS_SHOOT_SOUND[random(sizeof(FAMAS_SHOOT_SOUND))]) + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.1) + if (playerVelocityLength > 0.0) { // why it first + weapon_kick_back(weapon, player, 1.0, 0.45, 0.275, 0.05, 4.0, 2.5, 7) + } else if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 1.25, 0.45, 0.22, 0.18, 5.5, 4.0, 5) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.575, 0.325, 0.2, 0.011, 3.25, 2.0, 8) + } else { + weapon_kick_back(weapon, player, 0.625, 0.375, 0.25, 0.0125, 3.5, 2.25, 8) + } + if (isBurstMode) { + set_member(weapon, m_Weapon_iRemainingShotsFired, 1) + set_member(weapon, m_Weapon_flNextRemainingShoot, get_gametime() + 0.05) + set_member(weapon, m_Weapon_fBurstSpread, spread) + } +} + +@Famas_FireRemaining(weapon, player, clip, shotsFired) { + // refactoring from 1 to 3 + if (--clip < 0) { + set_member(weapon, m_Weapon_iClip, 0) + set_member(weapon, m_Weapon_iRemainingShotsFired, 3) + set_member(weapon, m_Weapon_flNextRemainingShoot, 0.0) + return + } + set_member(weapon, m_Weapon_iClip, clip) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + Float:get_member(weapon, m_Weapon_fBurstSpread), + 8192.0, + 2, + BULLET_PLAYER_556MM, + FAMAS_DAMAGE, + FAMAS_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(FAMAS_SHOOT1, FAMAS_SHOOT3)) + playFireSound(player, FAMAS_SHOOT_SOUND[random(sizeof(FAMAS_SHOOT_SOUND))]) + set_member(weapon, m_Weapon_iRemainingShotsFired, ++shotsFired) + if (shotsFired != 3) { + set_member(weapon, m_Weapon_flNextRemainingShoot, get_gametime() + 0.1) + } else { + set_member(weapon, m_Weapon_flNextRemainingShoot, 0.0) + } +} + +@Famas_SecondaryAttack(weapon, player, WeaponState:weaponState) { + if (weaponState & WPNSTATE_FAMAS_BURST_MODE) { + set_member(weapon, m_Weapon_iWeaponState, weaponState & ~WPNSTATE_FAMAS_BURST_MODE) + client_print(player, print_center, "#Cstrike_TitlesTXT_Switch_To_FullAuto") + } else { + set_member(weapon, m_Weapon_iWeaponState, weaponState | WPNSTATE_FAMAS_BURST_MODE) + client_print(player, print_center, "#Cstrike_TitlesTXT_Switch_To_BurstFire") + } + set_member(weapon, m_Weapon_flNextSecondaryAttack, 0.3) +} + +@Famas_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, FAMAS_RELOAD, FAMAS_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_flAccuracy, 0.0) // why 0.0? + set_member(weapon, m_Weapon_iShotsFired, 0) +} + +@Famas_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, FAMAS_IDLE) +} + +const AK47_MAX_SPEED = 221 +const AK47_WEIGHT = 25 +const AK47_DAMAGE = 36 +const Float:AK47_RANGE_MODIFER = 0.98 +const Float:AK47_RELOAD_TIME = 2.45 +const Float:AK47_BASE_ACCURACY = 0.2 +const Float:AK47_ACCURACY_DIVISOR = 200.0 +new const AK47_SHOOT_SOUND[2][] = { + "weapons/ak47-1.wav", + "weapons/ak47-2.wav", +} + +enum { + AK47_IDLE, + AK47_RELOAD, + AK47_DRAW, + AK47_SHOOT1, + AK47_SHOOT2, + AK47_SHOOT3, +} + +createAK47() { + new Weapon:weapon = create_weapon("default_ak47", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_AK47") + set_weapon_var(weapon, "view_model", create_model("models/v_ak47.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_ak47.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_ak47.mdl")) + set_weapon_var(weapon, "hud", "weapon_ak47") + set_weapon_var(weapon, "max_clip", 30) + set_weapon_var(weapon, "max_ammo", 90) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", AK47_WEIGHT) + set_weapon_var(weapon, "base_accuracy", AK47_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size4) + set_weapon_var(weapon, "forward_deploy", "@AK47_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@AK47_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@AK47_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@AK47_Reload") + set_weapon_var(weapon, "forward_idle", "@AK47_Idle") + precache_sounds(AK47_SHOOT_SOUND) +} + +@AK47_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, AK47_DRAW, "ak47")) { + return false + } + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, AK47_BASE_ACCURACY) + return true +} + +@AK47_MaxSpeed(weapon, player) { + return AK47_MAX_SPEED +} + +@AK47_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + new Float:playerVelocityLength = playerVelocityLength2d(player) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.04 + (0.4 * accuracy) + } else if (playerVelocityLength > 140.0) { + spread = 0.04 + (0.07 * accuracy) + } else { + spread = 0.0275 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = ((shotsFired * shotsFired * shotsFired) / AK47_ACCURACY_DIVISOR) + 0.35 + if (accuracy > 1.25) { + accuracy = 1.25 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, BRIGHT_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 2, + BULLET_PLAYER_762MM, + AK47_DAMAGE, + AK47_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(AK47_SHOOT1, AK47_SHOOT3)) + playFireSound(player, AK47_SHOOT_SOUND[random(sizeof(AK47_SHOOT_SOUND))]) + new Float:nextAttack = 0.0955 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.9) + if (playerVelocityLength > 0.0) { // why it first + weapon_kick_back(weapon, player, 1.5, 0.45, 0.225, 0.05, 6.5, 2.5, 7) + } else if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 2.0, 1.0, 0.5, 0.35, 9.0, 6.0, 5) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.9, 0.35, 0.15, 0.025, 5.5, 1.5, 9) + } else { + weapon_kick_back(weapon, player, 1.0, 0.375, 0.175, 0.0375, 5.75, 1.75, 8) + } +} + +@AK47_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, AK47_RELOAD, AK47_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, AK47_BASE_ACCURACY) +} + +@AK47_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, AK47_IDLE) +} + +const M4A1_MAX_SPEED = 230 +const M4A1_WEIGHT = 25 +const M4A1_DAMAGE = 32 +const M4A1_DAMAGE_SILENCER = 33 +const Float:M4A1_RANGE_MODIFER = 0.97 +const Float:M4A1_RANGE_MODIFER_SILENCER = 0.95 +const Float:M4A1_RELOAD_TIME = 3.05 +const Float:M4A1_BASE_ACCURACY = 0.2 +const Float:M4A1_ACCURACY_DIVISOR = 220.0 +const Float:M4A1_ADJUST_SILENCER_TIME = 2.0 +new const M4A1_SHOOT_SOUND[3][] = { + "weapons/m4a1-1.wav", + "weapons/m4a1_unsil-1.wav", + "weapons/m4a1_unsil-2.wav", +} + +enum { + M4A1_SILENCER_IDLE, + M4A1_SILENCER_SHOOT1, + M4A1_SILENCER_SHOOT2, + M4A1_SILENCER_SHOOT3, + M4A1_SILENCER_RELOAD, + M4A1_SILENCER_DRAW, + M4A1_ATTACH_SILENCER, + M4A1_IDLE, + M4A1_SHOOT1, + M4A1_SHOOT2, + M4A1_SHOOT3, + M4A1_RELOAD, + M4A1_DRAW, + M4A1_DETACH_SILENCER, +} + +createM4A1() { + new Weapon:weapon = create_weapon("default_m4a1", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_M4A1") + set_weapon_var(weapon, "view_model", create_model("models/v_m4a1.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_m4a1.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_m4a1.mdl")) + set_weapon_var(weapon, "hud", "weapon_m4a1") + set_weapon_var(weapon, "max_clip", 30) + set_weapon_var(weapon, "max_ammo", 90) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", M4A1_WEIGHT) + set_weapon_var(weapon, "base_accuracy", M4A1_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size4) + set_weapon_var(weapon, "forward_deploy", "@M4A1_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@M4A1_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@M4A1_PrimaryAttack") + set_weapon_var(weapon, "forward_secondary_attack", "@M4A1_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@M4A1_Reload") + set_weapon_var(weapon, "forward_idle", "@M4A1_Idle") + precache_sounds(M4A1_SHOOT_SOUND) +} + +@M4A1_Deploy(weapon, player) { + new anim = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_M4A1_SILENCED) ? M4A1_SILENCER_DRAW : M4A1_DRAW + if (!weapon_default_deploy(weapon, player, anim, "rifle")) { + return false + } + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, M4A1_BASE_ACCURACY) + return true +} + +@M4A1_MaxSpeed(weapon, player) { + return M4A1_MAX_SPEED +} + +@M4A1_PrimaryAttack(weapon, player, clip, ammo) { + new bool:isSilenced = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_M4A1_SILENCED) ? true : false + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + new Float:playerVelocityLength = playerVelocityLength2d(player) + if (isSilenced) { + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.035 + (0.4 * accuracy) + } else if (playerVelocityLength > 140.0) { + spread = 0.035 + (0.07 * accuracy) + } else { + spread = 0.025 * accuracy + } + } else { + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.035 + (0.4 * accuracy) + } else if (playerVelocityLength > 140.0) { + spread = 0.035 + (0.07 * accuracy) + } else { + spread = 0.02 * accuracy + } + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = ((shotsFired * shotsFired * shotsFired) / M4A1_ACCURACY_DIVISOR) + 0.3 + if (accuracy > 1.0) { + accuracy = 1.0 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, BRIGHT_GUN_FLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 2, + BULLET_PLAYER_556MM, + isSilenced ? M4A1_DAMAGE_SILENCER : M4A1_DAMAGE, + isSilenced ? M4A1_RANGE_MODIFER_SILENCER : M4A1_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + if (isSilenced) { + send_weapon_anim(player, random_num(M4A1_SILENCER_SHOOT1, M4A1_SILENCER_SHOOT3)) + playFireSound(player, M4A1_SHOOT_SOUND[0]) + } else { + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + send_weapon_anim(player, random_num(M4A1_SHOOT1, M4A1_SHOOT3)) + playFireSound(player, M4A1_SHOOT_SOUND[random_num(1, 2)]) + } + new Float:nextAttack = 0.0875 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.5) + if (playerVelocityLength > 0.0) { // why it first + weapon_kick_back(weapon, player, 1.0, 0.45, 0.28, 0.045, 3.75, 3.0, 7) + } else if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 1.2, 0.5, 0.23, 0.15, 5.5, 3.5, 6) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.6, 0.3, 0.2, 0.0125, 3.25, 2.0, 7) + } else { + weapon_kick_back(weapon, player, 0.65, 0.35, 0.25, 0.015, 3.5, 2.25, 7) + } +} + +@M4A1_SecondaryAttack(weapon, player, WeaponState:weaponState) { + if (weaponState & WPNSTATE_M4A1_SILENCED) { + set_member(weapon, m_Weapon_iWeaponState, weaponState & ~WPNSTATE_M4A1_SILENCED) + send_weapon_anim(player, M4A1_DETACH_SILENCER) + } else { + set_member(weapon, m_Weapon_iWeaponState, weaponState | WPNSTATE_M4A1_SILENCED) + send_weapon_anim(player, M4A1_ATTACH_SILENCER) + } + set_member(weapon, m_Weapon_flNextPrimaryAttack, M4A1_ADJUST_SILENCER_TIME) + set_member(weapon, m_Weapon_flNextSecondaryAttack, M4A1_ADJUST_SILENCER_TIME) + set_member(weapon, m_Weapon_flTimeWeaponIdle, M4A1_ADJUST_SILENCER_TIME) +} + +@M4A1_Reload(weapon, player) { + new anim = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_M4A1_SILENCED) ? M4A1_SILENCER_RELOAD : M4A1_RELOAD + if (!weapon_default_reload(weapon, player, anim, M4A1_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_flAccuracy, M4A1_BASE_ACCURACY) + set_member(weapon, m_Weapon_iShotsFired, 0) +} + +@M4A1_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + new anim = (get_member(weapon, m_Weapon_iWeaponState) & WPNSTATE_M4A1_SILENCED) ? M4A1_SILENCER_IDLE : M4A1_IDLE + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, anim) +} + +const SG552_MAX_SPEED = 235 +const SG552_MAX_SPEED_ZOOM = 200 +const SG552_WEIGHT = 25 +const SG552_DAMAGE = 33 +const Float:SG552_RANGE_MODIFER = 0.955 +const Float:SG552_RELOAD_TIME = 3.0 +const Float:SG552_BASE_ACCURACY = 0.2 +const Float:SG552_ACCURACY_DIVISOR = 220.0 +new const SG552_SHOOT_SOUND[2][] = { + "weapons/sg552-1.wav", + "weapons/sg552-2.wav", +} + +enum { + SG552_IDLE, + SG552_RELOAD, + SG552_DRAW, + SG552_SHOOT1, + SG552_SHOOT2, + SG552_SHOOT3, +} + +createSG552() { + new Weapon:weapon = create_weapon("default_sg552", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_SG552") + set_weapon_var(weapon, "view_model", create_model("models/v_sg552.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_sg552.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_sg552.mdl")) + set_weapon_var(weapon, "hud", "weapon_sg552") + set_weapon_var(weapon, "max_clip", 30) + set_weapon_var(weapon, "max_ammo", 90) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", SG552_WEIGHT) + set_weapon_var(weapon, "base_accuracy", SG552_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size5) + set_weapon_var(weapon, "forward_deploy", "@SG552_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@SG552_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@SG552_PrimaryAttack") + set_weapon_var(weapon, "forward_secondary_attack", "@SG552_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@SG552_Reload") + set_weapon_var(weapon, "forward_idle", "@SG552_Idle") + precache_sounds(SG552_SHOOT_SOUND) +} + +@SG552_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, SG552_DRAW, "mp5")) { + return false + } + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, SG552_BASE_ACCURACY) + return true +} + +@SG552_MaxSpeed(weapon, player, fov) { + return ((fov == DEFAULT_FOV) ? SG552_MAX_SPEED : SG552_MAX_SPEED_ZOOM) +} + +@SG552_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + new Float:playerVelocityLength = playerVelocityLength2d(player) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.035 + (0.45 * accuracy) + } else if (playerVelocityLength > 140.0) { + spread = 0.035 + (0.075 * accuracy) + } else { + spread = 0.02 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = ((shotsFired * shotsFired * shotsFired) / SG552_ACCURACY_DIVISOR) + 0.3 + if (accuracy > 1.0) { + accuracy = 1.0 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, BRIGHT_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 2, + BULLET_PLAYER_556MM, + SG552_DAMAGE, + SG552_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(SG552_SHOOT1, SG552_SHOOT3)) + playFireSound(player, SG552_SHOOT_SOUND[random(sizeof(SG552_SHOOT_SOUND))]) + new Float:nextAttack = (get_member(player, m_iFOV) == DEFAULT_FOV) ? 0.0825 : 0.135 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + if (playerVelocityLength > 0.0) { // why it first + weapon_kick_back(weapon, player, 1.0, 0.45, 0.28, 0.04, 4.25, 2.5, 7) + } else if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 1.25, 0.45, 0.22, 0.18, 6.0, 4.0, 5) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.6, 0.35, 0.2, 0.0125, 3.7, 2.0, 10) + } else { + weapon_kick_back(weapon, player, 0.625, 0.375, 0.25, 0.0125, 4.0, 2.25, 9) + } +} + +@SG552_SecondaryAttack(weapon, player, WeaponState:weaponState, fov) { + new nextFov + if (fov == DEFAULT_FOV) { + nextFov = 55 + } else { + nextFov = DEFAULT_FOV + } + set_member(player, m_iFOV, nextFov) + //rg_reset_maxspeed(player) // why not call? + set_member(weapon, m_Weapon_flNextSecondaryAttack, 0.3) +} + +@SG552_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, SG552_RELOAD, SG552_RELOAD_TIME)) { + return + } + if (get_member(player, m_iFOV) != DEFAULT_FOV) { + ExecuteHamB(Ham_Weapon_SecondaryAttack, weapon) + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, SG552_BASE_ACCURACY) +} + +@SG552_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, SG552_IDLE) +} + +const AUG_MAX_SPEED = 240 +// where is zoom speed? +const AUG_WEIGHT = 25 +const AUG_DAMAGE = 32 +const Float:AUG_RANGE_MODIFER = 0.96 +const Float:AUG_RELOAD_TIME = 3.3 +const Float:AUG_BASE_ACCURACY = 0.2 +const Float:AUG_ACCURACY_DIVISOR = 215.0 +new const AUG_SHOOT_SOUND[] = "weapons/aug-1.wav" + +enum { + AUG_IDLE, + AUG_RELOAD, + AUG_DRAW, + AUG_SHOOT1, + AUG_SHOOT2, + AUG_SHOOT3, +} + +createAUG() { + new Weapon:weapon = create_weapon("default_aug", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_AUG") + set_weapon_var(weapon, "view_model", create_model("models/v_aug.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_aug.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_aug.mdl")) + set_weapon_var(weapon, "hud", "weapon_aug") + set_weapon_var(weapon, "max_clip", 30) + set_weapon_var(weapon, "max_ammo", 90) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", AUG_WEIGHT) + set_weapon_var(weapon, "base_accuracy", AUG_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size3) + set_weapon_var(weapon, "forward_deploy", "@AUG_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@AUG_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@AUG_PrimaryAttack") + set_weapon_var(weapon, "forward_secondary_attack", "@AUG_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@AUG_Reload") + set_weapon_var(weapon, "forward_idle", "@AUG_Idle") + precache_sound(AUG_SHOOT_SOUND) +} + +@AUG_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, AUG_DRAW, "carbine")) { + return false + } + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, AUG_BASE_ACCURACY) + return true +} + +@AUG_MaxSpeed(weapon, player) { + return AUG_MAX_SPEED +} + +@AUG_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + new Float:playerVelocityLength = playerVelocityLength2d(player) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.035 + (0.4 * accuracy) + } else if (playerVelocityLength > 140.0) { + spread = 0.035 + (0.07 * accuracy) + } else { + spread = 0.02 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = ((shotsFired * shotsFired * shotsFired) / AUG_ACCURACY_DIVISOR) + 0.3 + if (accuracy > 1.0) { + accuracy = 1.0 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, BRIGHT_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 2, + BULLET_PLAYER_556MM, + AUG_DAMAGE, + AUG_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(AUG_SHOOT1, AUG_SHOOT3)) + playFireSound(player, AUG_SHOOT_SOUND) + new Float:nextAttack = (get_member(player, m_iFOV) == DEFAULT_FOV) ? 0.0825 : 0.135 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.9) + if (playerVelocityLength > 0.0) { // why it first + weapon_kick_back(weapon, player, 1.0, 0.45, 0.275, 0.05, 4.0, 2.5, 7) + } else if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 1.25, 0.45, 0.22, 0.18, 5.5, 4.0, 5) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.575, 0.325, 0.2, 0.011, 3.25, 2.0, 8) + } else { + weapon_kick_back(weapon, player, 0.625, 0.375, 0.25, 0.0125, 3.5, 2.25, 8) + } +} + +@AUG_SecondaryAttack(weapon, player, WeaponState:weaponState, fov) { + new nextFov + if (fov == DEFAULT_FOV) { + nextFov = 55 + } else { + nextFov = DEFAULT_FOV + } + set_member(player, m_iFOV, nextFov) + set_member(weapon, m_Weapon_flNextSecondaryAttack, 0.3) +} + +@AUG_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, AUG_RELOAD, AUG_RELOAD_TIME)) { + return + } + if (get_member(player, m_iFOV) != DEFAULT_FOV) { + ExecuteHamB(Ham_Weapon_SecondaryAttack, weapon) + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_flAccuracy, 0.0) // why 0.0 + set_member(weapon, m_Weapon_iShotsFired, 0) +} + +@AUG_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, AUG_IDLE) +} + +const SCOUT_MAX_SPEED = 260 +const SCOUT_MAX_SPEED_ZOOM = 220 +const SCOUT_WEIGHT = 30 +const SCOUT_DAMAGE = 75 +const Float:SCOUT_RANGE_MODIFER = 0.98 +const Float:SCOUT_RELOAD_TIME = 2.0 +new const SCOUT_SHOOT_SOUND[] = "weapons/scout_fire-1.wav" + +enum { + SCOUT_IDLE, + SCOUT_SHOOT1, + SCOUT_SHOOT2, + SCOUT_RELOAD, + SCOUT_DRAW, +} + +createScout() { + new Weapon:weapon = create_weapon("default_scout", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_SCOUT") + set_weapon_var(weapon, "view_model", create_model("models/v_scout.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_scout.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_scout.mdl")) + set_weapon_var(weapon, "hud", "weapon_scout") + set_weapon_var(weapon, "max_clip", 10) + set_weapon_var(weapon, "max_ammo", 90) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", SCOUT_WEIGHT) + set_weapon_var(weapon, "forward_deploy", "@Scout_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@Scout_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@Scout_PrimaryAttack") + set_weapon_var(weapon, "forward_secondary_attack", "@Scout_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@Scout_Reload") + set_weapon_var(weapon, "forward_idle", "@Scout_Idle") + precache_sound(SCOUT_SHOOT_SOUND) +} + +@Scout_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, SCOUT_DRAW, "rifle")) { + return false + } + new Float:nextAttack = 1.25 + set_member(player, m_flNextAttack, nextAttack) + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, 1.0) + return true +} + +@Scout_MaxSpeed(weapon, player, fov) { + return ((fov == DEFAULT_FOV) ? SCOUT_MAX_SPEED : SCOUT_MAX_SPEED_ZOOM) +} + +@Scout_PrimaryAttack(weapon, player, clip, ammo) { + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.2 + } else if (playerVelocityLength2d(player) > 170.0) { + spread = 0.075 + } else if (playerFlags & FL_DUCKING) { + spread = 0.0 + } else { + spread = 0.007 + } + new fov = get_member(player, m_iFOV) + if (fov != DEFAULT_FOV) { + set_member(player, m_bResumeZoom, true) + set_member(player, m_iLastZoom, fov) + set_member(player, m_iFOV, DEFAULT_FOV) + } else { + spread += 0.025 + } + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, NORMAL_GUN_FLASH) + set_member(player, m_flEjectBrass, get_gametime() + 0.56) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 3, + BULLET_PLAYER_762MM, + SCOUT_DAMAGE, + SCOUT_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(SCOUT_SHOOT1, SCOUT_SHOOT2)) + playFireSound(player, SCOUT_SHOOT_SOUND) + new Float:nextAttack = 1.25 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.8) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} + +@Scout_SecondaryAttack(weapon, player, WeaponState:weaponState, fov) { + new nextFov + if (fov == DEFAULT_FOV) { + nextFov = 40 + } else if (fov == 40) { + nextFov = 15 + } else { + nextFov = DEFAULT_FOV + } + set_member(player, m_iFOV, nextFov) + rg_reset_maxspeed(player) + emit_sound(player, CHAN_ITEM, "weapons/zoom.wav", 0.2, 2.4, 0, PITCH_NORM) + set_member(weapon, m_Weapon_flNextSecondaryAttack, 0.3) +} + +@Scout_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, SCOUT_RELOAD, SCOUT_RELOAD_TIME)) { + return + } + if (get_member(player, m_iFOV) != DEFAULT_FOV) { + set_member(player, m_iFOV, 15) + ExecuteHamB(Ham_Weapon_SecondaryAttack, weapon) + } + rg_set_animation(player, PLAYER_RELOAD) +} + +@Scout_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + if (!get_member(weapon, m_Weapon_iClip)) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 60.0) + send_weapon_anim(player, SCOUT_IDLE) +} + +const AWP_MAX_SPEED = 210 +const AWP_MAX_SPEED_ZOOM = 150 +const AWP_WEIGHT = 30 +const AWP_DAMAGE = 115 +const Float:AWP_RANGE_MODIFER = 0.99 +const Float:AWP_RELOAD_TIME = 2.5 +new const AWP_SHOOT_SOUND[] = "weapons/awp1.wav" + +enum { + AWP_IDLE, + AWP_SHOOT1, + AWP_SHOOT2, + AWP_SHOOT3, + AWP_RELOAD, + AWP_DRAW, +} + +createAWP() { + new Weapon:weapon = create_weapon("default_awp", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_AWP") + set_weapon_var(weapon, "view_model", create_model("models/v_awp.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_awp.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_awp.mdl")) + set_weapon_var(weapon, "hud", "weapon_awp") + set_weapon_var(weapon, "max_clip", 10) + set_weapon_var(weapon, "max_ammo", 30) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", AWP_WEIGHT) + set_weapon_var(weapon, "forward_deploy", "@AWP_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@AWP_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@AWP_PrimaryAttack") + set_weapon_var(weapon, "forward_secondary_attack", "@AWP_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@AWP_Reload") + set_weapon_var(weapon, "forward_idle", "@AWP_Idle") + precache_sound(AWP_SHOOT_SOUND) +} + +@AWP_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, AWP_DRAW, "rifle")) { + return false + } + new Float:nextAttack = 1.45 + set_member(player, m_flNextAttack, nextAttack) + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, 1.0) + return true +} + +@AWP_MaxSpeed(weapon, player, fov) { + return ((fov == DEFAULT_FOV) ? AWP_MAX_SPEED : AWP_MAX_SPEED_ZOOM) +} + +@AWP_PrimaryAttack(weapon, player, clip, ammo) { + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.85 + } else if (playerVelocityLength2d(player) > 140.0) { + spread = 0.25 + } else if (playerVelocityLength2d(player) > 10.0) { + spread = 0.1 + } else if (playerFlags & FL_DUCKING) { + spread = 0.0 + } else { + spread = 0.001 + } + new fov = get_member(player, m_iFOV) + if (fov != DEFAULT_FOV) { + set_member(player, m_bResumeZoom, true) + set_member(player, m_iLastZoom, fov) + set_member(player, m_iFOV, DEFAULT_FOV) + } else { + spread += 0.08 + } + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, NORMAL_GUN_FLASH) + set_member(player, m_flEjectBrass, get_gametime() + 0.55) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 3, + BULLET_PLAYER_338MAG, + AWP_DAMAGE, + AWP_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(AWP_SHOOT1, AWP_SHOOT3)) + playFireSound(player, AWP_SHOOT_SOUND) + new Float:nextAttack = 1.45 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} + +@AWP_SecondaryAttack(weapon, player, WeaponState:weaponState, fov) { + new nextFov + if (fov == DEFAULT_FOV) { + nextFov = 40 + } else if (fov == 40) { + nextFov = 10 + } else { + nextFov = DEFAULT_FOV + } + set_member(player, m_iFOV, nextFov) + rg_reset_maxspeed(player) + emit_sound(player, CHAN_ITEM, "weapons/zoom.wav", 0.2, 2.4, 0, PITCH_NORM) + set_member(weapon, m_Weapon_flNextSecondaryAttack, 0.3) +} + +@AWP_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, AWP_RELOAD, AWP_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + if (get_member(player, m_iFOV) != DEFAULT_FOV) { + set_member(player, m_iFOV, 15) + ExecuteHamB(Ham_Weapon_SecondaryAttack, weapon) + } +} + +@AWP_Idle(weapon, player, Float:idleTime) { + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + if (!get_member(weapon, m_Weapon_iClip)) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 60.0) + send_weapon_anim(player, AWP_IDLE) +} + +const G3SG1_MAX_SPEED = 210 +const G3SG1_MAX_SPEED_ZOOM = 150 +const G3SG1_WEIGHT = 20 +const G3SG1_DAMAGE = 80 +const Float:G3SG1_RANGE_MODIFER = 0.98 +const Float:G3SG1_RELOAD_TIME = 3.5 +new const G3SG1_SHOOT_SOUND[] = "weapons/g3sg1-1.wav" + +enum { + G3SG1_IDLE, + G3SG1_SHOOT1, + G3SG1_SHOOT2, + G3SG1_RELOAD, + G3SG1_DRAW, +} + +createG3SG1() { + new Weapon:weapon = create_weapon("default_g3sg1", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_G3SG1") + set_weapon_var(weapon, "view_model", create_model("models/v_g3sg1.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_g3sg1.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_g3sg1.mdl")) + set_weapon_var(weapon, "hud", "weapon_g3sg1") + set_weapon_var(weapon, "max_clip", 20) + set_weapon_var(weapon, "max_ammo", 90) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", G3SG1_WEIGHT) + set_weapon_var(weapon, "forward_deploy", "@G3SG1_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@G3SG1_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@G3SG1_PrimaryAttack") + set_weapon_var(weapon, "forward_secondary_attack", "@G3SG1_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@G3SG1_Reload") + set_weapon_var(weapon, "forward_idle", "@G3SG1_Idle") + precache_sound(G3SG1_SHOOT_SOUND) +} + +@G3SG1_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, G3SG1_DRAW, "mp5")) { + return false + } + set_member(weapon, m_Weapon_flAccuracy, 0.2) + return true +} + +@G3SG1_MaxSpeed(weapon, player, fov) { + return ((fov == DEFAULT_FOV) ? G3SG1_MAX_SPEED : G3SG1_MAX_SPEED_ZOOM) +} + +@G3SG1_PrimaryAttack(weapon, player, clip, ammo) { + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.45 + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.15 + } else if (playerFlags & FL_DUCKING) { + spread = 0.035 + } else { + spread = 0.055 + } + new fov = get_member(player, m_iFOV) + if (fov != DEFAULT_FOV) { + spread += 0.025 + } + new Float:time = get_gametime() + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:accuracy + if (lastFire) { + accuracy = (time - lastFire) * 0.3 + 0.55 + if (accuracy > 0.98) { + accuracy = 0.98 + } + } else { + accuracy = 0.98 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, NORMAL_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + (1.0 - accuracy) * spread, + 8192.0, + 3, + BULLET_PLAYER_762MM, + G3SG1_DAMAGE, + G3SG1_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(G3SG1_SHOOT1, G3SG1_SHOOT2)) + playFireSound(player, G3SG1_SHOOT_SOUND) + new Float:nextAttack = 0.25 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.8) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= punchAngle[0] * 0.25 + random_float(0.75, 1.75) + punchAngle[1] += random_float(-0.75, 0.75) + set_entvar(player, var_punchangle, punchAngle) +} + +@G3SG1_SecondaryAttack(weapon, player, WeaponState:weaponState, fov) { + new nextFov + if (fov == DEFAULT_FOV) { + nextFov = 40 + } else if (fov == 40) { + nextFov = 15 + } else { + nextFov = DEFAULT_FOV + } + set_member(player, m_iFOV, nextFov) + rg_reset_maxspeed(player) + emit_sound(player, CHAN_ITEM, "weapons/zoom.wav", 0.2, 2.4, 0, PITCH_NORM) + set_member(weapon, m_Weapon_flNextSecondaryAttack, 0.3) +} + +@G3SG1_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, G3SG1_RELOAD, G3SG1_RELOAD_TIME)) { + return + } + if (get_member(player, m_iFOV) != DEFAULT_FOV) { + set_member(player, m_iFOV, 15) + ExecuteHamB(Ham_Weapon_SecondaryAttack, weapon) + } + set_member(weapon, m_Weapon_flAccuracy, 0.2) + set_member(weapon, m_Weapon_flTimeWeaponIdle, Float:get_member(weapon, m_Weapon_flTimeWeaponIdle) + 1.2) + rg_set_animation(player, PLAYER_RELOAD) +} + +@G3SG1_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + if (!get_member(weapon, m_Weapon_iClip)) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 60.0) + send_weapon_anim(player, G3SG1_IDLE) +} + +const SG550_MAX_SPEED = 210 +const SG550_MAX_SPEED_ZOOM = 150 +const SG550_WEIGHT = 20 +const SG550_DAMAGE = 70 +const Float:SG550_RANGE_MODIFER = 0.98 +const Float:SG550_RELOAD_TIME = 3.35 +new const SG550_SHOOT_SOUND[] = "weapons/sg550-1.wav" + +enum { + SG550_IDLE, + SG550_SHOOT1, + SG550_SHOOT2, + SG550_RELOAD, + SG550_DRAW, +} + +createSG550() { + new Weapon:weapon = create_weapon("default_sg550", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_SG550") + set_weapon_var(weapon, "view_model", create_model("models/v_sg550.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_sg550.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_sg550.mdl")) + set_weapon_var(weapon, "hud", "weapon_sg550") + set_weapon_var(weapon, "max_clip", 30) + set_weapon_var(weapon, "max_ammo", 90) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", SG550_WEIGHT) + set_weapon_var(weapon, "forward_deploy", "@SG550_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@SG550_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@SG550_PrimaryAttack") + set_weapon_var(weapon, "forward_secondary_attack", "@SG550_SecondaryAttack") + set_weapon_var(weapon, "forward_reload", "@SG550_Reload") + set_weapon_var(weapon, "forward_idle", "@SG550_Idle") + precache_sound(SG550_SHOOT_SOUND) +} + +@SG550_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, SG550_DRAW, "rifle")) { + return false + } + set_member(weapon, m_Weapon_flAccuracy, 0.9) + return true +} + +@SG550_MaxSpeed(weapon, player, fov) { + return ((fov == DEFAULT_FOV) ? SG550_MAX_SPEED : SG550_MAX_SPEED_ZOOM) +} + +@SG550_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.45 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.15 + } else if (playerFlags & FL_DUCKING) { + spread = 0.04 * (1.0 - accuracy) + } else { + spread = 0.05 * (1.0 - accuracy) + } + new fov = get_member(player, m_iFOV) + if (fov != DEFAULT_FOV) { + spread += 0.025 + } + new Float:time = get_gametime() + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + if (lastFire) { + new Float:accuracy = (time - lastFire) * 0.35 + 0.65 + if (accuracy > 0.98) { + accuracy = 0.98 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, NORMAL_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 2, + BULLET_PLAYER_556MM, + SG550_DAMAGE, + SG550_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(SG550_SHOOT1, SG550_SHOOT2)) + playFireSound(player, SG550_SHOOT_SOUND) + new Float:nextAttack = 0.25 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.8) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= punchAngle[0] * 0.25 + random_float(0.75, 1.25) + punchAngle[1] += random_float(-0.75, 0.75) + set_entvar(player, var_punchangle, punchAngle) +} + +@SG550_SecondaryAttack(weapon, player, WeaponState:weaponState, fov) { + new nextFov + if (fov == DEFAULT_FOV) { + nextFov = 40 + } else if (fov == 40) { + nextFov = 15 + } else { + nextFov = DEFAULT_FOV + } + set_member(player, m_iFOV, nextFov) + rg_reset_maxspeed(player) + emit_sound(player, CHAN_ITEM, "weapons/zoom.wav", 0.2, 2.4, 0, PITCH_NORM) + set_member(weapon, m_Weapon_flNextSecondaryAttack, 0.3) +} + +@SG550_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, SG550_RELOAD, SG550_RELOAD_TIME)) { + return + } + if (get_member(player, m_iFOV) != DEFAULT_FOV) { + set_member(player, m_iFOV, 15) + ExecuteHamB(Ham_Weapon_SecondaryAttack, weapon) + } + rg_set_animation(player, PLAYER_RELOAD) +} + +@SG550_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + if (!get_member(weapon, m_Weapon_iClip)) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 60.0) + send_weapon_anim(player, SG550_IDLE) +} + +const M249_MAX_SPEED = 220 +const M249_WEIGHT = 25 +const M249_DAMAGE = 32 +const Float:M249_RANGE_MODIFER = 0.97 +const Float:M249_RELOAD_TIME = 4.7 +const Float:M249_BASE_ACCURACY = 0.2 +const Float:M249_ACCURACY_DIVISOR = 175.0 +new const M249_SHOOT_SOUND[2][] = { + "weapons/m249-1.wav", + "weapons/m249-2.wav", +} + +enum { + M249_IDLE, + M249_SHOOT1, + M249_SHOOT2, + M249_RELOAD, + M249_DRAW, +} + +createM249() { + new Weapon:weapon = create_weapon("default_m249", weapon_type_primary) + set_weapon_var(weapon, "name", "DEFAULT_M249") + set_weapon_var(weapon, "view_model", create_model("models/v_m249.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_m249.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_m249.mdl")) + set_weapon_var(weapon, "hud", "weapon_m249") + set_weapon_var(weapon, "max_clip", 100) + set_weapon_var(weapon, "max_ammo", 200) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", M249_WEIGHT) + set_weapon_var(weapon, "base_accuracy", M249_BASE_ACCURACY) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size6) + set_weapon_var(weapon, "forward_deploy", "@M249_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@M249_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@M249_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@M249_Reload") + set_weapon_var(weapon, "forward_idle", "@M249_Idle") + precache_sounds(M249_SHOOT_SOUND) +} + +@M249_Deploy(weapon, player) { + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, M249_BASE_ACCURACY) + return weapon_default_deploy(weapon, player, M249_DRAW, "m249") +} + +@M249_MaxSpeed(weapon, player) { + return M249_MAX_SPEED +} + +@M249_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + new Float:playerVelocityLength = playerVelocityLength2d(player) + if (!(playerFlags & FL_ONGROUND)) { + spread = 0.045 + (0.5 * accuracy) + } else if (playerVelocityLength > 140.0) { + spread = 0.045 + (0.095 * accuracy) + } else { + spread = 0.03 * accuracy + } + set_member(weapon, m_Weapon_bDelayFire, true) + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + 1 + set_member(weapon, m_Weapon_iShotsFired, shotsFired) + accuracy = ((shotsFired * shotsFired * shotsFired) / M249_ACCURACY_DIVISOR) + 0.4 + if (accuracy > 0.9) { + accuracy = 0.9 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, NORMAL_GUN_VOLUME) + set_member(player, m_iWeaponFlash, BRIGHT_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 2, + BULLET_PLAYER_556MM, + M249_DAMAGE, + M249_RANGE_MODIFER, + false, + get_member(player, random_seed) + ) + send_weapon_anim(player, random_num(M249_SHOOT1, M249_SHOOT2)) + playFireSound(player, M249_SHOOT_SOUND[random(sizeof(M249_SHOOT_SOUND))]) + new Float:nextAttack = 0.1 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.6) + if (!(playerFlags & FL_ONGROUND)) { + weapon_kick_back(weapon, player, 1.8, 0.65, 0.45, 0.125, 5.0, 3.5, 8) + } else if (playerVelocityLength > 0.0) { + weapon_kick_back(weapon, player, 1.1, 0.5, 0.3, 0.06, 4.0, 3.0, 8) + } else if (playerFlags & FL_DUCKING) { + weapon_kick_back(weapon, player, 0.75, 0.325, 0.25, 0.025, 3.5, 2.5, 9) + } else { + weapon_kick_back(weapon, player, 0.8, 0.35, 0.3, 0.03, 3.75, 3.0, 9) + } +} + +@M249_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, M249_RELOAD, M249_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_bDelayFire, false) + set_member(weapon, m_Weapon_iShotsFired, 0) + set_member(weapon, m_Weapon_flAccuracy, M249_BASE_ACCURACY) +} + +@M249_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, 20.0) + send_weapon_anim(player, M249_IDLE) +} + +const HEGRENADE_MAX_SPEED = 250 +const HEGRENADE_WEIGHT = 2 + +enum { + HEGRENADE_IDLE, + HEGRENADE_PULLPIN, + HEGRENADE_THROW, + HEGRENADE_DRAW, +} + +createHeGrenade() { + new Weapon:weapon = create_weapon("default_hegrenade", weapon_type_grenade) + set_weapon_var(weapon, "name", "DEFAULT_HE_GRENADE") + set_weapon_var(weapon, "view_model", create_model("models/v_hegrenade.mdl")) + set_weapon_var(weapon, "player_model", create_model("models/p_hegrenade.mdl")) + set_weapon_var(weapon, "world_model", create_model("models/w_hegrenade.mdl")) + set_weapon_var(weapon, "hud", "weapon_hegrenade") + set_weapon_var(weapon, "max_ammo", 1) + set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + set_weapon_var(weapon, "weight", HEGRENADE_WEIGHT) + set_weapon_var(weapon, "flags", ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@HeGrenade_Deploy") + set_weapon_var(weapon, "forward_holster", "@HeGrenade_Holster") + set_weapon_var(weapon, "forward_max_speed", "@HeGrenade_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@HeGrenade_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@HeGrenade_Reload") + set_weapon_var(weapon, "forward_idle", "@HeGrenade_Idle") +} + +@HeGrenade_Deploy(weapon, player) { + if (!weapon_default_deploy(weapon, player, HEGRENADE_DRAW, "grenade")) { + return false + } + set_member(weapon, m_flReleaseThrow, -1.0) + return true +} + +@HeGrenade_Holster(weapon, player) { + set_member(player, m_flNextAttack, 0.5) + if (!get_player_var(player, "ammo", weapon)) { + destroyItem(weapon, player) + } + set_member(weapon, m_flStartThrow, 0.0) + set_member(weapon, m_flReleaseThrow, -1.0) +} + +@HeGrenade_MaxSpeed(weapon, player) { + return HEGRENADE_MAX_SPEED +} + +@HeGrenade_PrimaryAttack(weapon, player, clip, ammo) { + if (Float:get_member(weapon, m_flStartThrow) || get_player_var(player, "ammo", weapon) <= 0) { + return + } + set_member(weapon, m_flReleaseThrow, 0.0) + set_member(weapon, m_flStartThrow, get_gametime()) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 0.5) + send_weapon_anim(player, HEGRENADE_PULLPIN) +} + +@HeGrenade_Idle(weapon, player) { + // need rework after grenades + + new Float:startThrow = Float:get_member(weapon, m_flStartThrow) + new Float:releaseThrow = Float:get_member(weapon, m_flReleaseThrow) + if (releaseThrow == 0.0 && startThrow) { + set_member(weapon, m_flReleaseThrow, get_gametime()) + } + if (Float:get_member(weapon, m_Weapon_flTimeWeaponIdle) > 0.0) { + return + } + new ammo = get_player_var(player, "ammo", weapon) + if (startThrow) { + //m_pPlayer->Radio("%!MRAD_FIREINHOLE", "#Fire_in_the_hole"); + new Float:src[3] + new Float:throw[3] + new Float:aimingAngle[3] + new Float:viewForward[3] + new Float:playerVelocity[3] + // to default_projectile_throw + ExecuteHamB(Ham_Player_GetGunPosition, player, src) + get_entvar(player, var_velocity, playerVelocity) + getAimingAngle(player, aimingAngle) + if (aimingAngle[0] < 0.0) { + aimingAngle[0] = -10.0 + aimingAngle[0] * ((80.0) / 90.0) + } else { + aimingAngle[0] = -10.0 + aimingAngle[0] * ((100.0) / 90.0) + } + new Float:velocity = (90.0 - aimingAngle[0]) * 6.0 + if (velocity > 750.0) { + velocity = 750.0 + } + engfunc(EngFunc_MakeVectors, aimingAngle) + global_get(glb_v_forward, viewForward) + for (new i = 0; i < 3; ++i) { + src[i] += viewForward[i] * 16.0 + throw[i] = viewForward[i] * velocity + playerVelocity[i] + } + new grenade = weapon_throw_grenade(weapon, player, src, throw, 1.5) + if (!is_nullent(grenade)) { + SetThink(grenade, "@HeGrenade_Think") + SetTouch(grenade, "@HeGrenade_Touch") + } + send_weapon_anim(player, HEGRENADE_THROW) + rg_set_animation(player, PLAYER_ATTACK1) + set_member(weapon, m_flStartThrow, 0.0) + set_member(weapon, m_Weapon_flNextPrimaryAttack, 0.5) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 0.75) + set_player_var(player, "ammo", weapon, --ammo) + if (ammo <= 0) { + set_member(weapon, m_Weapon_flNextPrimaryAttack, 0.5) + set_member(weapon, m_Weapon_flNextSecondaryAttack, 0.5) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 0.5) + } + } else if (releaseThrow > 0.0) { + set_member(weapon, m_flStartThrow, 0.0) + if (ammo) { + send_weapon_anim(player, HEGRENADE_DRAW) + } else { + ExecuteHamB(Ham_Weapon_RetireWeapon, weapon) + return + } + set_member(weapon, m_flReleaseThrow, -1.0) + set_member(weapon, m_Weapon_flTimeWeaponIdle, random_float(10.0, 15.0)) + } else if (ammo) { + set_member(weapon, m_Weapon_flTimeWeaponIdle, random_float(10.0, 15.0)) + send_weapon_anim(player, HEGRENADE_IDLE) + } +} + +@HeGrenade_Think(grenade) { + /* + if (!IsInWorld()) { + // UTIL_Remove(this); + return; + } + */ + new Float:time = get_gametime() + set_entvar(grenade, var_nextthink, time + 0.1) + if (Float:get_entvar(grenade, var_dmgtime) <= time) { + SetThink(grenade, "") + SetTouch(grenade, "") + set_entvar(grenade, var_flags, FL_KILLME) + return + } + if (get_entvar(grenade, var_waterlevel)) { + modifyVelocityByScalar(grenade, 0.5) + set_entvar(grenade, var_framerate, 0.2) + } +} + +@HeGrenade_Touch(grenade, other) { + if (get_entvar(grenade, var_owner) == other) { + return + } + if (FClassnameIs(other, "func_breakable") && get_entvar(other, var_rendermode) != kRenderNormal) { + modifyVelocityByScalar(grenade, -2.0) + return + } + new flags = get_entvar(grenade, var_flags) + if (flags & FL_ONGROUND) { + modifyVelocityByScalar(grenade, 0.8) + } else { + new bounceCount = get_member(grenade, m_Grenade_iBounceCount) + if (bounceCount < 5) { + emit_sound(grenade, CHAN_VOICE, "weapons/he_bounce-1.wav", 0.25, ATTN_NORM, 0, PITCH_NORM) + } + if (bounceCount >= 10) { + set_entvar(grenade, var_groundentity, -1) // 0 ? + set_entvar(grenade, var_flags, flags | FL_ONGROUND) + set_entvar(grenade, var_velocity, NULL_VECTOR) + } + set_member(grenade, m_Grenade_iBounceCount, ++bounceCount) + } + new Float:velocity[3] + get_entvar(grenade, var_velocity, velocity) + new Float:frameRate = vector_length(velocity) / 200.0 + if (frameRate > 1.0) { + frameRate = 1.0 + } else if (frameRate < 0.5) { + frameRate = 0.0 + } + set_entvar(grenade, var_framerate, frameRate) +} + +destroyItem(weapon, player) { + const WEAPON_SUIT = 31 + if (ExecuteHamB(Ham_RemovePlayerItem, player, weapon)) { + new weaponId = get_member(weapon, m_iId) + new weapons = get_entvar(player, var_weapons) & ~(1< +#include +#include +#include +#include + +const DUAL_DEAGLE_MAX_SPEED = 250 +const DUAL_DEAGLE_WEIGHT = 7 +//const ELITE_WEIGHT = 5 +const DUAL_DEAGLE_DAMAGE = 65 +const Float:DUAL_DEAGLE_RANGE_MODIFER = 0.81 +//const Float:ELITE_RANGE_MODIFER = 0.75 +const Float:DUAL_DEAGLE_RELOAD_TIME = 4.6 +//const Float:ELITE_RELOAD_TIME = 4.5 +new const DUAL_DEAGLE_SHOOT_SOUND[] = "weapons/deagle-1.wav" +//new const ELITE_SHOOT_SOUND[] = "weapons/elite_fire.wav" + +enum { + DUAL_DEAGLE_IDLE, + DUAL_DEAGLE_IDLE_LEFTEMPTY, + DUAL_DEAGLE_SHOOTLEFT1, + DUAL_DEAGLE_SHOOTLEFT2, + DUAL_DEAGLE_SHOOTLEFT3, + DUAL_DEAGLE_SHOOTLEFT4, + DUAL_DEAGLE_SHOOTLEFT5, + DUAL_DEAGLE_SHOOTLEFTLAST, + DUAL_DEAGLE_SHOOTRIGHT1, + DUAL_DEAGLE_SHOOTRIGHT2, + DUAL_DEAGLE_SHOOTRIGHT3, + DUAL_DEAGLE_SHOOTRIGHT4, + DUAL_DEAGLE_SHOOTRIGHT5, + DUAL_DEAGLE_SHOOTRIGHTLAST, + DUAL_DEAGLE_RELOAD, + DUAL_DEAGLE_DRAW, +} + +public plugin_precache() { + register_plugin("Dual Desert Eagle", "1.0.0", "fl0wer") + new Weapon:weapon = create_weapon("cso_dual_deagle", weapon_type_secondary) + set_weapon_var(weapon, "name", "CSO_DUAL_DEAGLE") + set_weapon_var(weapon, "view_model", create_model("rezombie/weapons/ddeagle/v_ddeagle.mdl")) + set_weapon_var(weapon, "player_model", create_model("rezombie/weapons/ddeagle/p_ddeagle.mdl")) + set_weapon_var(weapon, "world_model", create_model("rezombie/weapons/ddeagle/w_ddeagle.mdl")) + set_weapon_var(weapon, "hud", "weapon_elite") + set_weapon_var(weapon, "max_clip", 28) + set_weapon_var(weapon, "max_ammo", 70) + set_weapon_var(weapon, "slot", PISTOL_SLOT) + set_weapon_var(weapon, "weight", DUAL_DEAGLE_WEIGHT) + set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@DualDeagle_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@DualDeagle_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@DualDeagle_PrimaryAttack") + set_weapon_var(weapon, "forward_reload", "@DualDeagle_Reload") + set_weapon_var(weapon, "forward_idle", "@DualDeagle_Idle") + precache_sound(DUAL_DEAGLE_SHOOT_SOUND) + //add_translate("weapons/cso") +} + +@DualDeagle_Deploy(weapon, player) { + set_member(weapon, m_Weapon_flAccuracy, 0.88) + if (!(get_member(weapon, m_Weapon_iClip) & 1)) { + set_member(weapon, m_Weapon_iWeaponState, WPNSTATE_ELITE_LEFT) + } + return weapon_default_deploy(weapon, player, DUAL_DEAGLE_DRAW, "dualpistols") +} + +@DualDeagle_MaxSpeed(weapon, player) { + return DUAL_DEAGLE_MAX_SPEED +} + +@DualDeagle_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.3 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.175 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.08 * (1.0 - accuracy) + } else { + spread = 0.1 * (1.0 - accuracy) + } + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + set_member(weapon, m_Weapon_iShotsFired, ++shotsFired) + if (shotsFired > 1) { + return + } + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:time = get_gametime() + if (lastFire != 0.0) { + accuracy -= (0.325 - (time - lastFire)) * 0.275 + if (accuracy > 0.88) { + accuracy = 0.88 + } else if (accuracy < 0.55) { + accuracy = 0.55 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, DIM_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new WeaponState:weaponState = get_member(weapon, m_Weapon_iWeaponState) + new Float:aiming[3] + new Float:src[3] + new Float:viewRight[3] + getGunPositionAndAiming(player, src, aiming) + global_get(glb_v_right, viewRight) + if (weaponState & WPNSTATE_ELITE_LEFT) { + rg_set_animation(player, PLAYER_ATTACK1) + set_member(weapon, m_Weapon_iWeaponState, weaponState & ~WPNSTATE_ELITE_LEFT) + for (new i = 0; i < sizeof(src); ++i) { + src[i] -= viewRight[i] * 5.0 + } + send_weapon_anim(player, random_num(DUAL_DEAGLE_SHOOTLEFT1, DUAL_DEAGLE_SHOOTLEFT4)) + } else { + rg_set_animation(player, PLAYER_ATTACK2) + set_member(weapon, m_Weapon_iWeaponState, weaponState | WPNSTATE_ELITE_LEFT) + for (new i = 0; i < sizeof(src); ++i) { + src[i] += viewRight[i] * 5.0 + } + send_weapon_anim(player, random_num(DUAL_DEAGLE_SHOOTRIGHT1, DUAL_DEAGLE_SHOOTRIGHT4)) + } + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 8192.0, + 1, + BULLET_PLAYER_9MM, + DUAL_DEAGLE_DAMAGE, + DUAL_DEAGLE_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + playFireSound(player, DUAL_DEAGLE_SHOOT_SOUND) + new Float:nextAttack = 0.2 - 0.078 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 2.0) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} + +@DualDeagle_Reload(weapon, player) { + if (!weapon_default_reload(weapon, player, DUAL_DEAGLE_RELOAD, DUAL_DEAGLE_RELOAD_TIME)) { + return + } + rg_set_animation(player, PLAYER_RELOAD) + set_member(weapon, m_Weapon_flAccuracy, 0.88) +} + +@DualDeagle_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + new clip = get_member(weapon, m_Weapon_iClip) + if (!clip) { + return + } + new anim = (clip == 1) ? DUAL_DEAGLE_IDLE_LEFTEMPTY : DUAL_DEAGLE_IDLE + set_member(weapon, m_Weapon_flTimeWeaponIdle, 60.0) + send_weapon_anim(player, anim) +} + +/* +@DualDeagle_PrimaryAttack(weapon, player, clip, ammo) { + new Float:accuracy = get_member(weapon, m_Weapon_flAccuracy) + new Float:spread + new playerFlags = get_entvar(player, var_flags) + if (!(playerFlags & FL_ONGROUND)) { + spread = 1.5 * (1.0 - accuracy) + } else if (playerVelocityLength2d(player) > 0.0) { + spread = 0.25 * (1.0 - accuracy) + } else if (playerFlags & FL_DUCKING) { + spread = 0.115 * (1.0 - accuracy) + } else { + spread = 0.13 * (1.0 - accuracy) + } + new shotsFired = get_member(weapon, m_Weapon_iShotsFired) + set_member(weapon, m_Weapon_iShotsFired, ++shotsFired) + if (shotsFired > 1) { + return + } + new Float:lastFire = Float:get_member(weapon, m_Weapon_flLastFire) + new Float:time = get_gametime() + if (lastFire != 0.0) { + accuracy -= (0.4 - (time - lastFire)) * 0.35 + if (accuracy > 0.9) { + accuracy = 0.9 + } else if (accuracy < 0.55) { + accuracy = 0.55 + } + set_member(weapon, m_Weapon_flAccuracy, accuracy) + } + set_member(weapon, m_Weapon_flLastFire, time) + if (isEmptyFire(weapon, clip)) { + return + } + set_member(weapon, m_Weapon_iClip, --clip) + set_member(player, m_iWeaponVolume, BIG_EXPLOSION_VOLUME) + set_member(player, m_iWeaponFlash, NORMAL_GUN_FLASH) + set_entvar(player, var_effects, get_entvar(player, var_effects) | EF_MUZZLEFLASH) + new Float:aiming[3] + new Float:src[3] + getGunPositionAndAiming(player, src, aiming) + rg_set_animation(player, PLAYER_ATTACK1) + rg_fire_bullets3( + weapon, + player, + src, + aiming, + spread, + 4096.0, + 2, + BULLET_PLAYER_50AE, + DUAL_DEAGLE_DAMAGE, + DUAL_DEAGLE_RANGE_MODIFER, + true, + get_member(player, random_seed) + ) + send_weapon_anim(player, clip ? random_num(DEAGLE_SHOOT1, DEAGLE_SHOOT2) : DEAGLE_SHOOT_EMPTY) + playFireSound(player, DEAGLE_SHOOT_SOUND[random(sizeof(DEAGLE_SHOOT_SOUND))]) + new Float:nextAttack = 0.3 - 0.075 + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, 1.8) + new Float:punchAngle[3] + get_entvar(player, var_punchangle, punchAngle) + punchAngle[0] -= 2.0 + set_entvar(player, var_punchangle, punchAngle) +} +*/ diff --git a/extra/addons/amxmodx/scripting/rezombie/weapons/grenade_infection.sma b/extra/addons/amxmodx/scripting/rezombie/weapons/grenade_infection.sma new file mode 100644 index 0000000..96e832d --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/weapons/grenade_infection.sma @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include + +new const INFECTION_EXPLODE_SOUND[] = "zombie_plague/grenade_infect.wav" + +new ModelIndex_LaserBeam +new ModelIndex_ShockWave + +new Weapon:InfectGrenade + +new Class:HumanClass +new Class:ZombieClass + +public plugin_precache() { + register_plugin("Grenade: Infection", "1.0.0", "fl0wer") + + HumanClass = checkClassExists("human") + ZombieClass = checkClassExists("zombie") + + new Weapon:weapon = InfectGrenade = create_weapon("weapon_infectgrenade", "weapon_hegrenade") + + rz_weapon_set(weapon, RZ_WEAPON_NAME, "RZ_WPN_INFECT_GRENADE") + rz_weapon_set(weapon, RZ_WEAPON_VIEW_MODEL, "models/zombie_plague/v_grenade_infect.mdl") + + precache_sound(INFECTION_EXPLODE_SOUND) + + ModelIndex_LaserBeam = precache_model("sprites/laserbeam.spr") + ModelIndex_ShockWave = precache_model("sprites/shockwave.spr") +} + +public rz_weapon_grenade_throw_post(id, entity, weapon) { + if (weapon != InfectGrenade) { + return + } + set_entity_render(entity, kRenderNormal, 16, "green", kRenderFxGlowShell) + message_begin_f(MSG_ALL, SVC_TEMPENTITY) + TE_BeamFollow(entity, ModelIndex_LaserBeam, 10, 10, { 0, 200, 0 }, 200) +} + +public rz_weapon_grenade_explode_pre(id, grenade) { + if (weapon != InfectGrenade) { + return + } + new owner = get_entvar(grenade, var_owner) + + new Float:origin[3] + new Float:targetOrigin[3] + new Float:axis[3] + + get_entvar(grenade, var_origin, origin) + + axis = origin + axis[2] += 555.0 + + message_begin_f(MSG_PVS, SVC_TEMPENTITY, origin) + TE_BeamCylinder(origin, axis, ModelIndex_ShockWave, 0, 0, 4, 60, 0, { 0, 200, 0 }, 200, 0) + + rh_emit_sound2(grenade, 0, CHAN_WEAPON, INFECTION_EXPLODE_SOUND) + + if (!is_user_connected(owner) && get_player_var(owner, "class") != ZombieClass) { + owner = 0 + } + for (new target = 1; target <= MaxClients; ++target) { + if (!is_user_alive(target)) { + continue + } + get_entvar(target, var_origin, targetOrigin) + if (vector_distance(origin, targetOrigin) > 350.0) { + continue + } + if (!ExecuteHamB(Ham_FVisible, target, grenade)) { + continue + } + if (get_player_var(target, "class") != HumanClass) { + continue + } + rz_class_player_change(target, owner, ZombieClass) + } +} diff --git a/extra/addons/amxmodx/scripting/rezombie/weapons/knife_strong.sma b/extra/addons/amxmodx/scripting/rezombie/weapons/knife_strong.sma new file mode 100644 index 0000000..67fb0b4 --- /dev/null +++ b/extra/addons/amxmodx/scripting/rezombie/weapons/knife_strong.sma @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include + +const STRONG_PRIMARY_DAMAGE = 75 +const STRONG_PRIMARY_DISTANCE = 32 +const STRONG_SECONDARY_DAMAGE = 200 +const STRONG_SECONDARY_DISTANCE = 64 +const Float:SRTONG_SECONDARY_BACK_DAMAGE_MULTIPLIER = 3.0 +const STRONG_MAX_SPEED = 250 +const STRONG_WEIGHT = 5 + +enum { + STRONG_IDLE, + STRONG_SLASH1, + STRONG_SLASH2, + STRONG_DRAW, + STRONG_STAB, + STRONG_STAB_MISS, + STRONG_MIDSLASH1, + STRONG_MIDSLASH2, +} + +new const DRAW_SOUND[] = "rezombie/weapons/knife_strong/draw.wav" +new const HIT_SOUNDS[][] = { + "rezombie/weapons/knife_strong/hit1.wav", + "rezombie/weapons/knife_strong/hit2.wav", +} +new const SLASH_SOUND[] = "rezombie/weapons/knife_strong/slash.wav" +new const STAB_SOUND[] = "rezombie/weapons/knife_strong/stab.wav" +new const WALL_SOUND[] = "rezombie/weapons/knife_strong/wall.wav" +new const HUD_SPRITE[] = "sprites/rezombie/knife_strong/640hud23.spr" + +public plugin_precache() { + register_plugin("Knife: Strong", "1.0.0", "fl0wer") + + new Weapon:weapon = create_weapon("knife_strong", weapon_type_melee) + set_weapon_var(weapon, "name", "KNIFE_STRONG") + set_weapon_var(weapon, "view_model", create_model("rezombie/weapons/knife_strong/v_knife.mdl")) + //set_weapon_var(weapon, "player_model", create_model("models/weapons/knife_strong/p.mdl")) + set_weapon_var(weapon, "hud", "rezombie/knife_strong/hud") + //set_weapon_var(weapon, "max_clip", 20) + //set_weapon_var(weapon, "max_ammo", 120) + //set_weapon_var(weapon, "slot", PRIMARY_WEAPON_SLOT) + //set_weapon_var(weapon, "weight", GLOCK18_WEIGHT) + //set_weapon_var(weapon, "crosshair_size", CrosshairSize_Size8) + set_weapon_var(weapon, "forward_deploy", "@Strong_Deploy") + set_weapon_var(weapon, "forward_max_speed", "@Strong_MaxSpeed") + set_weapon_var(weapon, "forward_primary_attack", "@Strong_PrimaryAttack") + set_weapon_var(weapon, "forward_secondary_attack", "@Strong_SecondaryAttack") + //set_weapon_var(weapon, "forward_idle", "@Glock18_Idle") + + precache_sound(DRAW_SOUND) + precache_sounds(HIT_SOUNDS) + precache_sound(SLASH_SOUND) + precache_sound(STAB_SOUND) + precache_sound(WALL_SOUND) + precache_model(HUD_SPRITE) +} + +@Strong_Deploy(weapon, player) { + new bool:result = weapon_default_deploy(weapon, player, STRONG_DRAW, "knife") + if (result) { + set_member(player, m_flNextAttack, 1.0) + rh_emit_sound2(player, 0, CHAN_ITEM, DRAW_SOUND) + } + return result +} + +@Strong_MaxSpeed(weapon, player) { + return STRONG_MAX_SPEED +} + +@Strong_PrimaryAttack(weapon, player) { + new MeleeAttackResult:result = melee_default_attack( + weapon, + player, + STRONG_PRIMARY_DAMAGE, + STRONG_PRIMARY_DISTANCE + ) + new Float:nextAttack + new Float:idleTime + switch (result) { + case melee_attack_miss: { + nextAttack = idleTime = 2.2 + send_weapon_anim(player, random_num(STRONG_SLASH1, STRONG_SLASH2)) + play_weapon_sound(player, SLASH_SOUND) + } + case melee_attack_hit: { + nextAttack = idleTime = 1.2 + send_weapon_anim(player, random_num(STRONG_MIDSLASH1, STRONG_MIDSLASH2)) + play_random_weapon_sound(player, HIT_SOUNDS) + } + case melee_attack_hit_wall: { + nextAttack = idleTime = 1.2 + send_weapon_anim(player, random_num(STRONG_MIDSLASH1, STRONG_MIDSLASH2)) + play_weapon_sound(player, WALL_SOUND) + } + } + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, idleTime) + return result +} + +@Strong_SecondaryAttack(weapon, player) { + new MeleeAttackResult:result = melee_default_attack( + weapon, + player, + STRONG_SECONDARY_DAMAGE, + STRONG_SECONDARY_DISTANCE, + SRTONG_SECONDARY_BACK_DAMAGE_MULTIPLIER + ) + new Float:nextAttack + new Float:idleTime + switch (result) { + case melee_attack_miss: { + nextAttack = idleTime = 1.75 + send_weapon_anim(player, STRONG_STAB_MISS) + play_weapon_sound(player, SLASH_SOUND) + } + case melee_attack_hit: { + nextAttack = idleTime = 2.0 + send_weapon_anim(player, STRONG_STAB) + play_weapon_sound(player, STAB_SOUND) + } + case melee_attack_hit_wall: { + nextAttack = idleTime = 2.0 + send_weapon_anim(player, STRONG_STAB) + play_weapon_sound(player, WALL_SOUND) + } + } + set_member(weapon, m_Weapon_flNextPrimaryAttack, nextAttack) + set_member(weapon, m_Weapon_flNextSecondaryAttack, nextAttack) + set_member(weapon, m_Weapon_flTimeWeaponIdle, idleTime) + return result +} + +@Glock18_Idle(weapon, player, Float:idleTime) { + // need rework after grenades + /*ExecuteHamB(Ham_Weapon_ResetEmptySound, weapon) + if (idleTime > 0.0) { + return + } + if (!get_member(weapon, m_Weapon_iClip)) { + return + } + new Float:random = random_float(0.0, 1.0) + new anim + new Float:time + if (random <= 0.3) { + anim = GLOCK18_IDLE3 + time = 3.0625 + } else if (random <= 0.6) { + anim = GLOCK18_IDLE1 + time = 3.75 + } else { + anim = GLOCK18_IDLE2 + time = 2.5 + } + set_member(weapon, m_Weapon_flTimeWeaponIdle, time) + send_weapon_anim(player, anim)*/ +} diff --git a/extra/rezombie/configs/main.json b/extra/rezombie/configs/main.json new file mode 100644 index 0000000..fe17fad --- /dev/null +++ b/extra/rezombie/configs/main.json @@ -0,0 +1,4 @@ +{ + "happy": true, + "pi": 3.141 +} diff --git a/extra/rezombie/translates/en/awards.txt b/extra/rezombie/translates/en/awards.txt new file mode 100644 index 0000000..e85ef67 --- /dev/null +++ b/extra/rezombie/translates/en/awards.txt @@ -0,0 +1,6 @@ +[en] +RZ_AWARD_PLAYER_KILLED = Award for neutralizing an enemy. +RZ_AWARD_PLAYER_INFECT = Award for infecting an enemy. +RZ_AWARD_TEAM_WIN = Team award. +RZ_AWARD_TEAM_LOSER = Income for losing. +RZ_AWARD_TEAM_DRAW = Team award. diff --git a/extra/rezombie/translates/en/classes/assassin.txt b/extra/rezombie/translates/en/classes/assassin.txt new file mode 100644 index 0000000..b549e7a --- /dev/null +++ b/extra/rezombie/translates/en/classes/assassin.txt @@ -0,0 +1,2 @@ +[en] +RZ_ASSASSIN = Assassin diff --git a/extra/rezombie/translates/en/classes/human.txt b/extra/rezombie/translates/en/classes/human.txt new file mode 100644 index 0000000..0b16567 --- /dev/null +++ b/extra/rezombie/translates/en/classes/human.txt @@ -0,0 +1,2 @@ +[en] +RZ_HUMAN = Human diff --git a/extra/rezombie/translates/en/classes/nemesis.txt b/extra/rezombie/translates/en/classes/nemesis.txt new file mode 100644 index 0000000..4650f8d --- /dev/null +++ b/extra/rezombie/translates/en/classes/nemesis.txt @@ -0,0 +1,2 @@ +[en] +RZ_NEMESIS = Nemesis diff --git a/extra/rezombie/translates/en/classes/sniper.txt b/extra/rezombie/translates/en/classes/sniper.txt new file mode 100644 index 0000000..2cff4e7 --- /dev/null +++ b/extra/rezombie/translates/en/classes/sniper.txt @@ -0,0 +1,2 @@ +[en] +RZ_SNIPER = Sniper diff --git a/extra/rezombie/translates/en/classes/survivor.txt b/extra/rezombie/translates/en/classes/survivor.txt new file mode 100644 index 0000000..53c7088 --- /dev/null +++ b/extra/rezombie/translates/en/classes/survivor.txt @@ -0,0 +1,2 @@ +[en] +RZ_SURVIVOR = Survivor diff --git a/extra/rezombie/translates/en/classes/zombie.txt b/extra/rezombie/translates/en/classes/zombie.txt new file mode 100644 index 0000000..18feeee --- /dev/null +++ b/extra/rezombie/translates/en/classes/zombie.txt @@ -0,0 +1,2 @@ +[en] +RZ_ZOMBIE = Zombie diff --git a/extra/rezombie/translates/en/common.txt b/extra/rezombie/translates/en/common.txt new file mode 100644 index 0000000..f4a168c --- /dev/null +++ b/extra/rezombie/translates/en/common.txt @@ -0,0 +1,49 @@ +[en] +RZ_SPECTATING = Spectating +RZ_AMMOPACKS = Ammo packs +RZ_TURN_INTO = Turn into +RZ_DEAD = *DEAD* +RZ_AUTOSELECT = Auto Select +RZ_TIME_LEFT = Time Left +RZ_MENU_WPN_TITLE = Select Weapons +RZ_MENU_WPN_TIMER = Remaining time +RZ_MENU_WPN_FIELD_WPN = Weapons +RZ_MENU_WPN_FIELD_EQUIP = Equipment +RZ_MENU_WPN_SEC_TITLE = Select +RZ_MENU_WPN_SEC_PISTOL = Pistol +RZ_MENU_WPN_SEC_SHOTGUN = Shotgun +RZ_MENU_WPN_SEC_SMG = SMG +RZ_MENU_WPN_SEC_RIFLE = Rifle +RZ_MENU_WPN_SEC_MACHINEGUN = Machine Gun +RZ_MENU_WPN_SEC_EQUIP = Equipment +RZ_MENU_WPN_SEC_KNIFE = Knife +RZ_MENU_WPN_BUY_SELECT = Buy Selection +RZ_WIN_HUMAN = Humans Win! +RZ_WIN_ZOMBIE = Zombies Win! +RZ_WIN_NO_ONE = No one won... +RZ_SELECT_SUBCLASS = Select %l Class +RZ_PRESS_GAME_MENU = Press ^4«M» ^1to show the game menu +RZ_PRESS_BUY_AMMO = Press ^4«,» ^1or ^4«.» ^1to purchase ammo +RZ_WARMUP = WARMUP %d:%02d +RZ_WARMUP_END = WARMUP ENDING IN %d:%02d +RZ_WARMUP_START = WAR STARTING IN %d... +RZ_INFECTION_START = INFECTION STARTING IN %d... +RZ_ROUND_END = ROUND ENDING IN %d... +RZ_NOTICE_VIRUS_FREE = The virus has been set loose... + +EMPTY = Empty +NEXT = Next +BACK = Back +EXIT = Exit +CLOSE = Close +CURRENT = Current +FRIEND = Friend +ENEMY = Enemy +HEALTH = Health +CLASS = Class +YOUR_AUTH_ID = Your Auth ID: %s + +ROUND_VICTORY = VICTORY +ROUND_DEFEAT = DEFEAT +ROUND_HUMANS_WIN = HUMANS WIN +ROUND_ZOMBIES_WIN = ZOMBIES WIN diff --git a/extra/rezombie/translates/en/currency/ammo_packs.txt b/extra/rezombie/translates/en/currency/ammo_packs.txt new file mode 100644 index 0000000..ac3e728 --- /dev/null +++ b/extra/rezombie/translates/en/currency/ammo_packs.txt @@ -0,0 +1,5 @@ +[en] +AMMO_PACKS_SHORT = AP +AMMO_PACKS_ONE = ammo pack +AMMO_PACKS_FEW = ammo packs +AMMO_PACKS_MANY = ammo packs diff --git a/extra/rezombie/translates/en/items.txt b/extra/rezombie/translates/en/items.txt new file mode 100644 index 0000000..0332667 --- /dev/null +++ b/extra/rezombie/translates/en/items.txt @@ -0,0 +1,15 @@ +[en] +RZ_ITEMS_INSUFFICIENT_FUNDS = Insufficient funds to purchase! ^3%L^1 cost: ^4%L +RZ_ITEMS_PLAYER_BOUGHT = Player ^3%n ^1bought ^4%l +RZ_ITEMS_TITLE = Extra Items +RZ_ITEM_MADNESS = Madness +RZ_ITEM_ANTIDOTE = Antidote +RZ_ITEM_NIGHTVISION = Nightvision +RZ_ITEM_WPN_AWP = AWP Magnum Sniper +RZ_ITEM_WPN_M249 = M249 Para Machinegun +RZ_ITEM_WPN_SG550 = SG550 Auto-Sniper +RZ_ITEM_WPN_G3SG1 = G3SG1 Auto-Sniper +RZ_ITEM_NADE_INFECTION = Infection Bomb +RZ_ITEM_NADE_FIRE = Napalm Grenade +RZ_ITEM_NADE_FROST = Frost Grenade +RZ_ITEM_NADE_FLARE = Flare Grenade diff --git a/extra/rezombie/translates/en/items/human_armor.txt b/extra/rezombie/translates/en/items/human_armor.txt new file mode 100644 index 0000000..6cea97f --- /dev/null +++ b/extra/rezombie/translates/en/items/human_armor.txt @@ -0,0 +1,2 @@ +[en] +RZ_ITEM_ARMOR = Armor diff --git a/extra/rezombie/translates/en/menus/game.txt b/extra/rezombie/translates/en/menus/game.txt new file mode 100644 index 0000000..6ed882c --- /dev/null +++ b/extra/rezombie/translates/en/menus/game.txt @@ -0,0 +1,8 @@ +[en] +GAME_MENU_TITLE = Game Menu +GAME_MENU_SELECT_WPNS = Select Weapons +GAME_MENU_BUY_EXTRA = Buy Extra Items +GAME_MENU_CHOOSE_SUBCLASS = Choose %l Class +GAME_MENU_JOIN_GAME = Join Game +GAME_MENU_JOIN_SPECS = Join Spectators +GAME_MENU_ADMIN = Admin Menu diff --git a/extra/rezombie/translates/en/menus/items.txt b/extra/rezombie/translates/en/menus/items.txt new file mode 100644 index 0000000..1f8ce02 --- /dev/null +++ b/extra/rezombie/translates/en/menus/items.txt @@ -0,0 +1,6 @@ +[en] +ITEMS_MENU_TITLE = Extra Items +ITEMS_MENU_PLAYER_BOUGHT = %l ^3%n ^1bought ^4%l ^1for ^4%s +ITEMS_MENU_PLAYER_TAKEN = %l ^3%n ^1taken ^4%l +ITEMS_MENU_INSUFFICIENT_FUNDS = Insufficient funds to purchase ^4%l^1! Not enough: ^3%s +ITEMS_MENU_SOMETHING_WENT_WRONG = ^3Something went wrong during the purchase... diff --git a/extra/rezombie/translates/en/modes/armageddon.txt b/extra/rezombie/translates/en/modes/armageddon.txt new file mode 100644 index 0000000..0f220bb --- /dev/null +++ b/extra/rezombie/translates/en/modes/armageddon.txt @@ -0,0 +1,4 @@ +[en] +MODE_ARMAGEDDON_NAME = Armageddon +MODE_ARMAGEDDON_DESC = Survivors & Snipers vs Nemesis & Assassins +MODE_ARMAGEDDON_NOTICE = Survivors & Snipers vs Nemesis & Assassins diff --git a/extra/rezombie/translates/en/modes/assassin.txt b/extra/rezombie/translates/en/modes/assassin.txt new file mode 100644 index 0000000..009dd77 --- /dev/null +++ b/extra/rezombie/translates/en/modes/assassin.txt @@ -0,0 +1,4 @@ +[en] +MODE_ASSASSIN_NAME = Assassin +MODE_ASSASSIN_DESC = Assassin vs Humans +MODE_ASSASSIN_NOTICE = Assassin (%n) vs humans diff --git a/extra/rezombie/translates/en/modes/infection.txt b/extra/rezombie/translates/en/modes/infection.txt new file mode 100644 index 0000000..8f9e14e --- /dev/null +++ b/extra/rezombie/translates/en/modes/infection.txt @@ -0,0 +1,4 @@ +[en] +MODE_INFECTION_NAME = Multiple Infection +MODE_INFECTION_DESC = Humans vs Zombies +MODE_INFECTION_NOTICE = Humans vs zombies diff --git a/extra/rezombie/translates/en/modes/nemesis.txt b/extra/rezombie/translates/en/modes/nemesis.txt new file mode 100644 index 0000000..426672b --- /dev/null +++ b/extra/rezombie/translates/en/modes/nemesis.txt @@ -0,0 +1,4 @@ +[en] +MODE_NEMESIS_NAME = Nemesis +MODE_NEMESIS_DESC = Nemesis vs Humans +MODE_NEMESIS_NOTICE = Nemesis (%n) vs humans diff --git a/extra/rezombie/translates/en/modes/plague.txt b/extra/rezombie/translates/en/modes/plague.txt new file mode 100644 index 0000000..536c793 --- /dev/null +++ b/extra/rezombie/translates/en/modes/plague.txt @@ -0,0 +1,4 @@ +[en] +MODE_PLAGUE_NAME = Plague +MODE_PLAGUE_DESC = Humans & Survivor vs Zombies & Nemesis +MODE_PLAGUE_NOTICE = Humans & Survivor vs Zombies & Nemesis diff --git a/extra/rezombie/translates/en/modes/sniper.txt b/extra/rezombie/translates/en/modes/sniper.txt new file mode 100644 index 0000000..498ebe5 --- /dev/null +++ b/extra/rezombie/translates/en/modes/sniper.txt @@ -0,0 +1,4 @@ +[en] +MODE_SNIPER_NAME = Sniper +MODE_SNIPER_DESC = Sniper vs Zombies +MODE_SNIPER_NOTICE = Sniper (%n) vs zombies diff --git a/extra/rezombie/translates/en/modes/snipers_vs_assassins.txt b/extra/rezombie/translates/en/modes/snipers_vs_assassins.txt new file mode 100644 index 0000000..c059259 --- /dev/null +++ b/extra/rezombie/translates/en/modes/snipers_vs_assassins.txt @@ -0,0 +1,4 @@ +[en] +MODE_SVA_NAME = Snipers vs Assassins +MODE_SVA_DESC = Snipers vs Assassins +MODE_SVA_NOTICE = Snipers vs Assassins diff --git a/extra/rezombie/translates/en/modes/survivor.txt b/extra/rezombie/translates/en/modes/survivor.txt new file mode 100644 index 0000000..199efe9 --- /dev/null +++ b/extra/rezombie/translates/en/modes/survivor.txt @@ -0,0 +1,4 @@ +[en] +MODE_SURVIVOR_NAME = Survivor +MODE_SURVIVOR_DESC = Survivor vs Zombies +MODE_SURVIVOR_NOTICE = Survivor (%n) vs zombies diff --git a/extra/rezombie/translates/en/modes/swarm.txt b/extra/rezombie/translates/en/modes/swarm.txt new file mode 100644 index 0000000..d8fdabc --- /dev/null +++ b/extra/rezombie/translates/en/modes/swarm.txt @@ -0,0 +1,4 @@ +[en] +MODE_SWARM_NAME = Swarm +MODE_SWARM_DESC = Humans vs Zombies +MODE_SWARM_NOTICE = Humans vs zombies diff --git a/extra/rezombie/translates/en/subclasses/human_dead_inside.txt b/extra/rezombie/translates/en/subclasses/human_dead_inside.txt new file mode 100644 index 0000000..e80cc23 --- /dev/null +++ b/extra/rezombie/translates/en/subclasses/human_dead_inside.txt @@ -0,0 +1,3 @@ +[en] +RZ_SUBHUMAN_DEAD_NAME = Dead Inside +RZ_SUBHUMAN_DEAD_DESC = Armor+ diff --git a/extra/rezombie/translates/en/subclasses/human_techno_dancer.txt b/extra/rezombie/translates/en/subclasses/human_techno_dancer.txt new file mode 100644 index 0000000..b0445f7 --- /dev/null +++ b/extra/rezombie/translates/en/subclasses/human_techno_dancer.txt @@ -0,0 +1,3 @@ +[en] +RZ_SUBHUMAN_TECHNO_NAME = Techno Dancer +RZ_SUBHUMAN_TECHNO_DESC = HP+ diff --git a/extra/rezombie/translates/en/subclasses/zombie_jumper.txt b/extra/rezombie/translates/en/subclasses/zombie_jumper.txt new file mode 100644 index 0000000..159e9aa --- /dev/null +++ b/extra/rezombie/translates/en/subclasses/zombie_jumper.txt @@ -0,0 +1,3 @@ +[en] +RZ_SUBZOMBIE_JUMPER_NAME = Jumper +RZ_SUBZOMBIE_JUMPER_DESC = Gravity+ diff --git a/extra/rezombie/translates/en/subclasses/zombie_sprinter.txt b/extra/rezombie/translates/en/subclasses/zombie_sprinter.txt new file mode 100644 index 0000000..afcf542 --- /dev/null +++ b/extra/rezombie/translates/en/subclasses/zombie_sprinter.txt @@ -0,0 +1,3 @@ +[en] +RZ_SUBZOMBIE_SPRINTER_NAME = Sprinter +RZ_SUBZOMBIE_SPRINTER_DESC = Speed+ diff --git a/extra/rezombie/translates/en/subclasses/zombie_stone.txt b/extra/rezombie/translates/en/subclasses/zombie_stone.txt new file mode 100644 index 0000000..597f8b8 --- /dev/null +++ b/extra/rezombie/translates/en/subclasses/zombie_stone.txt @@ -0,0 +1,3 @@ +[en] +RZ_SUBZOMBIE_STONE_NAME = Stone +RZ_SUBZOMBIE_STONE_DESC = HP+ diff --git a/extra/rezombie/translates/en/weapons/default.txt b/extra/rezombie/translates/en/weapons/default.txt new file mode 100644 index 0000000..d1af729 --- /dev/null +++ b/extra/rezombie/translates/en/weapons/default.txt @@ -0,0 +1,45 @@ +[en] +DEFAULT_GLOCK18 = Glock-18 +DEFAULT_USP = USP +DEFAULT_P228 = 228 Compact +DEFAULT_DEAGLE = Desert Eagle +DEFAULT_ELITE = Dual Berettas +DEFAULT_FIVESEVEN = Five-SeveN + +DEFAULT_M3 = M3 +DEFAULT_XM1014 = XM1014 + +DEFAULT_MAC10 = MAC-10 +DEFAULT_TMP = TMP +DEFAULT_MP5 = MP5 +DEFAULT_UMP45 = UMP-45 +DEFAULT_P90 = P90 + +DEFAULT_GALIL = Galil +DEFAULT_FAMAS = FAMAS +DEFAULT_AK47 = AK-47 +DEFAULT_M4A1 = M4A1 +DEFAULT_SG552 = SG 552 +DEFAULT_AUG = AUG +DEFAULT_SCOUT = Scout +DEFAULT_AWP = AWP +DEFAULT_G3SG1 = G3SG1 +DEFAULT_SG550 = SG 550 + +DEFAULT_M249 = M249 + +DEFAULT_HE_GRENADE = HE Grenade +DEFAULT_HE_SHORT = HE +DEFAULT_FLASHBANG = Flashbang +DEFAULT_FB_SHORT = FB +DEFAULT_SMOKE_GRENADE = Smoke Grenade +DEFAULT_SMOKE_SHORT = Smoke + +DEFAULT_FIRE_GRENADE = Fire Grenade +DEFAULT_FIRE_SHORT = Fire +DEFAULT_FROST_GRENADE = Frost Grenade +DEFAULT_FROST_SHORT = Frost +DEFAULT_FLARE_GRENADE = Flare Grenade +DEFAULT_FLARE_SHORT = Flare + +DEFAULT_KNIFE = Knife diff --git a/extra/rezombie/translates/ru/awards.txt b/extra/rezombie/translates/ru/awards.txt new file mode 100644 index 0000000..60a9738 --- /dev/null +++ b/extra/rezombie/translates/ru/awards.txt @@ -0,0 +1,6 @@ +[ru] +RZ_AWARD_PLAYER_KILLED = Награда за нейтрализацию врага. +RZ_AWARD_PLAYER_INFECT = Награда за заражение врага. +RZ_AWARD_TEAM_WIN = Командная награда. +RZ_AWARD_TEAM_LOSER = Награда за проигрыш. +RZ_AWARD_TEAM_DRAW = Командная награда. diff --git a/extra/rezombie/translates/ru/classes/assassin.txt b/extra/rezombie/translates/ru/classes/assassin.txt new file mode 100644 index 0000000..a4225f3 --- /dev/null +++ b/extra/rezombie/translates/ru/classes/assassin.txt @@ -0,0 +1,2 @@ +[ru] +RZ_ASSASSIN = Ассасин diff --git a/extra/rezombie/translates/ru/classes/human.txt b/extra/rezombie/translates/ru/classes/human.txt new file mode 100644 index 0000000..2534131 --- /dev/null +++ b/extra/rezombie/translates/ru/classes/human.txt @@ -0,0 +1,2 @@ +[ru] +RZ_HUMAN = Человек diff --git a/extra/rezombie/translates/ru/classes/nemesis.txt b/extra/rezombie/translates/ru/classes/nemesis.txt new file mode 100644 index 0000000..31e05d3 --- /dev/null +++ b/extra/rezombie/translates/ru/classes/nemesis.txt @@ -0,0 +1,2 @@ +[ru] +RZ_NEMESIS = Немезида diff --git a/extra/rezombie/translates/ru/classes/sniper.txt b/extra/rezombie/translates/ru/classes/sniper.txt new file mode 100644 index 0000000..676a7d0 --- /dev/null +++ b/extra/rezombie/translates/ru/classes/sniper.txt @@ -0,0 +1,2 @@ +[ru] +RZ_SNIPER = Снайпер diff --git a/extra/rezombie/translates/ru/classes/survivor.txt b/extra/rezombie/translates/ru/classes/survivor.txt new file mode 100644 index 0000000..6fac4ff --- /dev/null +++ b/extra/rezombie/translates/ru/classes/survivor.txt @@ -0,0 +1,2 @@ +[ru] +RZ_SURVIVOR = Выживший diff --git a/extra/rezombie/translates/ru/classes/zombie.txt b/extra/rezombie/translates/ru/classes/zombie.txt new file mode 100644 index 0000000..21cfb86 --- /dev/null +++ b/extra/rezombie/translates/ru/classes/zombie.txt @@ -0,0 +1,2 @@ +[ru] +RZ_ZOMBIE = Зомби diff --git a/extra/rezombie/translates/ru/common.txt b/extra/rezombie/translates/ru/common.txt new file mode 100644 index 0000000..fb3eacd --- /dev/null +++ b/extra/rezombie/translates/ru/common.txt @@ -0,0 +1,49 @@ +[ru] +RZ_SPECTATING = Наблюдение +RZ_AMMOPACKS = Кредиты +RZ_TURN_INTO = Превратить в +RZ_DEAD = *МЕРТВ* +RZ_AUTOSELECT = Авто-выбор +RZ_TIME_LEFT = Осталось времени +RZ_MENU_WPN_TITLE = Выбор оружия +RZ_MENU_WPN_TIMER = Осталось +RZ_MENU_WPN_FIELD_WPN = Оружие +RZ_MENU_WPN_FIELD_EQUIP = Экипировка +RZ_MENU_WPN_SEC_TITLE = Выбор +RZ_MENU_WPN_SEC_PISTOL = Пистолет +RZ_MENU_WPN_SEC_SHOTGUN = Дробовик +RZ_MENU_WPN_SEC_SMG = Пистолет-пулемет +RZ_MENU_WPN_SEC_RIFLE = Винтовка +RZ_MENU_WPN_SEC_MACHINEGUN = Тяжелое +RZ_MENU_WPN_SEC_EQUIP = Снаряжение +RZ_MENU_WPN_SEC_KNIFE = Нож +RZ_MENU_WPN_BUY_SELECT = Купить +RZ_WIN_HUMAN = Люди победили! +RZ_WIN_ZOMBIE = Зомби победили! +RZ_WIN_NO_ONE = На этот раз ничья... +RZ_SELECT_SUBCLASS = Выбор класса %l +RZ_PRESS_GAME_MENU = Нажмите ^4«M» ^1чтобы открыть игровое меню +RZ_PRESS_BUY_AMMO = Нажмите ^4«,» ^1или ^4«.» ^1для покупки патронов +RZ_WARMUP = РАЗМИНКА %d:%02d +RZ_WARMUP_END = РАЗМИНКА ЗАКОНЧИТСЯ ЧЕРЕЗ %d:%02d +RZ_WARMUP_START = ВОЙНА НАЧНЕТСЯ ЧЕРЕЗ %d... +RZ_INFECTION_START = ЗАРАЖЕНИЕ НАЧНЕТСЯ ЧЕРЕЗ %d... +RZ_ROUND_END = РАУНД ЗАКОНЧИТСЯ ЧЕРЕЗ %d... +RZ_NOTICE_VIRUS_FREE = Вирус витает в воздухе... + +EMPTY = Пусто +NEXT = Далее +BACK = Назад +EXIT = Выход +CLOSE = Закрыть +CURRENT = Текущий +FRIEND = Друг +ENEMY = Враг +HEALTH = Здоровье +CLASS = Класс +YOUR_AUTH_ID = Ваш Auth ID: %s + +ROUND_VICTORY = ПОБЕДА +ROUND_DEFEAT = ПОРАЖЕНИЕ +ROUND_HUMANS_WIN = ЛЮДИ ПОБЕДИЛИ +ROUND_ZOMBIES_WIN = ЗОМБИ ПОБЕДИЛИ diff --git a/extra/rezombie/translates/ru/currency/ammo_packs.txt b/extra/rezombie/translates/ru/currency/ammo_packs.txt new file mode 100644 index 0000000..41ea7e1 --- /dev/null +++ b/extra/rezombie/translates/ru/currency/ammo_packs.txt @@ -0,0 +1,5 @@ +[ru] +AMMO_PACKS_SHORT = кр. +AMMO_PACKS_ONE = кредит +AMMO_PACKS_FEW = кредита +AMMO_PACKS_MANY = кредитов diff --git a/extra/rezombie/translates/ru/items.txt b/extra/rezombie/translates/ru/items.txt new file mode 100644 index 0000000..aa7d4e0 --- /dev/null +++ b/extra/rezombie/translates/ru/items.txt @@ -0,0 +1,12 @@ +[ru] +RZ_ITEM_MADNESS = Бешенство +RZ_ITEM_ANTIDOTE = Антидот +RZ_ITEM_NIGHTVISION = Ночное видение +RZ_ITEM_WPN_AWP = Винтовка AWP +RZ_ITEM_WPN_M249 = Пулемет M249 +RZ_ITEM_WPN_SG550 = Винтовка SG550 +RZ_ITEM_WPN_G3SG1 = Винтовка G3SG1 +RZ_ITEM_NADE_INFECTION = Граната-вирус +RZ_ITEM_NADE_FIRE = Граната Napalm +RZ_ITEM_NADE_FROST = Граната Frost +RZ_ITEM_NADE_FLARE = Граната Flare diff --git a/extra/rezombie/translates/ru/items/human_armor.txt b/extra/rezombie/translates/ru/items/human_armor.txt new file mode 100644 index 0000000..9dd4720 --- /dev/null +++ b/extra/rezombie/translates/ru/items/human_armor.txt @@ -0,0 +1,2 @@ +[ru] +RZ_ITEM_ARMOR = Бронежилет diff --git a/extra/rezombie/translates/ru/menus/admin.txt b/extra/rezombie/translates/ru/menus/admin.txt new file mode 100644 index 0000000..a157d1d --- /dev/null +++ b/extra/rezombie/translates/ru/menus/admin.txt @@ -0,0 +1,27 @@ +[ru] +ADMIN_MENU_ITEM = Меню админа +ADMIN_MENU_TITLE = Меню админа +ADMIN_GAME_SUBTITLE = Игра +ADMIN_PLAYERS_SUBTITLE = Игроки + +MODES_MENU_ITEM = Запустить режим +MODES_MENU_TITLE = Игровые режимы +MODE_WITH_TARGET = цель +LAUNCH_MODE_AFTER_PREPARE = После подготовки +LAUNCH_MODE_AFTER_INSTANTLY = Мгновенно + +SELECT_MODE_TARGET_TITLE = Выбор цели +SELECT_MODE_TARGET_SUBTITLE = для режима \r%l +SELECT_MODE_TARGET_RANDOM = Случайный игрок + +COMPLETE_WARMUP_ITEM = Завершить разминку +COMPLETE_ROUND_ITEM = Завершить раунд +COMPLETE_ROUND_TITLE = Завершить раунд + +CHANGE_CLASS_MENU_ITEM = Сменить класс +CHANGE_CLASS_MENU_TITLE = Сменить класс +TURN_INTO_CLASS_ITEM = превратить в + +RESPAWN_MENU_ITEM = Возродить +RESPAWN_MENU_TITLE = Возродить +RESPAWN_MENU_SUBTITLE = Мертвых игроков: \r%d diff --git a/extra/rezombie/translates/ru/menus/game.txt b/extra/rezombie/translates/ru/menus/game.txt new file mode 100644 index 0000000..0d2347d --- /dev/null +++ b/extra/rezombie/translates/ru/menus/game.txt @@ -0,0 +1,8 @@ +[ru] +GAME_MENU_TITLE = Игровое меню +GAME_MENU_SELECT_WPNS = Выбрать оружие +GAME_MENU_BUY_EXTRA = Купить Спец-вещи +GAME_MENU_CHOOSE_SUBCLASS = Выбрать %l класс +GAME_MENU_JOIN_GAME = Войти в игру +GAME_MENU_JOIN_SPECS = В зрители +GAME_MENU_ADMIN = Админ-меню diff --git a/extra/rezombie/translates/ru/menus/items.txt b/extra/rezombie/translates/ru/menus/items.txt new file mode 100644 index 0000000..941eea6 --- /dev/null +++ b/extra/rezombie/translates/ru/menus/items.txt @@ -0,0 +1,6 @@ +[ru] +ITEMS_MENU_TITLE = Специальные вещи +ITEMS_MENU_PLAYER_BOUGHT = %l ^3%n ^1купил ^4%l ^1за ^4%s +ITEMS_MENU_PLAYER_TAKEN = %l ^3%n ^1взял ^4%l +ITEMS_MENU_INSUFFICIENT_FUNDS = Недостаточно средств для покупки ^4%l^1! Не хватает: ^3%s +ITEMS_MENU_SOMETHING_WENT_WRONG = ^3Что-то пошло не так при покупки... diff --git a/extra/rezombie/translates/ru/modes/armageddon.txt b/extra/rezombie/translates/ru/modes/armageddon.txt new file mode 100644 index 0000000..6f660b5 --- /dev/null +++ b/extra/rezombie/translates/ru/modes/armageddon.txt @@ -0,0 +1,4 @@ +[ru] +MODE_ARMAGEDDON_NAME = Армагеддон +MODE_ARMAGEDDON_DESC = Выживщие & Снайперы vs. Немезиды & Ассасины +MODE_ARMAGEDDON_NOTICE = Выживщие & Снайперы vs. Немезиды & Ассасины diff --git a/extra/rezombie/translates/ru/modes/assassin.txt b/extra/rezombie/translates/ru/modes/assassin.txt new file mode 100644 index 0000000..740994e --- /dev/null +++ b/extra/rezombie/translates/ru/modes/assassin.txt @@ -0,0 +1,4 @@ +[ru] +MODE_ASSASSIN_NAME = Ассасин +MODE_ASSASSIN_DESC = Ассасин vs. Люди +MODE_ASSASSIN_NOTICE = Ассасин (%n) против людей diff --git a/extra/rezombie/translates/ru/modes/infection.txt b/extra/rezombie/translates/ru/modes/infection.txt new file mode 100644 index 0000000..785d46f --- /dev/null +++ b/extra/rezombie/translates/ru/modes/infection.txt @@ -0,0 +1,4 @@ +[ru] +MODE_INFECTION_NAME = Массовое Заражение +MODE_INFECTION_DESC = Люди vs. Зомби +MODE_INFECTION_NOTICE = Люди против зомби diff --git a/extra/rezombie/translates/ru/modes/nemesis.txt b/extra/rezombie/translates/ru/modes/nemesis.txt new file mode 100644 index 0000000..2759622 --- /dev/null +++ b/extra/rezombie/translates/ru/modes/nemesis.txt @@ -0,0 +1,4 @@ +[ru] +MODE_NEMESIS_NAME = Немезида +MODE_NEMESIS_DESC = Немезида vs. Люди +MODE_NEMESIS_NOTICE = Немезида (%n) против людей diff --git a/extra/rezombie/translates/ru/modes/plague.txt b/extra/rezombie/translates/ru/modes/plague.txt new file mode 100644 index 0000000..1e02351 --- /dev/null +++ b/extra/rezombie/translates/ru/modes/plague.txt @@ -0,0 +1,4 @@ +[ru] +MODE_PLAGUE_NAME = Чума расползается +MODE_PLAGUE_DESC = Люди & Выживший vs. Зомби & Немезида +MODE_PLAGUE_NOTICE = Люди & Выживший vs. Зомби & Немезида diff --git a/extra/rezombie/translates/ru/modes/sniper.txt b/extra/rezombie/translates/ru/modes/sniper.txt new file mode 100644 index 0000000..c1f361c --- /dev/null +++ b/extra/rezombie/translates/ru/modes/sniper.txt @@ -0,0 +1,4 @@ +[ru] +MODE_SNIPER_NAME = Снайпер +MODE_SNIPER_DESC = Снайпер vs. Зомби +MODE_SNIPER_NOTICE = Снайпер (%n) против зомби diff --git a/extra/rezombie/translates/ru/modes/snipers_vs_assassins.txt b/extra/rezombie/translates/ru/modes/snipers_vs_assassins.txt new file mode 100644 index 0000000..f6e02ca --- /dev/null +++ b/extra/rezombie/translates/ru/modes/snipers_vs_assassins.txt @@ -0,0 +1,4 @@ +[ru] +MODE_SVA_NAME = Снайперы против Ассасинов +MODE_SVA_DESC = Снайперы vs. Ассасины +MODE_SVA_NOTICE = Снайперы против Ассасинов diff --git a/extra/rezombie/translates/ru/modes/survivor.txt b/extra/rezombie/translates/ru/modes/survivor.txt new file mode 100644 index 0000000..3fac109 --- /dev/null +++ b/extra/rezombie/translates/ru/modes/survivor.txt @@ -0,0 +1,4 @@ +[ru] +MODE_SURVIVOR_NAME = Выживший +MODE_SURVIVOR_DESC = Выживший vs. Зомби +MODE_SURVIVOR_NOTICE = Выживший (%n) против зомби diff --git a/extra/rezombie/translates/ru/modes/swarm.txt b/extra/rezombie/translates/ru/modes/swarm.txt new file mode 100644 index 0000000..ce57a77 --- /dev/null +++ b/extra/rezombie/translates/ru/modes/swarm.txt @@ -0,0 +1,4 @@ +[ru] +MODE_SWARM_NAME = Куча на кучу +MODE_SWARM_DESC = Люди vs. Зомби +MODE_SWARM_NOTICE = Люди против зомби diff --git a/extra/rezombie/translates/ru/subclasses/human_dead_inside.txt b/extra/rezombie/translates/ru/subclasses/human_dead_inside.txt new file mode 100644 index 0000000..b9d5d14 --- /dev/null +++ b/extra/rezombie/translates/ru/subclasses/human_dead_inside.txt @@ -0,0 +1,3 @@ +[ru] +RZ_SUBHUMAN_DEAD_NAME = Мертвый внутри +RZ_SUBHUMAN_DEAD_DESC = Броня+ diff --git a/extra/rezombie/translates/ru/subclasses/human_techno_dancer.txt b/extra/rezombie/translates/ru/subclasses/human_techno_dancer.txt new file mode 100644 index 0000000..627c7e0 --- /dev/null +++ b/extra/rezombie/translates/ru/subclasses/human_techno_dancer.txt @@ -0,0 +1,3 @@ +[ru] +RZ_SUBHUMAN_TECHNO_NAME = Техно-танцор +RZ_SUBHUMAN_TECHNO_DESC = Здоровье+ diff --git a/extra/rezombie/translates/ru/subclasses/zombie_jumper.txt b/extra/rezombie/translates/ru/subclasses/zombie_jumper.txt new file mode 100644 index 0000000..e27c6c3 --- /dev/null +++ b/extra/rezombie/translates/ru/subclasses/zombie_jumper.txt @@ -0,0 +1,3 @@ +[ru] +RZ_SUBZOMBIE_JUMPER_NAME = Попрыгунчик +RZ_SUBZOMBIE_JUMPER_DESC = Гравитация+ diff --git a/extra/rezombie/translates/ru/subclasses/zombie_sprinter.txt b/extra/rezombie/translates/ru/subclasses/zombie_sprinter.txt new file mode 100644 index 0000000..8ff3642 --- /dev/null +++ b/extra/rezombie/translates/ru/subclasses/zombie_sprinter.txt @@ -0,0 +1,3 @@ +[ru] +RZ_SUBZOMBIE_SPRINTER_NAME = Спринтер +RZ_SUBZOMBIE_SPRINTER_DESC = Скорость+ diff --git a/extra/rezombie/translates/ru/subclasses/zombie_stone.txt b/extra/rezombie/translates/ru/subclasses/zombie_stone.txt new file mode 100644 index 0000000..3bb1991 --- /dev/null +++ b/extra/rezombie/translates/ru/subclasses/zombie_stone.txt @@ -0,0 +1,3 @@ +[ru] +RZ_SUBZOMBIE_STONE_NAME = Камень +RZ_SUBZOMBIE_STONE_DESC = Здоровье+ diff --git a/extra/rezombie/translates/ru/weapons/default.txt b/extra/rezombie/translates/ru/weapons/default.txt new file mode 100644 index 0000000..8275c20 --- /dev/null +++ b/extra/rezombie/translates/ru/weapons/default.txt @@ -0,0 +1,16 @@ +[ru] +DEFAULT_HE_GRENADE = Осколочная граната +DEFAULT_HE_SHORT = Осколочная +DEFAULT_FLASHBANG = Световая граната +DEFAULT_FB_SHORT = Световая +DEFAULT_SMOKE_GRENADE = Дымовая граната +DEFAULT_SMOKE_SHORT = Дымовая + +DEFAULT_FIRE_GRENADE = Поджигающая граната +DEFAULT_FIRE_SHORT = Поджигающая +DEFAULT_FROST_GRENADE = Замораживющая граната +DEFAULT_FROST_SHORT = Замораживющая +DEFAULT_FLARE_GRENADE = Освещающая граната +DEFAULT_FLARE_SHORT = Освещающая + +DEFAULT_KNIFE = Нож diff --git a/libs/cssdk/include/cssdk/dll/entity_base.h b/libs/cssdk/include/cssdk/dll/entity_base.h index f2bde9b..b9e6b94 100644 --- a/libs/cssdk/include/cssdk/dll/entity_base.h +++ b/libs/cssdk/include/cssdk/dll/entity_base.h @@ -47,6 +47,11 @@ #include #include +namespace rz +{ + class Extras; +} + namespace cssdk { /** @@ -455,7 +460,7 @@ namespace cssdk /** * @brief N/D */ - EntityBase* link{}; + rz::Extras* link{}; /** * @brief N/D diff --git a/libs/cssdk/include/cssdk/dll/game_rules.h b/libs/cssdk/include/cssdk/dll/game_rules.h index 2e33d60..859607b 100644 --- a/libs/cssdk/include/cssdk/dll/game_rules.h +++ b/libs/cssdk/include/cssdk/dll/game_rules.h @@ -684,13 +684,13 @@ namespace cssdk Neutral }; - class GameRules // NOLINT(cppcoreguidelines-special-member-functions) + class GameRulesBase // NOLINT(cppcoreguidelines-special-member-functions) { public: /** * @brief N/D */ - virtual ~GameRules() = default; + virtual ~GameRulesBase() = default; /** * @brief Fill skill data struct with proper values. @@ -1118,7 +1118,7 @@ namespace cssdk bool is_game_over{}; }; - class HalfLifeRules : public GameRules // NOLINT(cppcoreguidelines-special-member-functions) + class HalfLifeRules : public GameRulesBase // NOLINT(cppcoreguidelines-special-member-functions) { public: /** @@ -1402,7 +1402,7 @@ namespace cssdk #endif // ReSharper disable once CppImplicitDefaultConstructorNotAvailable - class HalfLifeMultiplay : public GameRules // NOLINT(cppcoreguidelines-special-member-functions) + class HalfLifeMultiplay : public GameRulesBase // NOLINT(cppcoreguidelines-special-member-functions) { public: /** @@ -2285,13 +2285,13 @@ namespace cssdk bool team_balanced_; }; - inline HalfLifeMultiplay* GameRules::CsGameRules() + inline HalfLifeMultiplay* GameRulesBase::CsGameRules() { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) return static_cast(this); } - inline const HalfLifeMultiplay* GameRules::CsGameRules() const + inline const HalfLifeMultiplay* GameRulesBase::CsGameRules() const { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) return static_cast(this); diff --git a/libs/cssdk/include/cssdk/public/regamedll/regamedll_api.h b/libs/cssdk/include/cssdk/public/regamedll/regamedll_api.h index ec446e7..b8f75b8 100644 --- a/libs/cssdk/include/cssdk/public/regamedll/regamedll_api.h +++ b/libs/cssdk/include/cssdk/public/regamedll/regamedll_api.h @@ -233,8 +233,8 @@ namespace cssdk using ReHookRegistryRoundEnd = IHookChainRegistry; // InstallGameRules hook - using ReHookInstallGameRules = IHookChain; - using ReHookRegistryInstallGameRules = IHookChainRegistry; + using ReHookInstallGameRules = IHookChain; + using ReHookRegistryInstallGameRules = IHookChainRegistry; // PM_Init hook using ReHookPmInit = IHookChain; @@ -547,8 +547,8 @@ namespace cssdk using ReHookRegistryPlayerJoiningThink = IHookChainClassRegistry; // FreeGameRules hook - using ReHookFreeGameRules = IHookChain; - using ReHookRegistryFreeGameRules = IHookChainRegistry; + using ReHookFreeGameRules = IHookChain; + using ReHookRegistryFreeGameRules = IHookChainRegistry; // PM_LadderMove hook using ReHookPmLadderMove = IHookChain; @@ -862,7 +862,7 @@ namespace cssdk virtual int GetMinorVersion() = 0; virtual const RegamedllFuncs* GetFuncs() = 0; virtual IReGameDllHookChains* GetHookChains() = 0; - virtual GameRules* GetGameRules() = 0; + virtual GameRulesBase* GetGameRules() = 0; virtual WeaponInfoStruct* GetWeaponInfo(WeaponId weapon) = 0; virtual WeaponInfoStruct* GetWeaponInfo(const char* weapon) = 0; virtual PlayerMove* GetPlayerMove() = 0; diff --git a/rezombie/CMakeLists.txt b/rezombie/CMakeLists.txt index adfef44..d7bfb48 100644 --- a/rezombie/CMakeLists.txt +++ b/rezombie/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(${PROJECT_NAME} SHARED "include/rezombie/main/main.h" "include/rezombie/main/convars.h" "include/rezombie/main/util.h" + "include/rezombie/main/api/main.h" "include/rezombie/core/object.h" "include/rezombie/core/module.h" @@ -37,6 +38,7 @@ add_library(${PROJECT_NAME} SHARED "include/rezombie/entity/items/item.h" "include/rezombie/entity/colors/color.h" "include/rezombie/entity/wrappers/player_item_wrapper.h" + "include/rezombie/entity/extras.h" "include/rezombie/messages/engine_message.h" "include/rezombie/messages/user_message.h" @@ -50,11 +52,13 @@ add_library(${PROJECT_NAME} SHARED "include/rezombie/map/map_spawns.h" "include/rezombie/map/environment.h" + "include/rezombie/map/extras.h" "include/rezombie/map/modules/map_cameras.h" "include/rezombie/map/modules/fog.h" "include/rezombie/map/api/map_cameras.h" "include/rezombie/map/api/environment.h" "include/rezombie/map/api/fog.h" + "include/rezombie/map/api/extras.h" "include/rezombie/gamerules/game_rules.h" "include/rezombie/gamerules/consts.h" @@ -103,6 +107,9 @@ add_library(${PROJECT_NAME} SHARED "include/rezombie/models/api/model.h" "include/rezombie/models/api/models_pack.h" + "include/rezombie/sounds/sounds.h" + "include/rezombie/sounds/api/sounds.h" + "include/rezombie/items/modules/item.h" "include/rezombie/items/api/items.h" @@ -122,6 +129,7 @@ add_library(${PROJECT_NAME} SHARED "src/main/message_hooks.cpp" "src/main/convars.cpp" "src/main/util.cpp" + "src/main/api/main.cpp" "src/messages/engine_message.cpp" "src/messages/user_message.cpp" @@ -137,6 +145,7 @@ add_library(${PROJECT_NAME} SHARED "src/map/api/map_cameras.cpp" "src/map/api/environment.cpp" "src/map/api/fog.cpp" + "src/map/api/extras.cpp" "src/gamerules/game_rules.cpp" "src/gamerules/player.cpp" @@ -179,6 +188,9 @@ add_library(${PROJECT_NAME} SHARED "src/models/api/models.cpp" "src/models/api/models_pack.cpp" + "src/sounds/sounds.cpp" + "src/sounds/api/sounds.cpp" + "src/items/api/items.cpp" "src/preview/join_preview.cpp" @@ -229,7 +241,7 @@ set(AMXX_USE_METAMOD ON) set(AMXX_182_COMPATIBILITY OFF) # Uncomment the functions you want to use in your code and specify the desired function names -set(AMXX_QUERY "Main") # void OnAmxxQuery() +set(AMXX_QUERY "Main") # void OnAmxxQuery() set(AMXX_ATTACH "__OnAmxxAttach") # AmxxStatus OnAmxxAttach() #set(AMXX_DETACH "__OnAmxxDetach") # void OnAmxxDetach() #set(AMXX_CHECK_GAME "__OnAmxxCheckGame") # AmxxGameStatus OnAmxxCheckGame(const char* game) diff --git a/rezombie/include/rezombie/configs/main_config.h b/rezombie/include/rezombie/configs/main_config.h new file mode 100644 index 0000000..f42776a --- /dev/null +++ b/rezombie/include/rezombie/configs/main_config.h @@ -0,0 +1,49 @@ +#pragma once +#include +#include + +namespace rz +{ + class MainConfig { + protected: + std::string serverBrowserInfo_ = "ReZombie"; + std::string skyName_ = "space"; + int warmupTime_ = 40; + int prepareTime_ = 20; + int roundTime_ = 180; + std::vector uselessEntities_ = { + "func_bomb_target", + "info_bomb_target", + "info_vip_start", + "func_vip_safetyzone", + "func_escapezone", + "func_hostage_rescue", + "info_hostage_rescue", + "hostage_entity", + "armoury_entity", + "player_weaponstrip", + "game_player_equip", + "env_fog", + "env_rain", + "env_snow", + "monster_scientist" + }; + + public: + auto load() -> void; + + auto getServerBrowswerInfo() const -> const std::string& { return serverBrowserInfo_; } + auto setServerBrowswerInfo(const std::string& browserInfo) -> void { serverBrowserInfo_ = browserInfo; } + auto getSkyName() const -> const std::string& { return skyName_; } + auto setSkyName(const std::string& skyName) -> void { skyName_ = skyName; } + auto getWarmupTime() const -> int { return warmupTime_; } + auto setWarmupTime(int warmupTime) -> void { warmupTime_ = warmupTime; } + auto getPrepareTime() const -> int { return prepareTime_; } + auto setPrepareTime(int prepareTime) -> void { prepareTime_ = prepareTime; } + auto getRoundTime() const -> int { return roundTime_; } + auto setRoundTime(int roundTime) -> void { roundTime_ = roundTime; } + auto getUselessEntities() const -> const std::vector& { return uselessEntities_; } + }; + + inline MainConfig MainConfig; +} diff --git a/rezombie/include/rezombie/core/api/amxx_feature.h b/rezombie/include/rezombie/core/api/amxx_feature.h index 1988ae1..7032c8c 100644 --- a/rezombie/include/rezombie/core/api/amxx_feature.h +++ b/rezombie/include/rezombie/core/api/amxx_feature.h @@ -21,7 +21,7 @@ namespace rz Dummy, }; - template + template class AmxxFeature : public AmxxBaseFeature { std::array(MAX_FORWARDS)> forwards_; diff --git a/rezombie/include/rezombie/core/api/amxx_features_store.h b/rezombie/include/rezombie/core/api/amxx_features_store.h index 82764dc..b555d29 100644 --- a/rezombie/include/rezombie/core/api/amxx_features_store.h +++ b/rezombie/include/rezombie/core/api/amxx_features_store.h @@ -1,26 +1,33 @@ #pragma once +#include "rezombie/main/api/main.h" #include "rezombie/colors/api/colors.h" #include "rezombie/gamerules/api/game_rules.h" -#include "rezombie/gamerules/api/modes.h" +#include "rezombie/modes/api/modes.h" #include "rezombie/player/api/player.h" #include "rezombie/player/api/player_class.h" #include "rezombie/player/api/player_subclass.h" #include "rezombie/player/api/player_props.h" #include "rezombie/player/api/flashlight.h" #include "rezombie/player/api/nightvision.h" +#include "rezombie/player/api/jumps.h" +#include "rezombie/player/api/long_jump.h" #include "rezombie/currency/api/currency.h" #include "rezombie/currency/api/price.h" #include "rezombie/models/api/model.h" #include "rezombie/models/api/models_pack.h" +#include "rezombie/sounds/api/sounds.h" #include "rezombie/weapons/api/weapon.h" #include "rezombie/weapons/api/melee.h" #include "rezombie/items/api/items.h" #include "rezombie/map/api/map_cameras.h" #include "rezombie/map/api/environment.h" #include "rezombie/map/api/fog.h" -#include "rezombie/modelpreview/api/model_preview.h" +#include "rezombie/map/api/extras.h" +#include "rezombie/preview/api/join_preview.h" +#include "rezombie/preview/api/world_preview.h" #include "rezombie/thirdcamera/api/third_camera.h" +#include "rezombie/messages/api/engine_message.h" #include "rezombie/messages/api/user_message.h" #include "rezombie/core/api/amxx_base_feature.h" #include @@ -30,6 +37,7 @@ namespace rz { class AmxxFeaturesStore { std::vector features_ = { + &MainApi, &ColorsApi, &CurrencyApi, &PriceApi, @@ -39,18 +47,24 @@ namespace rz &PlayerClassApi, &PlayerSubclassApi, &PlayerPropsApi, + &JumpsApi, + &LongJumpApi, &ModelsApi, &ModelsPackApi, + &SoundsApi, &WeaponApi, - &amxxMelee, + &MeleeApi, &FlashlightApi, &NightVisionApi, &ItemApi, &EnvironmentApi, &FogApi, + &MapExtrasApi, &ModelPreviewApi, + &WorldPreviewApi, &ThirdCameraApi, &MapCamerasApi, + &EngineMessageApi, &UserMessageApi }; diff --git a/rezombie/include/rezombie/core/api/amxx_helper.h b/rezombie/include/rezombie/core/api/amxx_helper.h index a2b838e..81762fd 100644 --- a/rezombie/include/rezombie/core/api/amxx_helper.h +++ b/rezombie/include/rezombie/core/api/amxx_helper.h @@ -2,6 +2,14 @@ namespace rz { +#define PARAMS_COUNT (params[0] / sizeof(cell)) + +#define CHECK_PLAYER(id) \ + if (!IsClient(id)) { \ + LogError(amx, AmxError::Native, "invalid player index %d", id); \ + return false; \ + } + #define CHECK_VAR_EXISTS(format, ...) \ if (!var) { \ LogError(amx, AmxError::Native, format, __VA_ARGS__); \ diff --git a/rezombie/include/rezombie/currency/modules/currency.h b/rezombie/include/rezombie/currency/modules/currency.h index a062b3e..554b71a 100644 --- a/rezombie/include/rezombie/currency/modules/currency.h +++ b/rezombie/include/rezombie/currency/modules/currency.h @@ -7,7 +7,7 @@ namespace rz { class CurrencyModule : public Module { public: - CurrencyModule() : Module("currency") {} + CurrencyModule() : Module("currency") {} auto add( std::string handle, diff --git a/rezombie/include/rezombie/currency/modules/price.h b/rezombie/include/rezombie/currency/modules/price.h index 56de215..a88c530 100644 --- a/rezombie/include/rezombie/currency/modules/price.h +++ b/rezombie/include/rezombie/currency/modules/price.h @@ -7,7 +7,7 @@ namespace rz { class PriceModule : public Module { public: - PriceModule() : Module("prices") {} + PriceModule() : Module("prices") {} auto add(int currency, int amount) -> int { return Module::add(new Price(currency, amount)); diff --git a/rezombie/include/rezombie/entity/colors/color.h b/rezombie/include/rezombie/entity/colors/color.h index 0e7be83..e45c4f8 100644 --- a/rezombie/include/rezombie/entity/colors/color.h +++ b/rezombie/include/rezombie/entity/colors/color.h @@ -1,30 +1,33 @@ #pragma once +#include + namespace rz { class Color { - unsigned char red_; - unsigned char green_; - unsigned char blue_; - unsigned char alpha_; + uint8_t red_; + uint8_t green_; + uint8_t blue_; + uint8_t alpha_; - public: - Color( - unsigned char red = 0, - unsigned char green = 0, - unsigned char blue = 0, - unsigned char alpha = 0 - ) : red_(red), - green_(green), - blue_(blue), - alpha_(alpha) {} + public: + Color( + const uint8_t red = 0, + const uint8_t green = 0, + const uint8_t blue = 0, + const float alpha = 1.f + ) : red_(red), + green_(green), + blue_(blue) { + alpha_ = std::clamp(static_cast(alpha * UINT8_MAX), static_cast(0), UINT8_MAX); + } - auto getRed() const -> unsigned char { return red_; } + auto getRed() const -> uint8_t { return red_; } - auto getGreen() const -> unsigned char { return green_; } + auto getGreen() const -> uint8_t { return green_; } - auto getBlue() const -> unsigned char { return blue_; } + auto getBlue() const -> uint8_t { return blue_; } - auto getAlpha() const -> unsigned char { return alpha_; } + auto getAlpha() const -> uint8_t { return alpha_; } }; } diff --git a/rezombie/include/rezombie/entity/extras.h b/rezombie/include/rezombie/entity/extras.h new file mode 100644 index 0000000..b364fb7 --- /dev/null +++ b/rezombie/include/rezombie/entity/extras.h @@ -0,0 +1,65 @@ +#pragma once + +#include "rezombie/main/util.h" +#include +#include + +namespace rz +{ + enum class ExtraType { + Int, + Float, + String, + }; + + class Extras { + std::unordered_map ints_ = {}; + std::unordered_map floats_ = {}; + std::unordered_map strings_ = {}; + + public: + Extras() = default; + + auto reset() -> void { + ints_.clear(); + floats_.clear(); + strings_.clear(); + } + + auto isKeyExists(const ExtraType type, const std::string& key) const -> bool { + switch (type) { + case ExtraType::Int: { + if (getMapValue(ints_, key)) { + return true; + } + break; + } + case ExtraType::Float: { + if (getMapValue(floats_, key)) { + return true; + } + break; + } + case ExtraType::String: { + if (getMapValue(strings_, key)) { + return true; + } + break; + } + } + return false; + } + + auto getInts() -> std::unordered_map& { + return ints_; + } + + auto getFloats() -> std::unordered_map& { + return floats_; + } + + auto getStrings() -> std::unordered_map& { + return strings_; + } + }; +} diff --git a/rezombie/include/rezombie/entity/gamerules/mode.h b/rezombie/include/rezombie/entity/gamerules/mode.h index c330199..f1a9ca6 100644 --- a/rezombie/include/rezombie/entity/gamerules/mode.h +++ b/rezombie/include/rezombie/entity/gamerules/mode.h @@ -5,47 +5,83 @@ namespace rz { + enum class RespawnType { + Off, + ToHumansTeam, + ToZombiesTeam, + Balance, + }; + class Mode : public Object { - std::string hudColor_{"white"}; + std::string description_; + std::string noticeMessage_; + std::string color_{"white"}; int dropChance_ = 20; int minimumPlayers_ = 0; int roundTime_ = 0; + bool isSupportTarget_{}; + RespawnType respawnType_ = RespawnType::Off; + std::vector ambienceSounds_{}; int launchForward_{}; public: Mode( std::string handle, - int launchForward + int launchForward, + bool isSupportTarget ) : Object(std::move(handle)), - launchForward_(launchForward) {} + launchForward_(launchForward), + isSupportTarget_(isSupportTarget) {} + + auto getDescription() const -> const std::string& { return description_; } + + auto setDescription(std::string description) -> void { description_ = std::move(description); } + + auto getNoticeMessage() const -> const std::string& { return noticeMessage_; } + + auto setNoticeMessage(std::string noticeMessage) -> void { noticeMessage_ = std::move(noticeMessage); } + + auto getColor() const -> const std::string& { return color_; } - auto getHudColor() const -> const std::string& { return hudColor_; } + auto setColor(std::string color) -> void { color_ = std::move(color); } - auto setHudColor(std::string hudColor) -> void { hudColor_ = std::move(hudColor); } + auto getDropChance() const -> int { return dropChance_; } - auto getDropChance() const { return dropChance_; } + auto setDropChance(int dropChance) -> void { dropChance_ = dropChance; } - auto setDropChance(int dropChance) { dropChance_ = dropChance; } + auto getMinPlayers() const -> int { return minimumPlayers_; } - auto getMinPlayers() const { return minimumPlayers_; } + auto setMinPlayers(int minimumPlayers) -> void { minimumPlayers_ = minimumPlayers; } - auto setMinPlayers(int minimumPlayers) { minimumPlayers_ = minimumPlayers; } + auto getRoundTime() const -> int { return roundTime_; } - auto getRoundTime() const { return roundTime_; } + auto setRoundTime(int roundTime) -> void { roundTime_ = roundTime; } - auto setRoundTime(int roundTime) { roundTime_ = roundTime; } + auto isSupportTarget() const -> bool { return isSupportTarget_; } + + auto setSupportTarget(bool isSupportTarget) -> void { isSupportTarget_ = isSupportTarget; } + + auto getRespawn() const -> RespawnType { return respawnType_; } + + auto setRespawn(const RespawnType respawnType) -> void { respawnType_ = respawnType; } + + auto addAmbienceSound(const std::string& path) -> void { + ambienceSounds_.emplace_back(path); + } + + auto getRandomAmbienceSound() const -> const std::string& { + // if (sounds_[toInt(soundType)].empty()) { + // return nullptr; + // } + return ambienceSounds_[RandomLong(0, ambienceSounds_.size() - 1)]; + } - auto getLaunchForward() const { return launchForward_; } + auto getLaunchForward() const -> int { return launchForward_; } - auto setLaunchForward(int launchForward) { launchForward_ = launchForward; } + auto setLaunchForward(int launchForward) -> void { launchForward_ = launchForward; } - auto executeLaunch(int modeId) const -> bool { - // no need because consturctor - if (getLaunchForward() == FORWARD_INVALID) { - return false; - } - ExecuteForward(getLaunchForward(), modeId); - return true; + auto executeLaunch(int target = 0) const -> int { + return ExecuteForward(getLaunchForward(), target); } }; } diff --git a/rezombie/include/rezombie/entity/player/flashlight.h b/rezombie/include/rezombie/entity/player/flashlight.h index f0de070..795421d 100644 --- a/rezombie/include/rezombie/entity/player/flashlight.h +++ b/rezombie/include/rezombie/entity/player/flashlight.h @@ -1,16 +1,14 @@ #pragma once -#include - #include "rezombie/core/object.h" -#include "rezombie/player/modules/nightvision.h" +#include namespace rz { class Flashlight { std::string color_{}; int size_{}; - int distance_ = 2048.f; // to float + int distance_ = 2048; float drainTime_{}; float chargeTime_{}; diff --git a/rezombie/include/rezombie/entity/player/nightvision.h b/rezombie/include/rezombie/entity/player/nightvision.h index 6ae7c09..7ed3caa 100644 --- a/rezombie/include/rezombie/entity/player/nightvision.h +++ b/rezombie/include/rezombie/entity/player/nightvision.h @@ -1,34 +1,24 @@ #pragma once -#include - -#include "rezombie/core/object.h" #include "rezombie/player/modules/nightvision.h" namespace rz { class NightVision { std::string color_{}; - int alphaPercentage_{}; int fogId_{}; public: NightVision( std::string color, - int alphaPercentage, int fogId ) : color_(std::move(color)), - alphaPercentage_(alphaPercentage), fogId_(fogId) {} auto getColor() const -> const std::string& { return color_; } auto setColor(const std::string& color) -> void { color_ = color; } - auto getAlphaPercentage() const -> int { return alphaPercentage_; } - - auto setAlphaPercentage(int alphaPercentage) -> void { alphaPercentage_ = alphaPercentage; } - auto getFog() const -> int { return fogId_; } auto setFog(int fogId) -> void { fogId_ = fogId; } diff --git a/rezombie/include/rezombie/entity/player/player_class.h b/rezombie/include/rezombie/entity/player/player_class.h index 87a3f83..42f135c 100644 --- a/rezombie/include/rezombie/entity/player/player_class.h +++ b/rezombie/include/rezombie/entity/player/player_class.h @@ -4,10 +4,8 @@ #include "rezombie/gamerules/game_rules.h" #include "rezombie/weapons/modules/weapon.h" #include "rezombie/models/modules/models_pack.h" -#include "rezombie/player/modules/nightvision.h" #include "rezombie/player/modules/player_props.h" #include "rezombie/player/modules/player_sounds.h" -#include namespace rz { @@ -18,54 +16,57 @@ namespace rz int modelsPackId_{}; int soundsId_{}; int meleeId_{}; + Extras extras_{}; int giveDefaultItemsForward_ = FORWARD_INVALID; - public: - PlayerClass( - std::string handle, - Team team - ) : Object(std::move(handle)), - team_(team) { - setProps(Props.add(getHandle())); - setModelsPack(ModelsPack.add(getHandle())); - setSounds(PlayerSounds.add(getHandle())); - setMelee(Weapons.add(getHandle(), WeaponType::Melee)); - } + public: + PlayerClass( + std::string handle, + Team team + ) : Object(std::move(handle)), + team_(team) { + setProps(Props.add(getHandle())); + setModelsPack(ModelsPack.add(getHandle())); + setSounds(PlayerSounds.add(getHandle())); + setMelee(Weapons.add(getHandle(), WeaponType::Melee)); + } + + auto getHudColor() const -> const std::string& { return hudColor_; } - auto getHudColor() const -> const std::string& { return hudColor_; } + auto setHudColor(std::string hudColor) -> void { hudColor_ = std::move(hudColor); } - auto setHudColor(std::string hudColor) -> void { hudColor_ = std::move(hudColor); } + auto getTeam() const -> Team { return team_; } - auto getTeam() const -> Team { return team_; } + auto getProps() const -> int { return propsId_; } - auto getProps() const -> int { return propsId_; } + auto setProps(int propsId) -> void { propsId_ = propsId; } - auto setProps(int propsId) -> void { propsId_ = propsId; } + auto getModelsPack() const -> int { return modelsPackId_; } - auto getModelsPack() const -> int { return modelsPackId_; } + auto setModelsPack(int modelsPackId) -> void { modelsPackId_ = modelsPackId; } - auto setModelsPack(int modelsPackId) -> void { modelsPackId_ = modelsPackId; } + auto getSounds() const -> int { return soundsId_; } - auto getSounds() const -> int { return soundsId_; } + auto setSounds(int soundsId) -> void { soundsId_ = soundsId; } - auto setSounds(int soundsId) -> void { soundsId_ = soundsId; } + auto getMelee() const -> int { return meleeId_; } - auto getMelee() const -> int { return meleeId_; } + auto setMelee(int meleeId) -> void { meleeId_ = meleeId; } - auto setMelee(int meleeId) -> void { meleeId_ = meleeId; } + auto getExtras() -> Extras& { return extras_; } - auto getGiveDefaultItemsForward() const -> int { return giveDefaultItemsForward_; } + auto getGiveDefaultItemsForward() const -> int { return giveDefaultItemsForward_; } - auto setGiveDefaultItemsForward(int giveDefaultItemsForward) -> void { - giveDefaultItemsForward_ = giveDefaultItemsForward; - } + auto setGiveDefaultItemsForward(int giveDefaultItemsForward) -> void { + giveDefaultItemsForward_ = giveDefaultItemsForward; + } - auto executeGiveDefaultItems(int playerId) const -> bool { - if (getGiveDefaultItemsForward() == -1) { - return false; + auto executeGiveDefaultItems(int playerId) const -> bool { + if (getGiveDefaultItemsForward() == -1) { + return false; + } + ExecuteForward(getGiveDefaultItemsForward(), playerId); + return true; } - ExecuteForward(getGiveDefaultItemsForward(), playerId); - return true; - } }; } diff --git a/rezombie/include/rezombie/entity/player/player_props.h b/rezombie/include/rezombie/entity/player/player_props.h index 019832b..42f4ede 100644 --- a/rezombie/include/rezombie/entity/player/player_props.h +++ b/rezombie/include/rezombie/entity/player/player_props.h @@ -3,8 +3,6 @@ #include "rezombie/core/object.h" #include "cssdk/public/regamedll/regamedll_consts.h" -#include - namespace rz { using namespace cssdk; diff --git a/rezombie/include/rezombie/entity/player/player_sounds.h b/rezombie/include/rezombie/entity/player/player_sounds.h index 78ced33..0128fa0 100644 --- a/rezombie/include/rezombie/entity/player/player_sounds.h +++ b/rezombie/include/rezombie/entity/player/player_sounds.h @@ -2,7 +2,6 @@ #include "rezombie/core/object.h" #include -#include namespace rz { @@ -21,7 +20,15 @@ namespace rz std::array, toInt(PlayerSoundType::MAX_SOUND_TYPES)> sounds_; std::array isDefault_{}; - auto addDefault(PlayerSoundType soundType, const std::string& path) -> void { + auto sounds(const PlayerSoundType soundType) -> std::vector& { + return sounds_[toInt(soundType)]; + } + + auto isDefault(const PlayerSoundType soundType) -> bool& { + return isDefault_[toInt(soundType)]; + } + + auto addDefault(const PlayerSoundType soundType, const std::string& path) -> void { sounds_[toInt(soundType)].emplace_back(path); } @@ -42,20 +49,19 @@ namespace rz addDefault(PlayerSoundType::Death, "player/death6.wav"); } - auto add(PlayerSoundType soundType, const std::string& path) -> void { - auto soundTypeInt = toInt(soundType); - if (isDefault_[soundTypeInt]) { - sounds_[soundTypeInt].clear(); - isDefault_[soundTypeInt] = false; + auto add(const PlayerSoundType soundType, const std::string& path) -> void { + if (isDefault(soundType)) { + isDefault(soundType) = false; + sounds(soundType).clear(); } - sounds_[soundTypeInt].emplace_back(path); + sounds(soundType).emplace_back(path); } - auto getRandom(PlayerSoundType soundType) const -> const std::string& { + auto getRandom(const PlayerSoundType soundType) -> const std::string& { // if (sounds_[toInt(soundType)].empty()) { // return nullptr; // } - return sounds_[toInt(soundType)][RandomLong(0, sounds_[toInt(soundType)].size() - 1)]; + return sounds(soundType)[RandomLong(0, sounds(soundType).size() - 1)]; } }; } diff --git a/rezombie/include/rezombie/entity/player/player_subclass.h b/rezombie/include/rezombie/entity/player/player_subclass.h index e002848..8192c0c 100644 --- a/rezombie/include/rezombie/entity/player/player_subclass.h +++ b/rezombie/include/rezombie/entity/player/player_subclass.h @@ -1,15 +1,12 @@ #pragma once #include "rezombie/core/object.h" -#include "rezombie/gamerules/game_rules.h" #include "rezombie/models/modules/models.h" #include "rezombie/player/modules/nightvision.h" -#include "rezombie/player/modules/player_props.h" #include "rezombie/player/modules/player_sounds.h" #include "rezombie/player/modules/player_class.h" #include "rezombie/weapons/modules/weapon.h" #include "player_class.h" -#include "cssdk/dll/player.h" namespace rz { diff --git a/rezombie/include/rezombie/entity/weapons/base_weapon.h b/rezombie/include/rezombie/entity/weapons/base_weapon.h index fe43b56..3e5a046 100644 --- a/rezombie/include/rezombie/entity/weapons/base_weapon.h +++ b/rezombie/include/rezombie/entity/weapons/base_weapon.h @@ -1,11 +1,10 @@ #pragma once #include "rezombie/core/object.h" -#include "rezombie/weapons/weapons.h" +#include "rezombie/entity/extras.h" #include #include #include -#include namespace rz { @@ -14,10 +13,29 @@ namespace rz using namespace amx; using namespace amxx; + enum class WeaponType : int { + Primary,// automatic + Secondary,// once + Melee,// delete + Grenade,// auto throw + Extra, + }; + + enum class CrosshairSize : int { + None, + Size3, + Size4, + Size5, + Size6, + Size7, + Size8, + Size9, + }; + class BaseWeapon : public Object { std::string reference_; WeaponType weaponType_; - InventorySlot inventorySlot_; + InventorySlot slot_; int viewModelId_{}; int playerModelId_{}; int worldModelId_{}; @@ -27,6 +45,9 @@ namespace rz int maxAmmo_ = 0; int weight_ = 0; int flags_ = 0; + int alwaysDamage_ = -1; + bool gibs_ = false; + Extras extras_{}; int deployForward_ = -1; int holsterForward_ = -1; int maxSpeedForward_ = -1; @@ -60,144 +81,156 @@ namespace rz } } - public: - BaseWeapon(std::string handle, std::string reference, WeaponType weaponType) : - Object(std::move(handle)), - reference_(std::move(reference)), - weaponType_(weaponType), - inventorySlot_(getDefaultInventorySlot(weaponType_)) { - setHudPath(getHud()); - } + public: + BaseWeapon(std::string handle, std::string reference, WeaponType weaponType) : Object(std::move(handle)), + reference_(std::move(reference)), + weaponType_(weaponType), + slot_(getDefaultInventorySlot(weaponType_)) { + setHudPath(getHud()); + } - virtual ~BaseWeapon() = default; + virtual ~BaseWeapon() = default; - auto getReference() const -> const std::string& { return reference_; } + auto getReference() const -> const std::string& { return reference_; } - auto getViewModel() const -> int { return viewModelId_; } + auto getWeaponType() const -> WeaponType { return weaponType_; } - auto setViewModel(int viewModelId) { viewModelId_ = viewModelId; } + auto setWeaponType(WeaponType weaponType) -> void { weaponType_ = weaponType; } - auto getPlayerModel() const -> int { return playerModelId_; } + auto getViewModel() const -> int { return viewModelId_; } - auto setPlayerModel(int playerModelId) { playerModelId_ = playerModelId; } + auto setViewModel(int viewModelId) -> void { viewModelId_ = viewModelId; } - auto getWorldModel() const -> int { return worldModelId_; } + auto getPlayerModel() const -> int { return playerModelId_; } - auto setWorldModel(int worldModelId) { worldModelId_ = worldModelId; } + auto setPlayerModel(int playerModelId) -> void { playerModelId_ = playerModelId; } - auto getHud() const -> const std::string& { return hud_; } + auto getWorldModel() const -> int { return worldModelId_; } - auto setHud(std::string hud) { - hud_ = std::move(hud); - setHudPath(getHud()); - } + auto setWorldModel(int worldModelId) -> void { worldModelId_ = worldModelId; } + + auto getHud() const -> const std::string& { return hud_; } + + auto setHud(std::string hud) { + hud_ = std::move(hud); + setHudPath(getHud()); + } + + auto getHudPath() const -> const std::string& { return hudPath_; } - auto getHudPath() const -> const std::string& { return hudPath_; } + auto getMaxClip() const { return maxClip_; } - auto getMaxClip() const { return maxClip_; } + auto setMaxClip(int maxClip) -> void { maxClip_ = maxClip; } - auto setMaxClip(int maxClip) { maxClip_ = maxClip; } + auto getMaxAmmo() const { return maxAmmo_; } - auto getMaxAmmo() const { return maxAmmo_; } + auto setMaxAmmo(int maxAmmo) -> void { maxAmmo_ = maxAmmo; } - auto setMaxAmmo(int maxAmmo) { maxAmmo_ = maxAmmo; } + auto getSlot() const { return slot_; } - auto getInventorySlot() const { return inventorySlot_; } + auto setSlot(InventorySlot slot) -> void { slot_ = slot; } - auto setInventorySlot(InventorySlot inventorySlot) { inventorySlot_ = inventorySlot; } + auto getWeight() const { return weight_; } - auto getWeight() const { return weight_; } + auto setWeight(int weight) -> void { weight_ = weight; } - auto setWeight(int weight) { weight_ = weight; } + auto getFlags() const { return flags_; } - auto getFlags() const { return flags_; } + auto setFlags(int flags) -> void { flags_ = flags; } - auto setFlags(int flags) { flags_ = flags; } + auto getAlwaysDamage() const { return alwaysDamage_; } - auto getWeaponType() const { return weaponType_; } + auto setAlwaysDamage(int damage) -> void { alwaysDamage_ = damage; } - auto setWeaponType(WeaponType weaponType) { weaponType_ = weaponType; } + auto getGibs() const { return gibs_; } - auto getDeployForward() const { return deployForward_; } + auto setGibs(bool gibs) -> void { gibs_ = gibs; } - auto setDeployForward(int deployForward) { deployForward_ = deployForward; } + auto getExtras() -> Extras& { return extras_; } - auto executeDeploy(int weapon, int player) const -> bool { - if (getDeployForward() == -1) { - return false; + auto getDeployForward() const { return deployForward_; } + + auto setDeployForward(int deployForward) -> void { deployForward_ = deployForward; } + + auto executeDeploy(int weapon, int player) const -> bool { + if (getDeployForward() == -1) { + return false; + } + return ExecuteForward(getDeployForward(), weapon, player); } - return ExecuteForward(getDeployForward(), weapon, player); - } - auto getHolsterForward() const { return holsterForward_; } + auto getHolsterForward() const { return holsterForward_; } - auto setHolsterForward(int holsterForward) { holsterForward_ = holsterForward; } + auto setHolsterForward(int holsterForward) -> void { holsterForward_ = holsterForward; } - auto executeHolster(int weapon, int player) const -> bool { - if (getHolsterForward() == -1) { - return false; + auto executeHolster(int weapon, int player) const -> bool { + if (getHolsterForward() == -1) { + return false; + } + ExecuteForward(getHolsterForward(), weapon, player); + return true; } - ExecuteForward(getHolsterForward(), weapon, player); - return true; - } - auto getMaxSpeedForward() const { return maxSpeedForward_; } + auto getMaxSpeedForward() const { return maxSpeedForward_; } - auto setMaxSpeedForward(int maxSpeedForward) { maxSpeedForward_ = maxSpeedForward; } + auto setMaxSpeedForward(int maxSpeedForward) -> void { maxSpeedForward_ = maxSpeedForward; } - auto executeMaxSpeed(int weapon, int player, int fov) const -> int { - if (getMaxSpeedForward() == -1) { - return 0; + auto executeMaxSpeed(int weapon, int player, int fov) const -> int { + if (getMaxSpeedForward() == -1) { + return 0; + } + return ExecuteForward(getMaxSpeedForward(), weapon, player, fov); } - return ExecuteForward(getMaxSpeedForward(), weapon, player, fov); - } - auto getPrimaryAttackForward() const { return primaryAttackForward_; } + auto getPrimaryAttackForward() const { return primaryAttackForward_; } - auto setPrimaryAttackForward(int primaryAttackForward) { primaryAttackForward_ = primaryAttackForward; } + auto setPrimaryAttackForward(int primaryAttackForward) -> void { + primaryAttackForward_ = primaryAttackForward; + } - auto executePrimaryAttack(int weapon, int player, int clip, int ammo) const -> bool { - if (getPrimaryAttackForward() == -1) { - return false; + auto executePrimaryAttack(int weapon, int player, int clip, int ammo) const -> bool { + if (getPrimaryAttackForward() == -1) { + return false; + } + ExecuteForward(getPrimaryAttackForward(), weapon, player, clip, ammo); + return true; } - ExecuteForward(getPrimaryAttackForward(), weapon, player, clip, ammo); - return true; - } - auto getSecondaryAttackForward() const { return secondaryAttackForward_; } + auto getSecondaryAttackForward() const { return secondaryAttackForward_; } - auto setSecondaryAttackForward(int secondaryAttackForward) { secondaryAttackForward_ = secondaryAttackForward; } + auto setSecondaryAttackForward(int secondaryAttackForward) -> void { + secondaryAttackForward_ = secondaryAttackForward; + } - auto executeSecondaryAttack(int weapon, int player, int weaponState, int fov) const -> bool { - if (getSecondaryAttackForward() == -1) { - return false; + auto executeSecondaryAttack(int weapon, int player, int weaponState, int fov) const -> bool { + if (getSecondaryAttackForward() == -1) { + return false; + } + ExecuteForward(getSecondaryAttackForward(), weapon, player, weaponState, fov); + return true; } - ExecuteForward(getSecondaryAttackForward(), weapon, player, weaponState, fov); - return true; - } - auto getReloadForward() const { return reloadForward_; } + auto getReloadForward() const { return reloadForward_; } - auto setReloadForward(int reloadForward) { reloadForward_ = reloadForward; } + auto setReloadForward(int reloadForward) -> void { reloadForward_ = reloadForward; } - auto executeReload(int weapon, int player) const -> bool { - if (getReloadForward() == -1) { - return false; + auto executeReload(int weapon, int player) const -> bool { + if (getReloadForward() == -1) { + return false; + } + ExecuteForward(getReloadForward(), weapon, player); + return true; } - ExecuteForward(getReloadForward(), weapon, player); - return true; - } - auto getIdleForward() const { return idleForward_; } + auto getIdleForward() const { return idleForward_; } - auto setIdleForward(int idleForward) { idleForward_ = idleForward; } + auto setIdleForward(int idleForward) -> void { idleForward_ = idleForward; } - auto executeIdle(int weapon, int player, float idleTime) const -> bool { - if (getIdleForward() == -1) { - return false; + auto executeIdle(int weapon, int player, float idleTime) const -> void { + if (getIdleForward() == -1) { + return; + } + ExecuteForward(getIdleForward(), weapon, player, idleTime); } - ExecuteForward(getIdleForward(), weapon, player, idleTime); - return true; - } }; } diff --git a/rezombie/include/rezombie/entity/weapons/melee.h b/rezombie/include/rezombie/entity/weapons/melee.h new file mode 100644 index 0000000..a65e2ad --- /dev/null +++ b/rezombie/include/rezombie/entity/weapons/melee.h @@ -0,0 +1,97 @@ +#pragma once + +#include "rezombie/entity/weapons/base_weapon.h" +#include +#include + +namespace rz +{ + using namespace metamod::engine; + + constexpr auto WEAPON_MELEE = "weapon_knife"; + + enum class MeleeAttackResult { + Miss, + Hit, + HitWall, + }; + + enum class MeleeSound : size_t { + Deploy, + Hit, + Slash, + Stab, + HitWall, + MAX_SOUND_TYPES + }; + + class Melee : public BaseWeapon { + int swingBaseDamage_ = 15; + int swingDistance_ = 48; + int stabBaseDamage_ = 65; + int stabDistance_ = 32; + // float damageMulti; + std::array, toInt(MeleeSound::MAX_SOUND_TYPES)> sounds_; + std::array isDefaultSounds_{}; + + auto sounds(const MeleeSound soundType) -> std::vector& { + return sounds_[toInt(soundType)]; + } + + auto isDefaultSounds(const MeleeSound soundType) -> bool& { + return isDefaultSounds_[toInt(soundType)]; + } + + auto addDefault(const MeleeSound soundType, const std::string& path) -> void { + sounds_[toInt(soundType)].emplace_back(path); + } + + public: + explicit Melee(std::string handle) : BaseWeapon( + std::move(handle), + WEAPON_MELEE, + WeaponType::Melee + ) { + setHud("weapon_knife"); + isDefaultSounds_.fill(true); + addDefault(MeleeSound::Deploy, "weapons/knife_deploy1.wav"); + addDefault(MeleeSound::Hit, "weapons/knife_hit1.wav"); + addDefault(MeleeSound::Hit, "weapons/knife_hit2.wav"); + addDefault(MeleeSound::Hit, "weapons/knife_hit3.wav"); + addDefault(MeleeSound::Hit, "weapons/knife_hit4.wav"); + addDefault(MeleeSound::Slash, "weapons/knife_slash1.wav"); + addDefault(MeleeSound::Slash, "weapons/knife_slash2.wav"); + addDefault(MeleeSound::Stab, "weapons/knife_stab.wav"); + addDefault(MeleeSound::HitWall, "weapons/knife_hitwall1.wav"); + } + + auto executeMeleePrimaryAttack(int weapon, int player) const -> MeleeAttackResult { + if (getPrimaryAttackForward() == -1) { + return MeleeAttackResult::Miss; + } + return static_cast(ExecuteForward(getPrimaryAttackForward(), weapon, player)); + } + + auto executeMeleeSecondaryAttack(int weapon, int player) const -> MeleeAttackResult { + if (getSecondaryAttackForward() == -1) { + return MeleeAttackResult::Miss; + } + return static_cast(ExecuteForward(getSecondaryAttackForward(), weapon, player)); + } + + auto add(const MeleeSound soundType, const std::string& path) -> void { + if (isDefaultSounds(soundType)) { + isDefaultSounds(soundType) = false; + sounds(soundType).clear(); + } + sounds(soundType).emplace_back(path); + } + + auto getRandom(const MeleeSound soundType) -> const std::string& { + // if (sounds_[toInt(soundType)].empty()) { + // return nullptr; + // } + return sounds(soundType)[RandomLong(0, sounds(soundType).size() - 1)]; + } + }; +} diff --git a/rezombie/include/rezombie/entity/weapons/weapon.h b/rezombie/include/rezombie/entity/weapons/weapon.h index 3a8fa78..7d46d28 100644 --- a/rezombie/include/rezombie/entity/weapons/weapon.h +++ b/rezombie/include/rezombie/entity/weapons/weapon.h @@ -6,6 +6,8 @@ namespace rz { + constexpr auto WEAPON_PLACEHOLDER = "weapon_ak47"; + class Weapon : public BaseWeapon { float baseAccuracy_ = 0.f; CrosshairSize crosshairSize_ = CrosshairSize::None; diff --git a/rezombie/include/rezombie/entity/wrappers/player_base_wrapper.h b/rezombie/include/rezombie/entity/wrappers/player_base_wrapper.h deleted file mode 100644 index 3156885..0000000 --- a/rezombie/include/rezombie/entity/wrappers/player_base_wrapper.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "cssdk/public/regamedll.h" - -namespace rz -{ - using namespace cssdk; - - class PlayerBaseWrapper : public PlayerBase { - public: - auto PlayerDeathThink() -> void; - auto HasWeapons() -> bool; - }; -} diff --git a/rezombie/include/rezombie/gamerules/game_rules.h b/rezombie/include/rezombie/gamerules/game_rules.h index 183db9c..997a631 100644 --- a/rezombie/include/rezombie/gamerules/game_rules.h +++ b/rezombie/include/rezombie/gamerules/game_rules.h @@ -11,15 +11,15 @@ namespace rz auto RegisterGameRulesHooks() -> void; - auto InstallGameRules(const ReGameRulesInstallGameRulesMChain& chain) -> GameRules*; + auto InstallGameRules(ReHookInstallGameRules* chain) -> GameRulesBase*; - auto FreeGameRules(const ReGameRulesFreeGameRulesMChain& chain, GameRules**) -> void; + auto FreeGameRules(ReHookFreeGameRules* chain, GameRulesBase**) -> void; - class TeamPlayGameRules : public HalfLifeMultiplay { + class TeamGameRules : public HalfLifeMultiplay { public: - TeamPlayGameRules(); + TeamGameRules(); - ~TeamPlayGameRules() override = default; + ~TeamGameRules() override = default; auto RefreshSkillData() -> void override {}; @@ -40,9 +40,7 @@ namespace rz auto IsCoop() -> qboolean override { return false; } - auto GetGameDescription() -> const char* override { - return "ReZombie"; - } + auto GetGameDescription() -> const char* override; auto ClientConnected(Edict* entity, const char* name, const char* address, char rejectReason[128]) -> qboolean override; @@ -196,6 +194,8 @@ namespace rz auto IsBombPlanted() -> bool override { return false; } + auto Reset() -> void; + auto ReadMultiplayCvars() -> void; auto CheckRoundLimits() -> void; @@ -222,8 +222,8 @@ namespace rz auto setReset(bool isReset) -> void; auto getRoundsPlayed() const -> int; auto setRoundsPlayed(int roundsPlayed) -> void; - auto getRoundRemainingTime() const -> int; - auto setRoundRemainingTime(int remainingTime) -> void; + auto getTimer() const -> int; + auto setTimer(int timer) -> void; auto getGameState() const -> GameState; auto setGameState(GameState gameState) -> void; @@ -243,6 +243,7 @@ namespace rz auto setDefaultPlayerClassOverride(Team team, int playerClass) -> void; auto defaultPlayerClass(Team team) const -> int; + auto getRespawnTeam() const -> Team; auto isCanMove() const -> bool; @@ -253,7 +254,7 @@ namespace rz GameState nextGameState_ = GameState::Warmup; RoundState roundState_ = RoundState::None; RoundState nextRoundState_ = RoundState::None; - int roundRemainingTime_ = 0; + int timer_ = 0; float nextRoundTimeUpdateTime_ = 0; int modeId_ = 0; int lastModeId_ = 0; @@ -263,6 +264,6 @@ namespace rz int shadowSprite_ = 0; }; - inline TeamPlayGameRules* gameRules{}; - inline GameRules* OriginalGameRules{}; + inline TeamGameRules GameRules; + inline GameRulesBase* OriginalGameRules{}; } diff --git a/rezombie/include/rezombie/items/modules/item.h b/rezombie/include/rezombie/items/modules/item.h index c2effce..8e34441 100644 --- a/rezombie/include/rezombie/items/modules/item.h +++ b/rezombie/include/rezombie/items/modules/item.h @@ -7,7 +7,7 @@ namespace rz { class ItemModule : public Module { public: - ItemModule() : Module("item") {} + ItemModule() : Module("item") {} auto add(std::string handle, int giveForward) -> int { return Module::add(new Item(std::move(handle), giveForward)); diff --git a/rezombie/include/rezombie/main/api/main.h b/rezombie/include/rezombie/main/api/main.h new file mode 100644 index 0000000..ef3c01c --- /dev/null +++ b/rezombie/include/rezombie/main/api/main.h @@ -0,0 +1,15 @@ +#pragma once + +#include "rezombie/core/api/amxx_feature.h" + +namespace rz +{ + class AmxxMain : public AmxxFeature<> { + public: + AmxxMain() : AmxxFeature("main") {} + + auto registerNatives() const -> void override; + }; + + inline AmxxMain MainApi; +} diff --git a/rezombie/include/rezombie/main/main.h b/rezombie/include/rezombie/main/main.h index 1d3d696..2d00c08 100644 --- a/rezombie/include/rezombie/main/main.h +++ b/rezombie/include/rezombie/main/main.h @@ -1,9 +1,13 @@ #pragma once +#include #include namespace rz { auto OnAmxxAttach(const AmxxAttachMChain& chain) -> AmxxStatus; auto OnAmxxPluginsLoaded(const AmxxPluginsLoadedMChain& chain) -> void; + auto OnAmxxDetach(const AmxxDetachMChain& chain) -> void; + + inline Extras GlobalExtras; } diff --git a/rezombie/include/rezombie/main/message_hooks.h b/rezombie/include/rezombie/main/message_hooks.h index b553d5a..42431f6 100644 --- a/rezombie/include/rezombie/main/message_hooks.h +++ b/rezombie/include/rezombie/main/message_hooks.h @@ -17,4 +17,13 @@ namespace rz Edict* client, MessageArgs& args ) -> bool; + + auto MessageScreenFade( + const NetworkMessageMChain& chain, + const MessageType& type, + int id, + const float* origin, + Edict* client, + MessageArgs& args + ) -> bool; } diff --git a/rezombie/include/rezombie/map/api/extras.h b/rezombie/include/rezombie/map/api/extras.h new file mode 100644 index 0000000..a59716e --- /dev/null +++ b/rezombie/include/rezombie/map/api/extras.h @@ -0,0 +1,15 @@ +#pragma once + +#include "rezombie/core/api/amxx_feature.h" + +namespace rz +{ + class AmxxMapExtras: public AmxxFeature<> { + public: + AmxxMapExtras() : AmxxFeature("map_extras") {} + + auto registerNatives() const -> void override; + }; + + inline AmxxMapExtras MapExtrasApi; +} diff --git a/rezombie/include/rezombie/map/extras.h b/rezombie/include/rezombie/map/extras.h new file mode 100644 index 0000000..e22c304 --- /dev/null +++ b/rezombie/include/rezombie/map/extras.h @@ -0,0 +1,8 @@ +#pragma once + +#include "rezombie/entity/extras.h" + +namespace rz +{ + inline Extras MapExtras; +} diff --git a/rezombie/include/rezombie/map/modules/fog.h b/rezombie/include/rezombie/map/modules/fog.h index 2bd300b..210d201 100644 --- a/rezombie/include/rezombie/map/modules/fog.h +++ b/rezombie/include/rezombie/map/modules/fog.h @@ -10,7 +10,7 @@ namespace rz class FogModule : public Module { public: - FogModule() : Module("fogs") {} + FogModule() : Module("fogs") {} auto add(std::string color, int densityPercentage) -> int { return Module::add(new Fog(std::move(color), densityPercentage)); diff --git a/rezombie/include/rezombie/map/modules/map_cameras.h b/rezombie/include/rezombie/map/modules/map_cameras.h index b1b2641..1e1baee 100644 --- a/rezombie/include/rezombie/map/modules/map_cameras.h +++ b/rezombie/include/rezombie/map/modules/map_cameras.h @@ -9,7 +9,7 @@ namespace rz Edict* camera_{}; public: - MapCamerasModule() : Module("map_cameras") {} + MapCamerasModule() : Module("map_cameras") {} auto add(Vector origin, Vector angles) -> int { return Module::add(new CameraData(origin, angles)); diff --git a/rezombie/include/rezombie/messages/api/engine_message.h b/rezombie/include/rezombie/messages/api/engine_message.h new file mode 100644 index 0000000..0d124a3 --- /dev/null +++ b/rezombie/include/rezombie/messages/api/engine_message.h @@ -0,0 +1,15 @@ +#pragma once + +#include "rezombie/core/api/amxx_feature.h" + +namespace rz +{ + class AmxxEngineMessage : public AmxxFeature<> { + public: + AmxxEngineMessage() : AmxxFeature("engine_message") {} + + auto registerNatives() const -> void override; + }; + + inline AmxxEngineMessage EngineMessageApi; +} diff --git a/rezombie/include/rezombie/messages/temporary_entity.h b/rezombie/include/rezombie/messages/temporary_entity.h index fe5b1d1..e6189bc 100644 --- a/rezombie/include/rezombie/messages/temporary_entity.h +++ b/rezombie/include/rezombie/messages/temporary_entity.h @@ -4,6 +4,7 @@ * You have to call MessageBegin before call these functions */ +#include "rezombie/colors/colors.h" #include #include @@ -302,17 +303,23 @@ namespace rz WriteByte(scrollSpeed); // scroll speed in 0.1's } - inline auto TE_BeamFollow(int entity, int spriteIndex, byte life, byte lineWidth, byte color[3], byte brightness) - -> void { + inline auto TE_BeamFollow( + int entity, + int spriteIndex, + byte life, + byte lineWidth, + const Color& color + ) -> void { WriteByte(TE_BEAM_FOLLOW); WriteShort(entity); // entity:attachment to follow WriteShort(spriteIndex); // sprite index WriteByte(life); // life in 0.1's WriteByte(lineWidth); // line width in 0.1's - WriteByte(color[0]); // red - WriteByte(color[1]); // green - WriteByte(color[2]); // blue - WriteByte(brightness); // brightness + WriteByte(color.getRed()); // red + WriteByte(color.getGreen()); // green + WriteByte(color.getBlue()); // blue + WriteByte(color.getAlpha()); // brightness + MessageEnd(); } inline auto TE_GlowSprite(Vector& position, int modelIndex, byte scale, byte size, byte brightness) -> void { diff --git a/rezombie/include/rezombie/messages/user_message.h b/rezombie/include/rezombie/messages/user_message.h index 7e6c80e..b61cda4 100644 --- a/rezombie/include/rezombie/messages/user_message.h +++ b/rezombie/include/rezombie/messages/user_message.h @@ -299,8 +299,7 @@ namespace rz short duration = 0, short holdTime = 0, short flags = 0, - const std::string& color = "", - byte alphaPercentage = 0 + const std::string& color = "" ) -> void { SendUserMessage(receiver, UserMessage::ScreenFade, [&]() { WriteShort(duration); @@ -312,7 +311,7 @@ namespace rz WriteByte(realColor.getRed()); WriteByte(realColor.getGreen()); WriteByte(realColor.getBlue()); - WriteByte(255 * alphaPercentage / 100); + WriteByte(realColor.getAlpha()); } else { WriteByte(0); WriteByte(0); @@ -358,6 +357,12 @@ namespace rz }); } + inline auto sendBarTime(Edict* receiver, short duration) -> void { + SendUserMessage(receiver, UserMessage::BarTime, [&]() { + WriteShort(duration); + }); + } + inline auto sendRadar(Edict* receiver, int player, Vector origin) -> void { SendUserMessage(receiver, UserMessage::Radar, [&]() { WriteByte(player); diff --git a/rezombie/include/rezombie/models/modules/models.h b/rezombie/include/rezombie/models/modules/models.h index 9a96dbc..97f17cc 100644 --- a/rezombie/include/rezombie/models/modules/models.h +++ b/rezombie/include/rezombie/models/modules/models.h @@ -13,7 +13,7 @@ namespace rz public: int defaultPlayerModelId_ = 0; - ModelModule() : Module("models") {} + ModelModule() : Module("models") {} auto add(std::string handle, std::string path, int body = 0, int skin = 0) -> int { return Module::add( diff --git a/rezombie/include/rezombie/models/modules/models_pack.h b/rezombie/include/rezombie/models/modules/models_pack.h index 977e80b..a6ce573 100644 --- a/rezombie/include/rezombie/models/modules/models_pack.h +++ b/rezombie/include/rezombie/models/modules/models_pack.h @@ -7,7 +7,7 @@ namespace rz { class ModelsPackModule : public Module { public: - ModelsPackModule() : Module("models_pack") {} + ModelsPackModule() : Module("models_pack") {} auto add(std::string handle) -> int { return Module::add(new ModelsPack(std::move(handle))); diff --git a/rezombie/include/rezombie/gamerules/api/modes.h b/rezombie/include/rezombie/modes/api/modes.h similarity index 87% rename from rezombie/include/rezombie/gamerules/api/modes.h rename to rezombie/include/rezombie/modes/api/modes.h index 05b6412..8e1006f 100644 --- a/rezombie/include/rezombie/gamerules/api/modes.h +++ b/rezombie/include/rezombie/modes/api/modes.h @@ -16,7 +16,7 @@ namespace rz auto registerForwards() -> void override; auto registerNatives() const -> void override; - auto ModeStart(int modeId) -> void; + auto ModeStart(int modeId, int target) const -> void; }; inline AmxxModes ModesApi; diff --git a/rezombie/include/rezombie/gamerules/modules/modes.h b/rezombie/include/rezombie/modes/modules/modes.h similarity index 64% rename from rezombie/include/rezombie/gamerules/modules/modes.h rename to rezombie/include/rezombie/modes/modules/modes.h index 87c4e81..f32ac72 100644 --- a/rezombie/include/rezombie/gamerules/modules/modes.h +++ b/rezombie/include/rezombie/modes/modules/modes.h @@ -7,10 +7,10 @@ namespace rz { class ModesModule : public Module { public: - ModesModule() : Module("modes") {} + ModesModule() : Module("modes") {} - auto add(std::string handle, int launchForward) -> int { - return Module::add(new Mode(std::move(handle), launchForward)); + auto add(std::string handle, int launchForward, bool isSupportTarget) -> int { + return Module::add(new Mode(std::move(handle), launchForward, isSupportTarget)); } }; diff --git a/rezombie/include/rezombie/player/api/flashlight.h b/rezombie/include/rezombie/player/api/flashlight.h index 2dc99a3..a3d3b8c 100644 --- a/rezombie/include/rezombie/player/api/flashlight.h +++ b/rezombie/include/rezombie/player/api/flashlight.h @@ -6,7 +6,7 @@ namespace rz { class AmxxFlashlight : public AmxxFeature<> { public: - AmxxFlashlight() : AmxxFeature("getFlashlight") {} + AmxxFlashlight() : AmxxFeature("flashlight") {} auto registerNatives() const -> void override; }; diff --git a/rezombie/include/rezombie/player/api/jumps.h b/rezombie/include/rezombie/player/api/jumps.h new file mode 100644 index 0000000..d0740ac --- /dev/null +++ b/rezombie/include/rezombie/player/api/jumps.h @@ -0,0 +1,24 @@ +#pragma once + +#include "rezombie/core/api/amxx_feature.h" +#include "rezombie/player/player.h" + +namespace rz +{ + enum class JumpsForward : int { + Jump, + MAX_FORWARDS, + }; + + class AmxxJumps : public AmxxFeature { + public: + AmxxJumps() : AmxxFeature("jumps") {} + + auto registerForwards() -> void override; + auto registerNatives() const -> void override; + + auto Jump(int player, int count) const -> void; + }; + + inline AmxxJumps JumpsApi; +} diff --git a/rezombie/include/rezombie/player/api/long_jump.h b/rezombie/include/rezombie/player/api/long_jump.h new file mode 100644 index 0000000..efa98e4 --- /dev/null +++ b/rezombie/include/rezombie/player/api/long_jump.h @@ -0,0 +1,29 @@ +#pragma once + +#include "rezombie/core/api/amxx_feature.h" + +namespace rz +{ + enum class LongJumpForward : int { + Give, + State, + Activated, + CooldownTimer, + MAX_FORWARDS, + }; + + class AmxxLongJump : public AmxxFeature { + public: + AmxxLongJump() : AmxxFeature("long_jump") {} + + auto registerForwards() -> void override; + auto registerNatives() const -> void override; + + auto Give(int player) const -> void; + auto State(int player, int longJumpState) const -> void; + auto Activated(int player) const -> void; + auto CooldownTimer(int player, int timer) const -> void; + }; + + inline AmxxLongJump LongJumpApi; +} diff --git a/rezombie/include/rezombie/player/api/player.h b/rezombie/include/rezombie/player/api/player.h index d723ec3..c0db4f1 100644 --- a/rezombie/include/rezombie/player/api/player.h +++ b/rezombie/include/rezombie/player/api/player.h @@ -1,8 +1,6 @@ #pragma once #include "rezombie/core/api/amxx_feature.h" -#include "rezombie/player/player.h" -#include "rezombie/player/long_jump_vars.h" namespace rz { @@ -10,8 +8,6 @@ namespace rz Joining, Joined, GiveDefaultItems, - LongJumpState, - LongJumpActivated, MAX_FORWARDS, }; @@ -25,9 +21,6 @@ namespace rz auto Joining(int player) const -> void; auto Joined(int player) const -> void; auto GiveDefaultItems(int player, int classId) const -> ForwardReturn; - - auto LongJumpState(int player, int longJumpState) const -> void; - auto LongJumpActivated(int player) const -> void; }; inline AmxxPlayer PlayerApi; diff --git a/rezombie/include/rezombie/player/api/player_class.h b/rezombie/include/rezombie/player/api/player_class.h index bf41ee1..12ea3ae 100644 --- a/rezombie/include/rezombie/player/api/player_class.h +++ b/rezombie/include/rezombie/player/api/player_class.h @@ -1,7 +1,6 @@ #pragma once #include "rezombie/core/api/amxx_feature.h" -#include "rezombie/player/player.h" namespace rz { diff --git a/rezombie/include/rezombie/player/healthbar.h b/rezombie/include/rezombie/player/healthbar.h new file mode 100644 index 0000000..54021d3 --- /dev/null +++ b/rezombie/include/rezombie/player/healthbar.h @@ -0,0 +1,27 @@ +#pragma once + +#include "rezombie/main/util.h" +#include "cssdk/public/regamedll.h" +#include +#include +#include + +namespace rz +{ + using namespace cssdk; + + class HealthBar { + Edict* entities_[MAX_CLIENTS]{}; + + public: + auto createEntity() -> void; + + auto precache() -> void; + + auto getEntity(int id) -> Edict* { return entities_[id]; } + + auto setEntity(int id, Edict* entity) { entities_[id] = entity; } + }; + + inline HealthBar HealthBar; +} diff --git a/rezombie/include/rezombie/player/preview_vars.h b/rezombie/include/rezombie/player/join_preview_vars.h similarity index 65% rename from rezombie/include/rezombie/player/preview_vars.h rename to rezombie/include/rezombie/player/join_preview_vars.h index f827eb0..3c21b77 100644 --- a/rezombie/include/rezombie/player/preview_vars.h +++ b/rezombie/include/rezombie/player/join_preview_vars.h @@ -6,11 +6,11 @@ namespace rz { using namespace cssdk; - class PreviewVars { + class JoinPreviewVars { bool isEnabled_{}; Vector origin_{}; Vector angles_{}; - std::array modelIds_{}; + std::array modelIds_{}; public: auto isEnabled() const -> bool { return isEnabled_; } @@ -25,8 +25,8 @@ namespace rz auto setAngles(const Vector& angles) -> void { angles_ = angles; } - auto getModel(PreviewType previewType) const -> int { return modelIds_[toInt(previewType)]; } + auto getModel(JoinPreviewType previewType) const -> int { return modelIds_[toInt(previewType)]; } - auto setModel(PreviewType previewType, int modelId) -> void { modelIds_[toInt(previewType)] = modelId; } + auto setModel(JoinPreviewType previewType, int modelId) -> void { modelIds_[toInt(previewType)] = modelId; } }; } diff --git a/rezombie/include/rezombie/player/extra_jump_vars.h b/rezombie/include/rezombie/player/jumps_vars.h similarity index 64% rename from rezombie/include/rezombie/player/extra_jump_vars.h rename to rezombie/include/rezombie/player/jumps_vars.h index f106a47..38f1be1 100644 --- a/rezombie/include/rezombie/player/extra_jump_vars.h +++ b/rezombie/include/rezombie/player/jumps_vars.h @@ -2,12 +2,10 @@ namespace rz { - // add forward for effects maybe - - class ExtraJumpVars { + class JumpsVars { //int id_ = 0; int count_ = 0; - int maximum_ = 0; + int maximum_ = 1; public: //auto getId() const -> int { return id_; } @@ -16,15 +14,15 @@ namespace rz auto getCount() const -> int { return count_; } - auto setCount(int count) -> void { count_ = count; } + auto setCount(int player, int count) -> void; auto getMaximum() const -> int { return maximum_; } auto setMaximum(int maximum) -> void { maximum_ = maximum; } - auto reset() -> void { - setCount(0); - setMaximum(0); + auto reset(int player) -> void { + setCount(player, 0); + setMaximum(1); } }; } diff --git a/rezombie/include/rezombie/player/long_jump_vars.h b/rezombie/include/rezombie/player/long_jump_vars.h index 942a708..18d8152 100644 --- a/rezombie/include/rezombie/player/long_jump_vars.h +++ b/rezombie/include/rezombie/player/long_jump_vars.h @@ -1,5 +1,7 @@ #pragma once +#include "rezombie/player/api/long_jump.h" + namespace rz { enum class LongJumpState : int { @@ -8,15 +10,14 @@ namespace rz Ready, }; - constexpr auto ITEM_LONG_JUMP = "item_longjump"; - class LongJumpVars { //int id_ = 0; LongJumpState state_ = LongJumpState::None; float nextStateTime_ = 0.f; int force_ = 0; int height_ = 0; - float cooldown_ = 0.f; + int cooldown_ = 0; + int cooldownTimer_ = 0; public: //auto getId() const -> int { return id_; } @@ -25,7 +26,7 @@ namespace rz auto getState() const -> LongJumpState { return state_; } - auto setState(LongJumpState state) -> void { state_ = state; } + auto setState(int player, LongJumpState state) -> void; auto getNextStateTime() const -> float { return nextStateTime_; } @@ -39,29 +40,20 @@ namespace rz auto setHeight(int height) -> void { height_ = height; } - auto getCooldown() const -> float { return nextStateTime_; } + auto getCooldown() const -> int { return cooldown_; } + + auto setCooldown(int cooldown) -> void { cooldown_ = cooldown; } + + auto getCooldownTimer() const -> int { return cooldownTimer_; } - auto setCooldown(float cooldown) -> void { nextStateTime_ = cooldown; } + auto setCooldownTimer(int timer) -> void { cooldownTimer_ = timer; } - auto reset() -> void { - setState(LongJumpState::None); + auto reset(int player) -> void { + setState(player, LongJumpState::None); setNextStateTime(0); setForce(0); setHeight(0); setCooldown(0); } }; - - /* - - auto Player::setLongJumpState(LongJumpState state) -> void { - const auto oldState = getLongJumpState(); - playerVars_.longJumpState = state; - if (oldState == state) { - return; - } - PlayerApi.LongJumpState(*this, toInt(getLongJumpState())); - } - - */ } diff --git a/rezombie/include/rezombie/player/modules/flashlight.h b/rezombie/include/rezombie/player/modules/flashlight.h index 55210db..a9db01a 100644 --- a/rezombie/include/rezombie/player/modules/flashlight.h +++ b/rezombie/include/rezombie/player/modules/flashlight.h @@ -7,7 +7,7 @@ namespace rz { class FlashlightModule : public Module { public: - FlashlightModule() : Module("flashlights") {} + FlashlightModule() : Module("flashlights") {} auto add( std::string color, diff --git a/rezombie/include/rezombie/player/modules/nightvision.h b/rezombie/include/rezombie/player/modules/nightvision.h index b2536c3..4f9ff59 100644 --- a/rezombie/include/rezombie/player/modules/nightvision.h +++ b/rezombie/include/rezombie/player/modules/nightvision.h @@ -7,10 +7,10 @@ namespace rz { class NightVisionModule : public Module { public: - NightVisionModule() : Module("nightvisions") {} + NightVisionModule() : Module("nightvisions") {} - auto add(std::string color, int radius, int fogId) -> int { - return Module::add(new NightVision(std::move(color), radius, fogId)); + auto add(std::string color, int fogId) -> int { + return Module::add(new NightVision(std::move(color), fogId)); } }; diff --git a/rezombie/include/rezombie/player/modules/player_class.h b/rezombie/include/rezombie/player/modules/player_class.h index 1343c66..be518d7 100644 --- a/rezombie/include/rezombie/player/modules/player_class.h +++ b/rezombie/include/rezombie/player/modules/player_class.h @@ -8,7 +8,7 @@ namespace rz { class PlayerClassModule : public Module { public: - PlayerClassModule() : Module("player_class") {} + PlayerClassModule() : Module("player_class") {} auto add(std::string handle, Team team) -> int { return Module::add(new PlayerClass(std::move(handle), team)); @@ -20,8 +20,8 @@ namespace rz return item->getTeam() == team; }; }; - gameRules->setDefaultPlayerClass(Team::Human, find(byTeam(Team::Human))); - gameRules->setDefaultPlayerClass(Team::Zombie, find(byTeam(Team::Zombie))); + GameRules.setDefaultPlayerClass(Team::Human, find(byTeam(Team::Human))); + GameRules.setDefaultPlayerClass(Team::Zombie, find(byTeam(Team::Zombie))); } }; diff --git a/rezombie/include/rezombie/player/modules/player_props.h b/rezombie/include/rezombie/player/modules/player_props.h index 8dfd0b6..7404df6 100644 --- a/rezombie/include/rezombie/player/modules/player_props.h +++ b/rezombie/include/rezombie/player/modules/player_props.h @@ -7,7 +7,7 @@ namespace rz { class Props : public Module { public: - Props() : Module("player_props") {} + Props() : Module("player_props") {} auto add(std::string handle) -> int { return Module::add(new PlayerProps(std::move(handle))); diff --git a/rezombie/include/rezombie/player/modules/player_sounds.h b/rezombie/include/rezombie/player/modules/player_sounds.h index 4192924..c16dee1 100644 --- a/rezombie/include/rezombie/player/modules/player_sounds.h +++ b/rezombie/include/rezombie/player/modules/player_sounds.h @@ -7,7 +7,7 @@ namespace rz { class PlayerSoundModule : public Module { public: - PlayerSoundModule() : Module("player_sound") {} + PlayerSoundModule() : Module("player_sound") {} auto add(std::string handle) -> int { return Module::add(new PlayerSounds(std::move(handle))); diff --git a/rezombie/include/rezombie/player/modules/player_subclass.h b/rezombie/include/rezombie/player/modules/player_subclass.h index 5c02d64..2a0ee1f 100644 --- a/rezombie/include/rezombie/player/modules/player_subclass.h +++ b/rezombie/include/rezombie/player/modules/player_subclass.h @@ -7,7 +7,7 @@ namespace rz { class PlayerSubclassModule : public Module { public: - PlayerSubclassModule() : Module("player_subclass") {} + PlayerSubclassModule() : Module("player_subclass") {} auto add(std::string handle, int classIndex) -> int { return Module::add(new PlayerSubclass(std::move(handle), classIndex)); diff --git a/rezombie/include/rezombie/player/player.h b/rezombie/include/rezombie/player/player.h index dd6a21e..a663bff 100644 --- a/rezombie/include/rezombie/player/player.h +++ b/rezombie/include/rezombie/player/player.h @@ -1,19 +1,21 @@ #pragma once #include "rezombie/entity/models/models_pack.h" -#include "rezombie/modelpreview/model_preview.h" +#include "rezombie/preview/join_preview.h" #include "rezombie/map/modules/map_cameras.h" #include "rezombie/player/player_vars.h" #include "rezombie/player/flashlight_vars.h" #include "rezombie/player/nightvision_vars.h" -#include "rezombie/player/extra_jump_vars.h" +#include "rezombie/player/jumps_vars.h" #include "rezombie/player/long_jump_vars.h" -#include "rezombie/player/preview_vars.h" +#include "rezombie/player/join_preview_vars.h" #include "rezombie/player/world_preview_vars.h" #include "rezombie/player/third_camera_vars.h" #include "rezombie/player/map_camera_vars.h" #include "rezombie/weapons/weapons.h" +#include "rezombie/weapons/melee.h" #include "rezombie/entity/weapons/base_weapon.h" +#include "rezombie/entity/weapons/melee.h" #include "rezombie/entity/wrappers/player_item_wrapper.h" #include "rezombie/core/api/amxx_feature.h" #include "rezombie/messages/engine_message.h" @@ -21,6 +23,10 @@ #include #include #include +#include + +#include "cssdk/public/rehlds/rehlds_interfaces.h" +#include "rezombie/entity/extras.h" namespace rz { @@ -38,9 +44,9 @@ namespace rz PlayerVars playerVars_ = {}; FlashlightVars flashlightVars_ = {}; NightVisionVars nightVisionVars_ = {}; - ExtraJumpVars extraJumpVars_ = {}; + JumpsVars jumpsVars_ = {}; LongJumpVars longJumpVars_ = {}; - PreviewVars previewVars_ = {}; + JoinPreviewVars joinPreviewVars_ = {}; WorldPreviewVars worldPreviewVars_ = {}; ThirdCameraVars thirdCameraVars_ = {}; MapCameraVars mapCameraVars_ = {}; @@ -62,10 +68,9 @@ namespace rz auto id() const { return base_->EdictIndex(); } - // auto getEntVars() const - //{ - // return vars_; - // } + auto getEntVars() const { + return vars_; + } //auto getEdict() const { // return edict_; @@ -75,21 +80,25 @@ namespace rz return base_; } + auto Extras() -> Extras& { + return *(base_->link); + } + // auto getCStrike() const //{ // return cstrike_; // } - auto getFlashlight() -> FlashlightVars& { return flashlightVars_; } + auto Flashlight() -> FlashlightVars& { return flashlightVars_; } - auto getNightVision() -> NightVisionVars& { return nightVisionVars_; } + auto NightVision() -> NightVisionVars& { return nightVisionVars_; } - auto getExtraJump() -> ExtraJumpVars& { return extraJumpVars_; } + auto Jumps() -> JumpsVars& { return jumpsVars_; } - auto getLongJump() -> LongJumpVars& { return longJumpVars_; } + auto LongJump() -> LongJumpVars& { return longJumpVars_; } - auto getPreviewVars() -> PreviewVars& { - return previewVars_; + auto getJoinPreviewVars() -> JoinPreviewVars& { + return joinPreviewVars_; } auto getWorldPreviewVars() -> WorldPreviewVars& { @@ -111,7 +120,7 @@ namespace rz auto ChangeClass(int classId, Player* attackerUnsafe = nullptr, bool preSpawn = false) -> ForwardReturn; auto ChangeSubclass(int subclassId) -> ForwardReturn; - auto ChangeProps(int propsId, bool spawn = false) -> bool; + auto ChangeProps(int propsId, bool isSpawn = false) -> bool; auto ChangeModel(int modelId) -> bool; auto SwitchFlashlight(bool isEnabled) -> void; auto ChangeNightVision(int nightVisionId) -> bool; @@ -131,11 +140,12 @@ namespace rz auto Freeze(float freezeTime) -> void; auto RemoveFreeze() -> void; - auto ExtraJump() -> void; + auto JumpThink() -> void; + auto Jump() -> void; - auto GiveLongJump(int force, int height, float cooldown) -> void; + auto GiveLongJump(int force, int height, int cooldown) -> void; auto RemoveLongJump() -> void; - auto LongJump() -> void; + auto ActivateLongJump() -> void; auto LongJumpCooldown() -> void; auto setPreview(bool isEnabled) -> void; @@ -155,9 +165,23 @@ namespace rz return (getTeam() == Team::Human || getTeam() == Team::Zombie); } + template + T* forEachItem(const F& func) { + for (auto* item : base_->player_items) { + while (item) { + auto* const next = item->next; + if (func(static_cast(item))) { + return static_cast(item); + } + item = next; + } + } + return nullptr; + } + template T* forEachItem(InventorySlot slot, const F& func) { - auto item = base_->player_items[toInt(slot)]; + auto item = base_->player_items[toInt(slot) - 1]; while (item != nullptr) { auto next = item->next; if (func(static_cast(item))) { @@ -168,10 +192,22 @@ namespace rz return nullptr; } + auto hasWeapons() -> bool { + return std::any_of( + std::cbegin(base_->player_items), + std::cend(base_->player_items), + [](const auto* item) { + return item != nullptr; + } + ); + } + operator Edict*() const { return edict_; } operator PlayerBase*() const { return base_; } + operator IGameClient*() const { return rehlds_api::ServerStatic()->GetGameClient(id() - 1); } + operator int() const { return base_->EdictIndex(); } auto getHealth() const -> int; @@ -184,9 +220,10 @@ namespace rz auto setMaxSpeed(int maxSpeed) -> void; auto getGravity() const; auto setGravity(float gravity) -> void; + auto getGroundEntity() const -> Edict*; auto getFlags() const -> int; auto setFlags(int flags) -> void; - auto getDeadFlag() const; + auto getDeadFlag() const -> DeathState; auto setDeadFlag(DeathState deadFlag) -> void; auto setViewModel(unsigned int viewModel) -> void; auto setWeaponModel(unsigned int weaponModel) -> void; @@ -194,6 +231,10 @@ namespace rz auto setRenderAmount(int amount) -> void; auto setRenderColor(const std::string& color) -> void; auto setRenderFx(RenderingFx fx) -> void; + auto getNextThink() const -> float; + auto setNextThink(float time) -> void; + auto getMoveType() const -> MoveTypeEntity; + auto setMoveType(MoveTypeEntity moveType) -> void; auto getSkin() const -> int; auto setSkin(int skin) -> void; auto getBody() const -> int; @@ -269,6 +310,8 @@ namespace rz auto setDisconnected(bool isDisconnected) -> void; auto getCanShoot() const -> bool; auto setCanShoot(int canShoot) -> void; + auto getDeadTime() const -> float; + auto setDeadTime(float time) -> void; auto getHideHud() const -> int; auto setHideHud(int hideFlags) -> void; auto setNextAttack(float nextAttack) -> void; @@ -281,6 +324,7 @@ namespace rz auto getAmmo(int ammoIndex) const -> int; auto setAmmo(int ammoIndex, int amount) -> void; auto getObserverTarget() const -> Edict*; + auto setWeaponVolume(int volume) -> void; auto getButtonLast() const -> int; auto setButtonLast(int button) -> void; auto getButtonPressed() const -> int; @@ -304,6 +348,7 @@ namespace rz auto TeamChangeUpdate() -> void; auto Reset() -> void; auto SpawnEquip() -> void; + auto SetScoreboardAttributes(PlayerBase* destination = nullptr) -> void; auto getClass() const -> int; auto setClass(int index) -> void; @@ -366,5 +411,13 @@ namespace rz const Vector& origin, const Vector& velocity, float actionTime - ) -> cssdk::Grenade*; + ) -> Grenade*; + + auto MeleeDefaultAttack( + Player& player, + Knife* knife, + float damage, + float distance, + float backDamageMultiplier = 1.0f + ) -> MeleeAttackResult; } diff --git a/rezombie/include/rezombie/player/player_vars.h b/rezombie/include/rezombie/player/player_vars.h index b469f15..fb2fbb3 100644 --- a/rezombie/include/rezombie/player/player_vars.h +++ b/rezombie/include/rezombie/player/player_vars.h @@ -2,7 +2,7 @@ #include "rezombie/player/long_jump_vars.h" #include "rezombie/entity/models/models_pack.h" -#include "rezombie/modelpreview/model_preview.h" +#include "rezombie/preview/join_preview.h" #include "rezombie/weapons/weapons.h" #include #include diff --git a/rezombie/include/rezombie/player/world_preview_vars.h b/rezombie/include/rezombie/player/world_preview_vars.h index d1a02af..fe25cec 100644 --- a/rezombie/include/rezombie/player/world_preview_vars.h +++ b/rezombie/include/rezombie/player/world_preview_vars.h @@ -11,6 +11,7 @@ namespace rz Vector origin_{}; Vector angles_{}; int modelId_{}; + int maxDistance_{}; public: auto isEnabled() const -> bool { return isEnabled_; } @@ -28,5 +29,9 @@ namespace rz auto getModel() const -> int { return modelId_; } auto setModel(int modelId) -> void { modelId_ = modelId; } + + auto getMaxDistance() const -> int { return maxDistance_; } + + auto setMaxDistance(int maxDistance) -> void { maxDistance_ = maxDistance; } }; } diff --git a/rezombie/include/rezombie/modelpreview/api/model_preview.h b/rezombie/include/rezombie/preview/api/join_preview.h similarity index 80% rename from rezombie/include/rezombie/modelpreview/api/model_preview.h rename to rezombie/include/rezombie/preview/api/join_preview.h index 2e83756..66b07c7 100644 --- a/rezombie/include/rezombie/modelpreview/api/model_preview.h +++ b/rezombie/include/rezombie/preview/api/join_preview.h @@ -6,7 +6,7 @@ namespace rz { class AmxxModelPreview : public AmxxFeature<> { public: - AmxxModelPreview() : AmxxFeature("model_preview") {} + AmxxModelPreview() : AmxxFeature("join_preview") {} auto registerNatives() const -> void override; }; diff --git a/rezombie/include/rezombie/preview/api/world_preview.h b/rezombie/include/rezombie/preview/api/world_preview.h new file mode 100644 index 0000000..7a39cb7 --- /dev/null +++ b/rezombie/include/rezombie/preview/api/world_preview.h @@ -0,0 +1,15 @@ +#pragma once + +#include "rezombie/core/api/amxx_feature.h" + +namespace rz +{ + class AmxxWorldPreview : public AmxxFeature<> { + public: + AmxxWorldPreview() : AmxxFeature("world_preview") {} + + auto registerNatives() const -> void override; + }; + + inline AmxxWorldPreview WorldPreviewApi; +} diff --git a/rezombie/include/rezombie/modelpreview/model_preview.h b/rezombie/include/rezombie/preview/join_preview.h similarity index 58% rename from rezombie/include/rezombie/modelpreview/model_preview.h rename to rezombie/include/rezombie/preview/join_preview.h index 96cd586..393f9d7 100644 --- a/rezombie/include/rezombie/modelpreview/model_preview.h +++ b/rezombie/include/rezombie/preview/join_preview.h @@ -1,7 +1,7 @@ #pragma once #include "rezombie/main/util.h" -#include +#include "cssdk/public/regamedll.h" #include #include #include @@ -10,7 +10,7 @@ namespace rz { using namespace cssdk; - enum class PreviewType : int { + enum class JoinPreviewType : int { ParentModel, AttachModel, ExtraAttachModel, @@ -18,22 +18,22 @@ namespace rz }; class ModelPreview { - std::array entities_{}; + std::array entities_{}; float viewForwardDistance_ = 96; float buttonsRotateSpeed_ = 2; public: auto createEntities() -> void; - auto getEntity(PreviewType previewEntity) -> Edict* { return entities_[toInt(previewEntity)]; } + auto getEntity(JoinPreviewType previewEntity) -> Edict* { return entities_[toInt(previewEntity)]; } - auto setEntity(PreviewType previewEntity, Edict* entity) { entities_[toInt(previewEntity)] = entity; } + auto setEntity(JoinPreviewType previewEntity, Edict* entity) { entities_[toInt(previewEntity)] = entity; } auto getViewForwardDistance() const -> float { return viewForwardDistance_; } auto setViewForwardDistance(float viewForwardDistance) -> void { viewForwardDistance_ = viewForwardDistance; } - auto& operator[](PreviewType previewEntity) { return entities_[toInt(previewEntity)]; } + auto& operator[](JoinPreviewType previewEntity) { return entities_[toInt(previewEntity)]; } }; inline ModelPreview ModelPreview; diff --git a/rezombie/include/rezombie/player/world_preview.h b/rezombie/include/rezombie/preview/world_preview.h similarity index 95% rename from rezombie/include/rezombie/player/world_preview.h rename to rezombie/include/rezombie/preview/world_preview.h index 251a8af..6490c13 100644 --- a/rezombie/include/rezombie/player/world_preview.h +++ b/rezombie/include/rezombie/preview/world_preview.h @@ -1,7 +1,7 @@ #pragma once #include "rezombie/main/util.h" -#include +#include "cssdk/public/regamedll.h" #include #include #include diff --git a/rezombie/include/rezombie/sounds/api/sounds.h b/rezombie/include/rezombie/sounds/api/sounds.h new file mode 100644 index 0000000..bf6e190 --- /dev/null +++ b/rezombie/include/rezombie/sounds/api/sounds.h @@ -0,0 +1,15 @@ +#pragma once + +#include "rezombie/core/api/amxx_feature.h" + +namespace rz +{ + class AmxxSounds : public AmxxFeature<> { + public: + AmxxSounds() : AmxxFeature("sounds") {} + + auto registerNatives() const -> void override; + }; + + inline AmxxSounds SoundsApi; +} diff --git a/rezombie/include/rezombie/sounds/sounds.h b/rezombie/include/rezombie/sounds/sounds.h new file mode 100644 index 0000000..c3354a3 --- /dev/null +++ b/rezombie/include/rezombie/sounds/sounds.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace rz +{ + class Sounds { + std::string lastAmbienceSound_; + + public: + auto playAmbienceSound(const std::string& soundPath) -> void; + auto stopAmbienceSound() -> void; + }; + + inline Sounds Sounds; +} diff --git a/rezombie/include/rezombie/weapons/api/melee.h b/rezombie/include/rezombie/weapons/api/melee.h index 431f05f..77ca369 100644 --- a/rezombie/include/rezombie/weapons/api/melee.h +++ b/rezombie/include/rezombie/weapons/api/melee.h @@ -1,9 +1,21 @@ #pragma once #include "rezombie/core/api/amxx_feature.h" +#include "rezombie/entity/weapons/melee.h" namespace rz { + enum class MeleeForward : int { + AttackPre, + AttackPost, + MAX_FORWARDS, + }; + + enum MeleeAttackType { + Primary, + Secondary, + }; + enum class MeleeVars : int { Handle, ViewModel, @@ -13,12 +25,16 @@ namespace rz Name, }; - class AmxxMelee : public AmxxFeature<> { + class AmxxMelee : public AmxxFeature { public: AmxxMelee() : AmxxFeature("melee") {} + auto registerForwards() -> void override; auto registerNatives() const -> void override; + + auto AttackPre(int player, MeleeAttackType attackType) const -> ForwardReturn; + auto AttackPost(int player, MeleeAttackType attackType, MeleeAttackResult result) const -> void; }; - inline AmxxMelee amxxMelee; + inline AmxxMelee MeleeApi; } diff --git a/rezombie/include/rezombie/weapons/api/weapon.h b/rezombie/include/rezombie/weapons/api/weapon.h index 557fa00..fcff819 100644 --- a/rezombie/include/rezombie/weapons/api/weapon.h +++ b/rezombie/include/rezombie/weapons/api/weapon.h @@ -1,8 +1,6 @@ #pragma once #include "rezombie/core/api/amxx_feature.h" -#include -#include namespace rz { diff --git a/rezombie/include/rezombie/weapons/melee.h b/rezombie/include/rezombie/weapons/melee.h index fb44093..08b35c2 100644 --- a/rezombie/include/rezombie/weapons/melee.h +++ b/rezombie/include/rezombie/weapons/melee.h @@ -1,36 +1,38 @@ #pragma once #include "rezombie/entity/weapons/base_weapon.h" -#include namespace rz { - const std::string WEAPON_MELEE = "weapon_knife"; - - class Melee : public BaseWeapon { - int swingBaseDamage_ = 15; - int swingDistance_ = 48; - int stabBaseDamage_ = 65; - int stabDistance_ = 32; - // float damageMulti; - // Array: Melee_Sounds[MAX_MELEE_SOUNDS]; - - public: - explicit Melee(std::string handle) : BaseWeapon( - std::move(handle), - WEAPON_MELEE, - WeaponType::Melee - ) {} + enum KnifeAnimations { + KNIFE_IDLE, + KNIFE_ATTACK1_HIT, + KNIFE_ATTACK2_HIT, + KNIFE_DRAW, + KNIFE_STAB_HIT, + KNIFE_STAB_MISS, + KNIFE_MIDDLE_ATTACK1_HIT, + KNIFE_MIDDLE_ATTACK2_HIT, }; class MeleeVirtuals : public PlayerWeaponBase { + static VirtualHook addToPlayer; static VirtualHook deploy; + static VirtualHook maxSpeed; static VirtualHook primaryAttack; static VirtualHook secondaryAttack; + static VirtualHook idle; + static VirtualHook create; + static VirtualHook destroy; protected: + auto MeleeAddToPlayer(PlayerBase* basePlayer) -> qboolean; auto MeleeDeploy() -> qboolean; + auto MeleeMaxSpeed() -> float; auto MeleePrimaryAttack() -> void; auto MeleeSecondaryAttack() -> void; + auto MeleeIdle() -> void; + auto MeleeCreate() -> void; + auto MeleeDestroy() -> void; }; } diff --git a/rezombie/include/rezombie/weapons/modules/weapon.h b/rezombie/include/rezombie/weapons/modules/weapon.h index 1bca9e1..f4095eb 100644 --- a/rezombie/include/rezombie/weapons/modules/weapon.h +++ b/rezombie/include/rezombie/weapons/modules/weapon.h @@ -2,9 +2,7 @@ #include "rezombie/core/module.h" #include "rezombie/entity/weapons/weapon.h" -#include "rezombie/weapons/melee.h" -#include "core/strings/format.h" -#include "cssdk/dll/weapon_type.h" +#include "rezombie/entity/weapons/melee.h" namespace rz { @@ -13,7 +11,7 @@ namespace rz class WeaponModule : public Module { public: - WeaponModule() : Module("weapons") {} + WeaponModule() : Module("weapons") {} auto add(std::string handle, WeaponType weaponType) -> int { if (weaponType == WeaponType::Melee) { diff --git a/rezombie/include/rezombie/weapons/weapons.h b/rezombie/include/rezombie/weapons/weapons.h index 8717d4f..4526918 100644 --- a/rezombie/include/rezombie/weapons/weapons.h +++ b/rezombie/include/rezombie/weapons/weapons.h @@ -1,6 +1,5 @@ #pragma once -#include "rezombie/main/util.h" #include #include @@ -11,27 +10,6 @@ namespace rz void RegisterWeaponHooks(); - constexpr auto WEAPON_PLACEHOLDER = "weapon_ak47"; - - enum class WeaponType : int { - Primary, // automatic - Secondary, // once - Melee, // delete - Grenade, // auto throw - Extra, - }; - - enum class CrosshairSize : int { - None, - Size3, - Size4, - Size5, - Size6, - Size7, - Size8, - Size9, - }; - enum class GiveType : int { Append, Replace, @@ -53,6 +31,8 @@ namespace rz static VirtualHook reload; static VirtualHook idle; static VirtualHook postFrame; + static VirtualHook create; + static VirtualHook destroy; protected: auto HolderSpawn() -> void; @@ -69,5 +49,7 @@ namespace rz auto HolderReload() -> void; auto HolderIdle() -> void; auto HolderPostFrame() -> void; + auto HolderCreate() -> void; + auto HolderDestroy() -> void; }; } diff --git a/rezombie/src/colors/api/colors.cpp b/rezombie/src/colors/api/colors.cpp index d7b8bbf..e9145d3 100644 --- a/rezombie/src/colors/api/colors.cpp +++ b/rezombie/src/colors/api/colors.cpp @@ -15,15 +15,13 @@ namespace rz arg_color, }; - const auto name = GetAmxString(amx, params[arg_name]); - const auto colors = Address(amx, params[arg_color]); - const auto color = Color( - toUChar(colors[0]), - toUChar(colors[1]), - toUChar(colors[2]), - toUChar(colors[3]) - ); - Colors.add(name, color); + const auto name = GetAmxString(amx, params[arg_name], 0); + const auto color = GetAmxString(amx, params[arg_color], 1); + const auto colorRef = Colors.parse(color); + if (!colorRef) { + return false; + } + Colors.add(name, *colorRef); return true; } diff --git a/rezombie/src/colors/colors.cpp b/rezombie/src/colors/colors.cpp index f8eb261..9790176 100644 --- a/rezombie/src/colors/colors.cpp +++ b/rezombie/src/colors/colors.cpp @@ -1,282 +1,271 @@ #include "rezombie/colors/colors.h" -#include +#include "rezombie/main/util.h" #include -#include -#include namespace rz { Colors::Colors() : defaultColors_( { - {"transparent", {0, 0, 0, 0}}, - {"aliceblue", {240, 248, 255, 1}}, - {"antiquewhite", {250, 235, 215, 1}}, - {"aqua", {0, 255, 255, 1}}, - {"aquamarine", {127, 255, 212, 1}}, - {"azure", {240, 255, 255, 1}}, - {"beige", {245, 245, 220, 1}}, - {"bisque", {255, 228, 196, 1}}, - {"black", {0, 0, 0, 1}}, - {"blanchedalmond", {255, 235, 205, 1}}, - {"blue", {0, 0, 255, 1}}, - {"blueviolet", {138, 43, 226, 1}}, - {"brown", {165, 42, 42, 1}}, - {"burlywood", {222, 184, 135, 1}}, - {"cadetblue", {95, 158, 160, 1}}, - {"chartreuse", {127, 255, 0, 1}}, - {"chocolate", {210, 105, 30, 1}}, - {"coral", {255, 127, 80, 1}}, - {"cornflowerblue", {100, 149, 237, 1}}, - {"cornsilk", {255, 248, 220, 1}}, - {"crimson", {220, 20, 60, 1}}, - {"cyan", {0, 255, 255, 1}}, - {"darkblue", {0, 0, 139, 1}}, - {"darkcyan", {0, 139, 139, 1}}, - {"darkgoldenrod", {184, 134, 11, 1}}, - {"darkgray", {169, 169, 169, 1}}, - {"darkgreen", {0, 100, 0, 1}}, - {"darkgrey", {169, 169, 169, 1}}, - {"darkkhaki", {189, 183, 107, 1}}, - {"darkmagenta", {139, 0, 139, 1}}, - {"darkolivegreen", {85, 107, 47, 1}}, - {"darkorange", {255, 140, 0, 1}}, - {"darkorchid", {153, 50, 204, 1}}, - {"darkred", {139, 0, 0, 1}}, - {"darksalmon", {233, 150, 122, 1}}, - {"darkseagreen", {143, 188, 143, 1}}, - {"darkslateblue", {72, 61, 139, 1}}, - {"darkslategray", {47, 79, 79, 1}}, - {"darkslategrey", {47, 79, 79, 1}}, - {"darkturquoise", {0, 206, 209, 1}}, - {"darkviolet", {148, 0, 211, 1}}, - {"deeppink", {255, 20, 147, 1}}, - {"deepskyblue", {0, 191, 255, 1}}, - {"dimgray", {105, 105, 105, 1}}, - {"dimgrey", {105, 105, 105, 1}}, - {"dodgerblue", {30, 144, 255, 1}}, - {"firebrick", {178, 34, 34, 1}}, - {"floralwhite", {255, 250, 240, 1}}, - {"forestgreen", {34, 139, 34, 1}}, - {"fuchsia", {255, 0, 255, 1}}, - {"gainsboro", {220, 220, 220, 1}}, - {"ghostwhite", {248, 248, 255, 1}}, - {"gold", {255, 215, 0, 1}}, - {"goldenrod", {218, 165, 32, 1}}, - {"gray", {128, 128, 128, 1}}, - {"green", {0, 128, 0, 1}}, - {"greenyellow", {173, 255, 47, 1}}, - {"grey", {128, 128, 128, 1}}, - {"honeydew", {240, 255, 240, 1}}, - {"hotpink", {255, 105, 180, 1}}, - {"indianred", {205, 92, 92, 1}}, - {"indigo", {75, 0, 130, 1}}, - {"ivory", {255, 255, 240, 1}}, - {"khaki", {240, 230, 140, 1}}, - {"lavender", {230, 230, 250, 1}}, - {"lavenderblush", {255, 240, 245, 1}}, - {"lawngreen", {124, 252, 0, 1}}, - {"lemonchiffon", {255, 250, 205, 1}}, - {"lightblue", {173, 216, 230, 1}}, - {"lightcoral", {240, 128, 128, 1}}, - {"lightcyan", {224, 255, 255, 1}}, + {"transparent", {0, 0, 0, 0}}, + {"aliceblue", {240, 248, 255, 1}}, + {"antiquewhite", {250, 235, 215, 1}}, + {"aqua", {0, 255, 255, 1}}, + {"aquamarine", {127, 255, 212, 1}}, + {"azure", {240, 255, 255, 1}}, + {"beige", {245, 245, 220, 1}}, + {"bisque", {255, 228, 196, 1}}, + {"black", {0, 0, 0, 1}}, + {"blanchedalmond", {255, 235, 205, 1}}, + {"blue", {0, 0, 255, 1}}, + {"blueviolet", {138, 43, 226, 1}}, + {"brown", {165, 42, 42, 1}}, + {"burlywood", {222, 184, 135, 1}}, + {"cadetblue", {95, 158, 160, 1}}, + {"chartreuse", {127, 255, 0, 1}}, + {"chocolate", {210, 105, 30, 1}}, + {"coral", {255, 127, 80, 1}}, + {"cornflowerblue", {100, 149, 237, 1}}, + {"cornsilk", {255, 248, 220, 1}}, + {"crimson", {220, 20, 60, 1}}, + {"cyan", {0, 255, 255, 1}}, + {"darkblue", {0, 0, 139, 1}}, + {"darkcyan", {0, 139, 139, 1}}, + {"darkgoldenrod", {184, 134, 11, 1}}, + {"darkgray", {169, 169, 169, 1}}, + {"darkgreen", {0, 100, 0, 1}}, + {"darkgrey", {169, 169, 169, 1}}, + {"darkkhaki", {189, 183, 107, 1}}, + {"darkmagenta", {139, 0, 139, 1}}, + {"darkolivegreen", {85, 107, 47, 1}}, + {"darkorange", {255, 140, 0, 1}}, + {"darkorchid", {153, 50, 204, 1}}, + {"darkred", {139, 0, 0, 1}}, + {"darksalmon", {233, 150, 122, 1}}, + {"darkseagreen", {143, 188, 143, 1}}, + {"darkslateblue", {72, 61, 139, 1}}, + {"darkslategray", {47, 79, 79, 1}}, + {"darkslategrey", {47, 79, 79, 1}}, + {"darkturquoise", {0, 206, 209, 1}}, + {"darkviolet", {148, 0, 211, 1}}, + {"deeppink", {255, 20, 147, 1}}, + {"deepskyblue", {0, 191, 255, 1}}, + {"dimgray", {105, 105, 105, 1}}, + {"dimgrey", {105, 105, 105, 1}}, + {"dodgerblue", {30, 144, 255, 1}}, + {"firebrick", {178, 34, 34, 1}}, + {"floralwhite", {255, 250, 240, 1}}, + {"forestgreen", {34, 139, 34, 1}}, + {"fuchsia", {255, 0, 255, 1}}, + {"gainsboro", {220, 220, 220, 1}}, + {"ghostwhite", {248, 248, 255, 1}}, + {"gold", {255, 215, 0, 1}}, + {"goldenrod", {218, 165, 32, 1}}, + {"gray", {128, 128, 128, 1}}, + {"green", {0, 128, 0, 1}}, + {"greenyellow", {173, 255, 47, 1}}, + {"grey", {128, 128, 128, 1}}, + {"honeydew", {240, 255, 240, 1}}, + {"hotpink", {255, 105, 180, 1}}, + {"indianred", {205, 92, 92, 1}}, + {"indigo", {75, 0, 130, 1}}, + {"ivory", {255, 255, 240, 1}}, + {"khaki", {240, 230, 140, 1}}, + {"lavender", {230, 230, 250, 1}}, + {"lavenderblush", {255, 240, 245, 1}}, + {"lawngreen", {124, 252, 0, 1}}, + {"lemonchiffon", {255, 250, 205, 1}}, + {"lightblue", {173, 216, 230, 1}}, + {"lightcoral", {240, 128, 128, 1}}, + {"lightcyan", {224, 255, 255, 1}}, {"lightgoldenrodyellow", {250, 250, 210, 1}}, - {"lightgray", {211, 211, 211, 1}}, - {"lightgreen", {144, 238, 144, 1}}, - {"lightgrey", {211, 211, 211, 1}}, - {"lightpink", {255, 182, 193, 1}}, - {"lightsalmon", {255, 160, 122, 1}}, - {"lightseagreen", {32, 178, 170, 1}}, - {"lightskyblue", {135, 206, 250, 1}}, - {"lightslategray", {119, 136, 153, 1}}, - {"lightslategrey", {119, 136, 153, 1}}, - {"lightsteelblue", {176, 196, 222, 1}}, - {"lightyellow", {255, 255, 224, 1}}, - {"lime", {0, 255, 0, 1}}, - {"limegreen", {50, 205, 50, 1}}, - {"linen", {250, 240, 230, 1}}, - {"magenta", {255, 0, 255, 1}}, - {"maroon", {128, 0, 0, 1}}, - {"mediumaquamarine", {102, 205, 170, 1}}, - {"mediumblue", {0, 0, 205, 1}}, - {"mediumorchid", {186, 85, 211, 1}}, - {"mediumpurple", {147, 112, 219, 1}}, - {"mediumseagreen", {60, 179, 113, 1}}, - {"mediumslateblue", {123, 104, 238, 1}}, - {"mediumspringgreen", {0, 250, 154, 1}}, - {"mediumturquoise", {72, 209, 204, 1}}, - {"mediumvioletred", {199, 21, 133, 1}}, - {"midnightblue", {25, 25, 112, 1}}, - {"mintcream", {245, 255, 250, 1}}, - {"mistyrose", {255, 228, 225, 1}}, - {"moccasin", {255, 228, 181, 1}}, - {"navajowhite", {255, 222, 173, 1}}, - {"navy", {0, 0, 128, 1}}, - {"oldlace", {253, 245, 230, 1}}, - {"olive", {128, 128, 0, 1}}, - {"olivedrab", {107, 142, 35, 1}}, - {"orange", {255, 165, 0, 1}}, - {"orangered", {255, 69, 0, 1}}, - {"orchid", {218, 112, 214, 1}}, - {"palegoldenrod", {238, 232, 170, 1}}, - {"palegreen", {152, 251, 152, 1}}, - {"paleturquoise", {175, 238, 238, 1}}, - {"palevioletred", {219, 112, 147, 1}}, - {"papayawhip", {255, 239, 213, 1}}, - {"peachpuff", {255, 218, 185, 1}}, - {"peru", {205, 133, 63, 1}}, - {"pink", {255, 192, 203, 1}}, - {"plum", {221, 160, 221, 1}}, - {"powderblue", {176, 224, 230, 1}}, - {"purple", {128, 0, 128, 1}}, - {"red", {255, 0, 0, 1}}, - {"rosybrown", {188, 143, 143, 1}}, - {"royalblue", {65, 105, 225, 1}}, - {"saddlebrown", {139, 69, 19, 1}}, - {"salmon", {250, 128, 114, 1}}, - {"sandybrown", {244, 164, 96, 1}}, - {"seagreen", {46, 139, 87, 1}}, - {"seashell", {255, 245, 238, 1}}, - {"sienna", {160, 82, 45, 1}}, - {"silver", {192, 192, 192, 1}}, - {"skyblue", {135, 206, 235, 1}}, - {"slateblue", {106, 90, 205, 1}}, - {"slategray", {112, 128, 144, 1}}, - {"slategrey", {112, 128, 144, 1}}, - {"snow", {255, 250, 250, 1}}, - {"springgreen", {0, 255, 127, 1}}, - {"steelblue", {70, 130, 180, 1}}, - {"tan", {210, 180, 140, 1}}, - {"teal", {0, 128, 128, 1}}, - {"thistle", {216, 191, 216, 1}}, - {"tomato", {255, 99, 71, 1}}, - {"turquoise", {64, 224, 208, 1}}, - {"violet", {238, 130, 238, 1}}, - {"wheat", {245, 222, 179, 1}}, - {"white", {255, 255, 255, 1}}, - {"whitesmoke", {245, 245, 245, 1}}, - {"yellow", {255, 255, 0, 1}}, - {"yellowgreen", {154, 205, 50, 1}}, + {"lightgray", {211, 211, 211, 1}}, + {"lightgreen", {144, 238, 144, 1}}, + {"lightgrey", {211, 211, 211, 1}}, + {"lightpink", {255, 182, 193, 1}}, + {"lightsalmon", {255, 160, 122, 1}}, + {"lightseagreen", {32, 178, 170, 1}}, + {"lightskyblue", {135, 206, 250, 1}}, + {"lightslategray", {119, 136, 153, 1}}, + {"lightslategrey", {119, 136, 153, 1}}, + {"lightsteelblue", {176, 196, 222, 1}}, + {"lightyellow", {255, 255, 224, 1}}, + {"lime", {0, 255, 0, 1}}, + {"limegreen", {50, 205, 50, 1}}, + {"linen", {250, 240, 230, 1}}, + {"magenta", {255, 0, 255, 1}}, + {"maroon", {128, 0, 0, 1}}, + {"mediumaquamarine", {102, 205, 170, 1}}, + {"mediumblue", {0, 0, 205, 1}}, + {"mediumorchid", {186, 85, 211, 1}}, + {"mediumpurple", {147, 112, 219, 1}}, + {"mediumseagreen", {60, 179, 113, 1}}, + {"mediumslateblue", {123, 104, 238, 1}}, + {"mediumspringgreen", {0, 250, 154, 1}}, + {"mediumturquoise", {72, 209, 204, 1}}, + {"mediumvioletred", {199, 21, 133, 1}}, + {"midnightblue", {25, 25, 112, 1}}, + {"mintcream", {245, 255, 250, 1}}, + {"mistyrose", {255, 228, 225, 1}}, + {"moccasin", {255, 228, 181, 1}}, + {"navajowhite", {255, 222, 173, 1}}, + {"navy", {0, 0, 128, 1}}, + {"oldlace", {253, 245, 230, 1}}, + {"olive", {128, 128, 0, 1}}, + {"olivedrab", {107, 142, 35, 1}}, + {"orange", {255, 165, 0, 1}}, + {"orangered", {255, 69, 0, 1}}, + {"orchid", {218, 112, 214, 1}}, + {"palegoldenrod", {238, 232, 170, 1}}, + {"palegreen", {152, 251, 152, 1}}, + {"paleturquoise", {175, 238, 238, 1}}, + {"palevioletred", {219, 112, 147, 1}}, + {"papayawhip", {255, 239, 213, 1}}, + {"peachpuff", {255, 218, 185, 1}}, + {"peru", {205, 133, 63, 1}}, + {"pink", {255, 192, 203, 1}}, + {"plum", {221, 160, 221, 1}}, + {"powderblue", {176, 224, 230, 1}}, + {"purple", {128, 0, 128, 1}}, + {"red", {255, 0, 0, 1}}, + {"rosybrown", {188, 143, 143, 1}}, + {"royalblue", {65, 105, 225, 1}}, + {"saddlebrown", {139, 69, 19, 1}}, + {"salmon", {250, 128, 114, 1}}, + {"sandybrown", {244, 164, 96, 1}}, + {"seagreen", {46, 139, 87, 1}}, + {"seashell", {255, 245, 238, 1}}, + {"sienna", {160, 82, 45, 1}}, + {"silver", {192, 192, 192, 1}}, + {"skyblue", {135, 206, 235, 1}}, + {"slateblue", {106, 90, 205, 1}}, + {"slategray", {112, 128, 144, 1}}, + {"slategrey", {112, 128, 144, 1}}, + {"snow", {255, 250, 250, 1}}, + {"springgreen", {0, 255, 127, 1}}, + {"steelblue", {70, 130, 180, 1}}, + {"tan", {210, 180, 140, 1}}, + {"teal", {0, 128, 128, 1}}, + {"thistle", {216, 191, 216, 1}}, + {"tomato", {255, 99, 71, 1}}, + {"turquoise", {64, 224, 208, 1}}, + {"violet", {238, 130, 238, 1}}, + {"wheat", {245, 222, 179, 1}}, + {"white", {255, 255, 255, 1}}, + {"whitesmoke", {245, 245, 245, 1}}, + {"yellow", {255, 255, 0, 1}}, + {"yellowgreen", {154, 205, 50, 1}}, } ) { } - // TODO: clamp - template - auto clampCssByte(T i) -> unsigned char { - i = ::round(i); - return i < 0 ? 0 : i > 255 ? 255 : uint8_t(i); + auto clampCssByte(const uint8_t value) -> uint8_t { + return std::clamp(value, static_cast(0), UINT8_MAX); } - template - auto clampCssFloat(T f) -> float { - return f < 0 ? 0 : f > 1 ? 1 : float(f); + auto clampCssFloat(const float value) -> float { + return std::clamp(value, 0.f, 1.f); } - auto parseInt(const std::string& str, unsigned char base = 10) -> int64_t { - return strtoll(str.c_str(), nullptr, base); + auto parseInt(const std::string& input, const uint8_t base = 10) -> int64_t { + return strtoll(input.c_str(), nullptr, base); } - auto parseFloat(const std::string& str) -> float { - return strtof(str.c_str(), nullptr); + auto parseFloat(const std::string& input) -> float { + return strtof(input.c_str(), nullptr); } - auto parseCssInt(const std::string& str) -> unsigned char { - if (str.length() && str.back() == '%') { - return clampCssByte(parseFloat(str) / 100.0f * 255.0f); - } else { - return clampCssByte(parseInt(str)); + auto parseCssInt(const std::string& str) -> uint8_t { + if (!str.empty() && str.back() == '%') { + return clampCssByte(static_cast(parseFloat(str) / 100.f * 255.f)); } + return clampCssByte(static_cast(parseInt(str))); } auto parseCssFloat(const std::string& str) -> float { - if (str.length() && str.back() == '%') { - return clampCssFloat(parseFloat(str) / 100.0f); - } else { - return clampCssFloat(parseFloat(str)); + if (!str.empty() && str.back() == '%') { + return clampCssFloat(parseFloat(str) / 100.f); } + return clampCssFloat(parseFloat(str)); } - auto split(const std::string& s, char delim) -> std::vector { - std::vector elems; - std::stringstream ss(s); + auto split(const std::string& input, const char delim) -> std::vector { + std::vector elements; + std::stringstream inputStream(input); std::string item; - while (std::getline(ss, item, delim)) { - elems.emplace_back(item); + while (std::getline(inputStream, item, delim)) { + elements.emplace_back(item); } - return elems; + return elements; } auto Colors::parse(const std::string& color) -> std::optional { auto str = color; - str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); - std::transform(str.begin(), str.end(), str.begin(), std::tolower); - for (const auto& namedColor: defaultColors_) { - if (str != namedColor.first) { - continue; - } - return {namedColor.second}; + str.erase(std::ranges::begin(std::ranges::remove(str, ' ')), std::end(str)); + std::ranges::transform(str.begin(), str.end(), str.begin(), std::tolower); + const auto& namedDefaultColor = getMapValue(defaultColors_, str); + if (namedDefaultColor) { + return *namedDefaultColor; } - for (const auto& namedColor: customColors_) { - if (str != namedColor.first) { - continue; - } - return {namedColor.second}; + const auto& namedCustomColor = getMapValue(customColors_, str); + if (namedCustomColor) { + return *namedCustomColor; } - if (str.length() && str.front() == '#') { + if (!str.empty() && str.front() == '#') { if (str.length() == 4) { - int64_t iv = parseInt(str.substr(1), 16); + const int64_t iv = parseInt(str.substr(1), 16); if (!(iv >= 0 && iv <= 0xfff)) { return std::nullopt; - } else { - return { - { - static_cast(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)), - static_cast((iv & 0xf0) | ((iv & 0xf0) >> 4)), - static_cast((iv & 0xf) | ((iv & 0xf) << 4)), - static_cast(255) - } - }; } - } else if (str.length() == 7) { - int64_t iv = parseInt(str.substr(1), 16); + return { + { + static_cast(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)), + static_cast((iv & 0xf0) | ((iv & 0xf0) >> 4)), + static_cast((iv & 0xf) | ((iv & 0xf) << 4)), + 1 + } + }; + } + if (str.length() == 7) { + const int64_t iv = parseInt(str.substr(1), 16); if (!(iv >= 0 && iv <= 0xffffff)) { return std::nullopt; - } else { - return { - { - static_cast((iv & 0xff0000) >> 16), - static_cast((iv & 0xff00) >> 8), - static_cast(iv & 0xff), - static_cast(255) - } - }; } + return { + { + static_cast((iv & 0xff0000) >> 16), + static_cast((iv & 0xff00) >> 8), + static_cast(iv & 0xff), + 1 + } + }; } return std::nullopt; } - auto op = str.find_first_of('('); - auto ep = str.find_first_of(')'); + const auto op = str.find_first_of('('); + const auto ep = str.find_first_of(')'); if (op != std::string::npos && ep + 1 == str.length()) { const auto fname = str.substr(0, op); + if (fname != "rgba" && fname != "rgb") { + return std::nullopt; + } const auto params = split(str.substr(op + 1, ep - (op + 1)), ','); - float alpha = 1.0f; - if (fname == "rgba" || fname == "rgb") { - if (fname == "rgba") { - if (params.size() != 4) { - return std::nullopt; - } - alpha = parseCssFloat(params.back()); - } else { - if (params.size() != 3) { - return std::nullopt; + if (fname == "rgb" && params.size() == 3) { + return { + { + parseCssInt(params[0]), + parseCssInt(params[1]), + parseCssInt(params[2]), + 1 } - } + }; + } + if (fname == "rgba" && params.size() == 4) { return { { parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), - static_cast(alpha) + parseCssFloat(params.back()) } }; } diff --git a/rezombie/src/configs/main_config.cpp b/rezombie/src/configs/main_config.cpp new file mode 100644 index 0000000..cbcdf75 --- /dev/null +++ b/rezombie/src/configs/main_config.cpp @@ -0,0 +1,39 @@ +#include "rezombie/configs/main_config.h" +#include "rezombie/main/util.h" +#include +#include +#include +#include + +namespace rz +{ + using namespace core; + using namespace nlohmann; + + template + auto read(const json& data, const std::string& key, V& var) -> bool { + const auto it = data.find(key); + if (it == data.end()) { + return false; + } + it->get_to(var); + return true; + } + + auto MainConfig::load() -> void { + const std::filesystem::path path = str::BuildPathName("rezombie/configs/main.json"); + std::ifstream file(path); + if (!file) { + return; + } + const auto data = json::parse(file); + metamod::utils::LogConsole("%s", data.dump(4).c_str()); + + read(data, "server_browser_info", serverBrowserInfo_); + read(data, "sky_name", skyName_); + read(data, "warmup_time", warmupTime_); + read(data, "prepare_time", prepareTime_); + read(data, "round_time", roundTime_); + read(data, "useless_entities", uselessEntities_); + } +} diff --git a/rezombie/src/currency/api/currency.cpp b/rezombie/src/currency/api/currency.cpp index 9955cf2..e3ac680 100644 --- a/rezombie/src/currency/api/currency.cpp +++ b/rezombie/src/currency/api/currency.cpp @@ -1,6 +1,7 @@ #include "rezombie/currency/api/currency.h" #include "rezombie/currency/modules/currency.h" -#include "amxx/api.h" +#include "rezombie/player/players.h" +#include namespace rz { @@ -82,13 +83,39 @@ namespace rz return Currency[handle]; } + auto add_player_currency(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_player, + arg_currency, + arg_amount, + arg_reason, + arg_reason_arguments, + }; + + // Check arg count + const int playerId = params[arg_player]; + const auto& player = Players[playerId]; + const auto currencyId = params[arg_currency]; + const auto& currencyRef = Currency[currencyId]; + if (!currencyRef) { + // throw + return false; + } + const auto currency = currencyRef->get(); + auto length = 0; + const auto reason = FormatAmxString(amx, params, arg_reason, &length); + return currency.executeSet(player, currency.executeGet(player) + params[arg_amount], reason); + } + auto AmxxCurrency::registerNatives() const -> void { static AmxNativeInfo natives[] = { - {"create_currency", create_currency}, - {"format_currency", format_currency}, - {"find_currency", find_currency}, + {"create_currency", create_currency}, + {"format_currency", format_currency}, + {"find_currency", find_currency}, + {"add_player_currency", add_player_currency}, - {nullptr, nullptr}, + {nullptr, nullptr}, }; AddNatives(natives); } diff --git a/rezombie/src/gamerules/api/game_rules.cpp b/rezombie/src/gamerules/api/game_rules.cpp index 10d041b..89c67c4 100644 --- a/rezombie/src/gamerules/api/game_rules.cpp +++ b/rezombie/src/gamerules/api/game_rules.cpp @@ -1,7 +1,8 @@ #include "rezombie/gamerules/api/game_rules.h" #include "rezombie/gamerules/game_rules.h" -#include "rezombie/gamerules/modules/modes.h" -#include "amxx/api.h" +#include "rezombie/modes/modules/modes.h" +#include "rezombie/core/api/amxx_helper.h" +#include namespace rz { @@ -57,7 +58,7 @@ namespace rz enum class GameVars : int { GameState, RoundState, - RoundRemainingTime, + Timer, TeamWins, Mode, DefaultClass, @@ -67,7 +68,7 @@ namespace rz const std::unordered_map GameVarsMap = { {"game_state", GameVars::GameState}, {"round_state", GameVars::RoundState}, - {"round_remaining_time", GameVars::RoundRemainingTime}, + {"timer", GameVars::Timer}, {"team_wins", GameVars::TeamWins}, {"mode", GameVars::Mode}, {"default_class", GameVars::DefaultClass}, @@ -83,17 +84,13 @@ namespace rz }; using vars = GameVars; - const auto key = GetAmxString(amx, params[arg_var]); const auto& var = getMapValue(GameVarsMap, key); - if (!var) { - // Invalid index - return false; - } + CHECK_VAR_EXISTS("Invalid game '%s' var", key) switch (*var) { case vars::GameState: { if (isGetter) { - return toInt(gameRules->getGameState()); + return toInt(GameRules.getGameState()); } else { // Invalid set vars } @@ -101,15 +98,15 @@ namespace rz } case vars::RoundState: { if (isGetter) { - return toInt(gameRules->getRoundState()); + return toInt(GameRules.getRoundState()); } else { // Invalid set vars } break; } - case vars::RoundRemainingTime: { + case vars::Timer: { if (isGetter) { - return gameRules->getRoundRemainingTime(); + return GameRules.getTimer(); } else { // Invalid set vars } @@ -118,15 +115,15 @@ namespace rz case vars::TeamWins: { const auto team = static_cast(*Address(amx, params[arg_2])); if (isGetter) { - return gameRules->getTeamWins(team); + return GameRules.getTeamWins(team); } else { - gameRules->setTeamWins(team, *Address(amx, params[arg_3])); + GameRules.setTeamWins(team, *Address(amx, params[arg_3])); } break; } case vars::Mode: { if (isGetter) { - return gameRules->getMode(); + return GameRules.getMode(); } else { // Invalid set vars } @@ -136,15 +133,15 @@ namespace rz const auto team = static_cast(*Address(amx, params[arg_2])); // CHECK_PLAYABLE_TEAM(team, false) if (isGetter) { - if (gameRules->getDefaultPlayerClassOverride(team)) { - return gameRules->getDefaultPlayerClassOverride(team); + if (GameRules.getDefaultPlayerClassOverride(team)) { + return GameRules.getDefaultPlayerClassOverride(team); } - return gameRules->getDefaultPlayerClass(team); + return GameRules.getDefaultPlayerClass(team); } else { const int classId = *Address(amx, params[arg_3]); // new index = rz_module_get_valid_index(g_iModule, class); // CHECK_MODULE_VALID_INDEX(index, false) - gameRules->setDefaultPlayerClassOverride(team, classId); + GameRules.setDefaultPlayerClassOverride(team, classId); } break; } @@ -156,12 +153,12 @@ namespace rz // CHECK_PLAYABLE_TEAM(team, false) const int classId = *Address(amx, params[arg_3]); if (!classId) { - gameRules->setDefaultPlayerClassOverride(team, 0); + GameRules.setDefaultPlayerClassOverride(team, 0); return true; } // new index = rz_module_get_valid_index(g_iModule, class); // CHECK_MODULE_VALID_INDEX(index, false) - gameRules->setDefaultPlayerClassOverride(team, classId); + GameRules.setDefaultPlayerClassOverride(team, classId); } break; } diff --git a/rezombie/src/gamerules/api/modes.cpp b/rezombie/src/gamerules/api/modes.cpp deleted file mode 100644 index a805792..0000000 --- a/rezombie/src/gamerules/api/modes.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "rezombie/gamerules/api/modes.h" -#include "rezombie/gamerules/modules/modes.h" -#include "rezombie/main/util.h" -#include - -namespace rz -{ - using namespace amx; - using namespace amxx; - - auto AmxxModes::ModeStart(int modeId) -> void { - executeForward(ModesForward::ModeStart, modeId); - } - - auto AmxxModes::registerForwards() -> void { - using e = ForwardExecType; - using p = ForwardParam; - - setForward( - ModesForward::ModeStart, - RegisterForward("@mode_start", e::Ignore, p::Cell, p::Done) - ); - } - - enum class ModeVars : int { - Handle, - Name, - HudColor, - DropChance, - MinimumPlayers, - RoundTime, - }; - - const std::unordered_map ModeVarsMap = { - {"handle", ModeVars::Handle}, - {"name", ModeVars::Name}, - {"hud_color", ModeVars::HudColor}, - {"drop_chance", ModeVars::DropChance}, - {"minimum_players", ModeVars::MinimumPlayers}, - {"round_time", ModeVars::RoundTime}, - }; - - auto create_mode(Amx* amx, cell* params) -> cell { - enum { - arg_count, - arg_handle, - arg_launch_forward, - }; - - using p = ForwardParam; - - // Check arg count - auto handle = GetAmxString(amx, params[arg_handle], 0); - const auto launchForward = RegisterSpForwardByName( - amx, GetAmxString(amx, params[arg_launch_forward], 1), - p::Cell, p::Done - ); - if (launchForward == FORWARD_INVALID) { - return 0; - } - const auto modeId = Modes.add(handle, launchForward); - return modeId; - } - - auto HandleModeVar(Amx* amx, cell* params, bool isGetter) -> cell { - enum { - arg_count, - arg_mode, - arg_var, - arg_3, - arg_4, - }; - - using vars = ModeVars; - - const int modeId = params[arg_mode]; - const auto modeRef = Modes[modeId]; - if (!modeRef) { - // Invalid index - return false; - } - const auto key = GetAmxString(amx, params[arg_var]); - const auto& var = getMapValue(ModeVarsMap, key); - if (!var) { - // Invalid index - return false; - } - auto& mode = modeRef->get(); - switch (*var) { - case vars::Handle: { - if (isGetter) { - SetAmxString(amx, params[arg_3], mode.getHandle().c_str(), params[arg_4]); - } else { - // Invalid set vars - } - break; - } - case vars::Name: { - if (isGetter) { - SetAmxString(amx, params[arg_3], mode.getName().c_str(), *Address(amx, params[arg_4])); - } else { - mode.setName(GetAmxString(amx, params[arg_3])); - } - break; - } - case vars::HudColor: { - if (isGetter) { - SetAmxString(amx, params[arg_3], mode.getHudColor().c_str(), *Address(amx, params[arg_4])); - } else { - mode.setHudColor(GetAmxString(amx, params[arg_3])); - } - break; - } - case vars::DropChance: { - if (isGetter) { - return mode.getDropChance(); - } else { - mode.setDropChance(*Address(amx, params[arg_3])); - } - break; - } - case vars::MinimumPlayers: { - if (isGetter) { - return mode.getMinPlayers(); - } else { - mode.setMinPlayers(*Address(amx, params[arg_3])); - } - break; - } - case vars::RoundTime: { - if (isGetter) { - return mode.getRoundTime(); - } else { - mode.setRoundTime(*Address(amx, params[arg_3])); - } - break; - } - } - return true; - } - - auto get_mode_var(Amx* amx, cell* params) -> cell { - return HandleModeVar(amx, params, true); - } - - auto set_mode_var(Amx* amx, cell* params) -> cell { - return HandleModeVar(amx, params, false); - } - - auto mode_begin(Amx*, cell*) -> cell { - return Modes.begin(); - } - - auto mode_end(Amx*, cell*) -> cell { - return Modes.end(); - } - - auto find_mode(Amx* amx, cell* params) -> cell { - enum { - arg_count, - arg_handle, - }; - - const auto handle = GetAmxString(amx, params[arg_handle]); - return Modes[handle]; - } - - auto AmxxModes::registerNatives() const -> void { - static AmxNativeInfo natives[] = { - {"create_mode", create_mode}, - {"get_mode_var", get_mode_var}, - {"set_mode_var", set_mode_var}, - {"mode_begin", mode_begin}, - {"mode_end", mode_end}, - {"find_mode", find_mode}, - - {nullptr, nullptr}, - }; - AddNatives(natives); - } -} diff --git a/rezombie/src/gamerules/game_rules.cpp b/rezombie/src/gamerules/game_rules.cpp index 3995a51..1c90984 100644 --- a/rezombie/src/gamerules/game_rules.cpp +++ b/rezombie/src/gamerules/game_rules.cpp @@ -1,48 +1,50 @@ #include "rezombie/gamerules/game_rules.h" #include "rezombie/gamerules/api/game_rules.h" -#include "rezombie/gamerules/api/modes.h" -#include "rezombie/gamerules/modules/modes.h" +#include "rezombie/modes/api/modes.h" +#include "rezombie/modes/modules/modes.h" #include "rezombie/player/players.h" #include "rezombie/map/environment.h" #include "rezombie/main/util.h" #include "rezombie/messages/user_message.h" +#include "rezombie/configs/main_config.h" #include #include #include -#include namespace rz { using namespace cssdk; using namespace metamod::engine; using namespace metamod::gamedll; - using namespace mhooks; auto RegisterGameRulesHooks() -> void { - MHookReGameRulesInstallGameRules(DELEGATE_ARG, HookChainPriority::Low); - MHookReGameRulesFreeGameRules(DELEGATE_ARG); + const auto hooks = regamedll_api::HookChains(); + + hooks->InstallGameRules()->RegisterHook(&InstallGameRules, HookChainPriority::Low); + hooks->FreeGameRules()->RegisterHook(&FreeGameRules); } - auto InstallGameRules(const ReGameRulesInstallGameRulesMChain& chain) -> cssdk::GameRules* { - OriginalGameRules = chain.CallNext(); + auto InstallGameRules(ReHookInstallGameRules* chain) -> GameRulesBase* { + OriginalGameRules = chain->CallNext(); ConVarInit(); - if (!gameRules) { - gameRules = new TeamPlayGameRules(); - } - return gameRules; + /*if (!GameRules) { + GameRules = new TeamGameRules(); + }*/ + GameRules.Reset(); + return &GameRules; } - auto FreeGameRules(const ReGameRulesFreeGameRulesMChain& chain, cssdk::GameRules**) -> void { - chain.CallNext(&OriginalGameRules); + auto FreeGameRules(ReHookFreeGameRules* chain, GameRulesBase**) -> void { + chain->CallNext(&OriginalGameRules); OriginalGameRules = nullptr; - delete gameRules; - gameRules = nullptr; + /*delete GameRules; + GameRules = nullptr;*/ } - TeamPlayGameRules::TeamPlayGameRules() { + TeamGameRules::TeamGameRules() { // setGameState(GameState::Warmup); - // setRoundRemainingTime(10); - roundRemainingTime_ = 10; + // setTimer(10); + timer_ = 10; game_started_ = false; freeze_period = false; setWinStatus(WinStatus::None); @@ -60,16 +62,20 @@ namespace rz round_terminating = false; setRoundsPlayed(0); - ReadMultiplayCvars(); - max_idle_period = std::numeric_limits::max(); - CvarSetFloat("pausable", 0); - skip_spawn_ = false; skip_show_menu_ = false; time_limit_ = 0; + Environment.reset(); + } + + auto TeamGameRules::Reset() -> void { + ReadMultiplayCvars(); + + CvarSetFloat("pausable", 0); + spawn_point_count_terrorist = g_global_vars->max_clients; spawn_point_count_ct = g_global_vars->max_clients; level_initialized = true; @@ -78,11 +84,13 @@ namespace rz CvarSetFloat(sv_accelerate->name, 5); CvarSetFloat(sv_friction->name, 4); CvarSetFloat(sv_stopspeed->name, 75); + } - Environment.reset(); + auto TeamGameRules::GetGameDescription() -> const char* { + return MainConfig.getServerBrowswerInfo().c_str(); } - auto TeamPlayGameRules::ReadMultiplayCvars() -> void { + auto TeamGameRules::ReadMultiplayCvars() -> void { //limit_teams = 0; //unbalanced_rounds = 0; //CvarSetFloat(mp_limitteams->name, 0); @@ -91,7 +99,7 @@ namespace rz CheckRoundLimits(); } - auto TeamPlayGameRules::CheckRoundLimits() -> void { + auto TeamGameRules::CheckRoundLimits() -> void { max_rounds = static_cast(mp_maxrounds->value); if (max_rounds < 0) { max_rounds = 0; @@ -105,7 +113,7 @@ namespace rz } } - auto TeamPlayGameRules::RestartRound() -> void { + auto TeamGameRules::RestartRound() -> void { // change to listener CvarSetFloat(sv_accelerate->name, 5); CvarSetFloat(sv_friction->name, 4); @@ -154,7 +162,7 @@ namespace rz ); if (getGameState() == GameState::Playing) { - setRoundRemainingTime(10); + setTimer(10); } Environment.reset(); @@ -163,7 +171,7 @@ namespace rz setReset(false); } - auto TeamPlayGameRules::Think() -> void { + auto TeamGameRules::Think() -> void { // m_VoiceGameMgr.Update(gpGlobals->frametime); if (getGameState() != GameState::Warmup && getGameState() != GameState::Over) { @@ -224,9 +232,9 @@ namespace rz if (nextRoundTimeUpdateTime_ <= g_global_vars->time) { nextRoundTimeUpdateTime_ = g_global_vars->time + 1.0f; - setRoundRemainingTime(getRoundRemainingTime() - 1); + setTimer(getTimer() - 1); } - if (getRoundRemainingTime() != 0) { + if (getTimer() != 0) { return; } switch (getGameState()) { @@ -266,15 +274,14 @@ namespace rz setMode(modeId); const auto& mode = modeRef->get(); if (mode.getRoundTime()) { - setRoundRemainingTime(mode.getRoundTime()); + setTimer(mode.getRoundTime()); } else { - setRoundRemainingTime(round_time); + setTimer(round_time); } - mode.executeLaunch(modeId); + const auto target = mode.executeLaunch(); + ModesApi.ModeStart(modeId, target); + setRoundState(RoundState::Playing); } - // TODO: no need? - ModesApi.ModeStart(modeId); - setRoundState(RoundState::Playing); break; } case RoundState::Playing: { @@ -295,7 +302,7 @@ namespace rz } } - auto TeamPlayGameRules::getRandomMode() const -> int { + auto TeamGameRules::getRandomMode() const -> int { if (Modes.count() == 1) { return Modes.begin(); } @@ -332,14 +339,14 @@ namespace rz return resultMode; } - auto TeamPlayGameRules::EndRound(EndRoundEvent event) -> void { + auto TeamGameRules::EndRound(EndRoundEvent event) -> void { switch (event) { case EndRoundEvent::WarmupEnd: { setReset(true); // setGameState(GameState::Playing); setRoundState(RoundState::Terminate); setWinStatus(WinStatus::Draw); - setRoundRemainingTime(3); + setTimer(3); break; } case EndRoundEvent::GameCommence: { @@ -347,7 +354,7 @@ namespace rz setGameState(GameState::Playing); setRoundState(RoundState::Terminate); setWinStatus(WinStatus::Draw); - setRoundRemainingTime(3); + setTimer(3); break; } case EndRoundEvent::GameRestart: { @@ -355,21 +362,21 @@ namespace rz setReset(true); setRoundState(RoundState::Terminate); setWinStatus(WinStatus::Draw); - setRoundRemainingTime(1); + setTimer(1); break; } case EndRoundEvent::GameOver: { setGameState(GameState::Over); setRoundState(RoundState::Terminate); setWinStatus(WinStatus::Draw); - setRoundRemainingTime(10); + setTimer(10); break; } case EndRoundEvent::HumansWin: { setRoundState(RoundState::Terminate); setWinStatus(WinStatus::Cts); setTeamWins(Team::Human, getTeamWins(Team::Human) + 1); - setRoundRemainingTime(static_cast(mp_round_restart_delay->value)); + setTimer(static_cast(mp_round_restart_delay->value)); CheckRoundsLimit(); break; } @@ -377,26 +384,26 @@ namespace rz setRoundState(RoundState::Terminate); setWinStatus(WinStatus::Terrorists); setTeamWins(Team::Zombie, getTeamWins(Team::Zombie) + 1); - setRoundRemainingTime(static_cast(mp_round_restart_delay->value)); + setTimer(static_cast(mp_round_restart_delay->value)); CheckRoundsLimit(); break; } } - GameRulesApi.RoundEnd(event, getMode(), getRoundRemainingTime()); + GameRulesApi.RoundEnd(event, getMode(), getTimer()); } - auto TeamPlayGameRules::UpdateTeamScores() -> void { + auto TeamGameRules::UpdateTeamScores() -> void { sendTeamScore(TO_ALL, Team::Human, getTeamWins(Team::Human)); sendTeamScore(TO_ALL, Team::Zombie, getTeamWins(Team::Zombie)); } - auto TeamPlayGameRules::GoToIntermission() -> void { + auto TeamGameRules::GoToIntermission() -> void { if (getGameState() == GameState::Over) { return; } int chatTime = std::clamp(static_cast(mp_chattime->value), 0, MAX_INTERMISSION_TIME); setGameState(GameState::Over); // endRound? - setRoundRemainingTime(chatTime); + setTimer(chatTime); Players.forEachConnected( [](auto& player) { if (!(player.getButton() & IN_SCORE)) { @@ -408,20 +415,20 @@ namespace rz ); } - auto TeamPlayGameRules::ChangeLevel() -> void { + auto TeamGameRules::ChangeLevel() -> void { const char* nextMap = "de_dust2"; metamod::engine::ChangeLevel(nextMap, nullptr); } - auto TeamPlayGameRules::CleanUpMap() -> void { + auto TeamGameRules::CleanUpMap() -> void { OriginalGameRules->CsGameRules()->CleanUpMap(); } - auto TeamPlayGameRules::RemoveGuns() -> void { + auto TeamGameRules::RemoveGuns() -> void { OriginalGameRules->CsGameRules()->RemoveGuns(); } - auto TeamPlayGameRules::CheckWinConditions() -> void { + auto TeamGameRules::CheckWinConditions() -> void { /*if (getGameState() == GameState::Warmup || getGameState() == GameState::Over) { return; } @@ -450,7 +457,7 @@ namespace rz }*/ } - auto TeamPlayGameRules::CheckRoundsLimit() -> bool { + auto TeamGameRules::CheckRoundsLimit() -> bool { if (max_rounds_won != 0 && (getTeamWins(Team::Human) >= max_rounds_won || getTeamWins(Team::Zombie) >= max_rounds_won)) { GoToIntermission(); @@ -463,7 +470,7 @@ namespace rz return false; } - auto TeamPlayGameRules::changeGameState(GameState gameState) -> void { + auto TeamGameRules::changeGameState(GameState gameState) -> void { /*if (getGameState() == gameState) { return; }*/ @@ -501,23 +508,23 @@ namespace rz } } - auto TeamPlayGameRules::GetTimeLeft() const { + auto TeamGameRules::GetTimeLeft() const { return time_limit_ - g_global_vars->time; } - auto TeamPlayGameRules::GetRoundElapsedTime() const { + auto TeamGameRules::GetRoundElapsedTime() const { return g_global_vars->time - round_start_time; } - auto TeamPlayGameRules::GetMapElapsedTime() const { + auto TeamGameRules::GetMapElapsedTime() const { return g_global_vars->time; } - auto TeamPlayGameRules::GetRoundRespawnTime() const { + auto TeamGameRules::GetRoundRespawnTime() const { return mp_roundrespawn_time->value; } - auto TeamPlayGameRules::getTeamWins(Team team) const -> short { + auto TeamGameRules::getTeamWins(Team team) const -> short { switch (team) { case Team::Human: { return num_ct_wins; @@ -531,7 +538,7 @@ namespace rz } } - auto TeamPlayGameRules::setTeamWins(Team team, int wins, bool update) -> void { + auto TeamGameRules::setTeamWins(Team team, int wins, bool update) -> void { switch (team) { case Team::Human: { num_ct_wins = static_cast(wins); @@ -553,119 +560,147 @@ namespace rz } } - auto TeamPlayGameRules::getWinStatus() const -> WinStatus { + auto TeamGameRules::getWinStatus() const -> WinStatus { return round_win_status; } - auto TeamPlayGameRules::setWinStatus(WinStatus winStatus) -> void { + auto TeamGameRules::setWinStatus(WinStatus winStatus) -> void { round_win_status = winStatus; } - auto TeamPlayGameRules::isReset() const -> bool { + auto TeamGameRules::isReset() const -> bool { return complete_reset; } - auto TeamPlayGameRules::setReset(bool isReset) -> void { + auto TeamGameRules::setReset(bool isReset) -> void { complete_reset = isReset; } - auto TeamPlayGameRules::getRoundsPlayed() const -> int { + auto TeamGameRules::getRoundsPlayed() const -> int { return total_rounds_played; } - auto TeamPlayGameRules::setRoundsPlayed(int roundsPlayed) -> void { + auto TeamGameRules::setRoundsPlayed(int roundsPlayed) -> void { total_rounds_played = roundsPlayed; } - auto TeamPlayGameRules::getRoundRemainingTime() const -> int { - return roundRemainingTime_; + auto TeamGameRules::getTimer() const -> int { + return timer_; } - auto TeamPlayGameRules::setRoundRemainingTime(int remainingTime) -> void { - if (remainingTime < 0) { - remainingTime = 0; + auto TeamGameRules::setTimer(int timer) -> void { + if (timer < 0) { + timer = 0; } - roundRemainingTime_ = remainingTime; + timer_ = timer; nextRoundTimeUpdateTime_ = g_global_vars->time + 1.0f; - GameRulesApi.RoundTimer(getRoundRemainingTime()); + GameRulesApi.RoundTimer(getTimer()); } - auto TeamPlayGameRules::getGameState() const -> GameState { + auto TeamGameRules::getGameState() const -> GameState { return gameState_; } - auto TeamPlayGameRules::setGameState(GameState gameState) -> void { + auto TeamGameRules::setGameState(GameState gameState) -> void { const auto oldState = gameState_; gameState_ = gameState; GameRulesApi.GameStateChanged(oldState, gameState); } - auto TeamPlayGameRules::getNextGameState() const -> GameState { + auto TeamGameRules::getNextGameState() const -> GameState { return nextGameState_; } - auto TeamPlayGameRules::setNextGameState(GameState gameState) -> void { + auto TeamGameRules::setNextGameState(GameState gameState) -> void { nextGameState_ = gameState; } - auto TeamPlayGameRules::getRoundState() const -> RoundState { + auto TeamGameRules::getRoundState() const -> RoundState { return roundState_; } - auto TeamPlayGameRules::setRoundState(RoundState roundState) -> void { + auto TeamGameRules::setRoundState(RoundState roundState) -> void { const auto oldState = roundState_; roundState_ = roundState; GameRulesApi.RoundStateChanged(oldState, roundState); } - auto TeamPlayGameRules::getNextRoundState() const -> RoundState { + auto TeamGameRules::getNextRoundState() const -> RoundState { return roundState_; } - auto TeamPlayGameRules::setNextRoundState(RoundState roundState) -> void { + auto TeamGameRules::setNextRoundState(RoundState roundState) -> void { nextRoundState_ = roundState; } - auto TeamPlayGameRules::getMode() const -> int { + auto TeamGameRules::getMode() const -> int { return modeId_; } - auto TeamPlayGameRules::setMode(int modeId) -> void { + auto TeamGameRules::setMode(int modeId) -> void { modeId_ = modeId; } - auto TeamPlayGameRules::getLastMode() const -> int { + auto TeamGameRules::getLastMode() const -> int { return lastModeId_; } - auto TeamPlayGameRules::setLastMode(int lastModeId) -> void { + auto TeamGameRules::setLastMode(int lastModeId) -> void { lastModeId_ = lastModeId; } - auto TeamPlayGameRules::getDefaultPlayerClass(Team team) const -> int { + auto TeamGameRules::getDefaultPlayerClass(Team team) const -> int { return defaultPlayerClass_[toInt(team)]; } - auto TeamPlayGameRules::setDefaultPlayerClass(Team team, int playerClass) -> void { + auto TeamGameRules::setDefaultPlayerClass(Team team, int playerClass) -> void { defaultPlayerClass_[toInt(team)] = playerClass; } - auto TeamPlayGameRules::getDefaultPlayerClassOverride(Team team) const -> int { + auto TeamGameRules::getDefaultPlayerClassOverride(Team team) const -> int { return defaultPlayerClassOverride_[toInt(team)]; } - auto TeamPlayGameRules::setDefaultPlayerClassOverride(Team team, int playerClass) -> void { + auto TeamGameRules::setDefaultPlayerClassOverride(Team team, int playerClass) -> void { defaultPlayerClassOverride_[toInt(team)] = playerClass; } - auto TeamPlayGameRules::defaultPlayerClass(Team team) const -> int { + auto TeamGameRules::defaultPlayerClass(Team team) const -> int { if (!getDefaultPlayerClassOverride(team)) { return getDefaultPlayerClass(team); } return getDefaultPlayerClassOverride(team); } - auto TeamPlayGameRules::isCanMove() const -> bool { + auto TeamGameRules::getRespawnTeam() const -> Team { + if (getGameState() != GameState::Playing) { + return Team::Human; + } + if (getRoundState() != RoundState::Playing) { + return Team::Human; + } + const auto modeRef = Modes[getMode()]; + if (modeRef) { + const auto& mode = modeRef->get(); + switch (mode.getRespawn()) { + case RespawnType::ToZombiesTeam: { + return Team::Zombie; + } + case RespawnType::Balance: { + if (getPlayersCount(PlayersCountFlags::Humans) >= getPlayersCount(PlayersCountFlags::Zombies)) { + return Team::Zombie; + } + break; + } + default: { + break; + } + } + } + return Team::Human; + } + + auto TeamGameRules::isCanMove() const -> bool { switch (getGameState()) { case GameState::Warmup: { if (getRoundState() == RoundState::Terminate) { @@ -676,11 +711,14 @@ namespace rz case GameState::Over: { return false; } + default: { + break; + } } return true; } - auto TeamPlayGameRules::precache() -> void { + auto TeamGameRules::precache() -> void { shadowSprite_ = PrecacheModel("sprites/shadow_circle.spr"); } } diff --git a/rezombie/src/gamerules/player.cpp b/rezombie/src/gamerules/player.cpp index 849740b..ac3e67e 100644 --- a/rezombie/src/gamerules/player.cpp +++ b/rezombie/src/gamerules/player.cpp @@ -7,12 +7,14 @@ #include #include +#include "rezombie/modes/modules/modes.h" + namespace rz { using namespace cssdk; using namespace metamod::engine; - auto TeamPlayGameRules::ClientConnected( + auto TeamGameRules::ClientConnected( Edict* entity, const char* name, const char* address, @@ -21,15 +23,15 @@ namespace rz return OriginalGameRules->CsGameRules()->ClientConnected(entity, name, address, rejectReason); } - auto TeamPlayGameRules::ClientCommand(PlayerBase* player, const char* command) -> qboolean { + auto TeamGameRules::ClientCommand(PlayerBase* player, const char* command) -> qboolean { return OriginalGameRules->CsGameRules()->ClientCommand(player, command); } - auto TeamPlayGameRules::ClientCommandDeadOrAlive(PlayerBase* player, const char* command) -> qboolean { + auto TeamGameRules::ClientCommandDeadOrAlive(PlayerBase* player, const char* command) -> qboolean { return OriginalGameRules->CsGameRules()->ClientCommandDeadOrAlive(player, command); } - auto TeamPlayGameRules::ClientUserInfoChanged(PlayerBase* base, char* infoBuffer) -> void { + auto TeamGameRules::ClientUserInfoChanged(PlayerBase* base, char* infoBuffer) -> void { auto value = InfoKeyValue(infoBuffer, "_cl_autowepswitch"); if (str::Equals(value, "")) { base->auto_wep_switch = 1; @@ -44,7 +46,7 @@ namespace rz } } - auto TeamPlayGameRules::ClientDisconnected(Edict* client) -> void { + auto TeamGameRules::ClientDisconnected(Edict* client) -> void { OriginalGameRules->CsGameRules()->ClientDisconnected(client); /* if (client == nullptr) { CheckWinConditions(); @@ -98,7 +100,7 @@ namespace rz CheckWinConditions();/*/ } - auto TeamPlayGameRules::InitHud(PlayerBase* base) -> void { + auto TeamGameRules::InitHud(PlayerBase* base) -> void { const auto& player = Players[base]; netLightStyle(player, 0, Environment.getLight()); sendFog(player, Environment.getFog()); @@ -121,9 +123,9 @@ namespace rz SendMotdToClient(player); } Players.forEachConnected( - [&player](const auto& target) { + [&player](auto& target) { sendTeamInfo(player, target, target.getTeam()); - // target->GetCsPlayer()->SetScoreAttribute(player); // SetScoreboardAttributeSSS(player); + target.SetScoreboardAttributes(player); sendHealthInfo(player, target, target.getHealth()); sendAccount(player, target, target.getAccount()); if (player.id() != target.id() && target.isAlive()) { @@ -133,12 +135,12 @@ namespace rz ); } - auto TeamPlayGameRules::UpdateGameMode(PlayerBase* base) -> void { + auto TeamGameRules::UpdateGameMode(PlayerBase* base) -> void { const auto& player = Players[base]; sendGameMode(player, 1); } - auto TeamPlayGameRules::PlayerFallDamage(PlayerBase* player) -> float { + auto TeamGameRules::PlayerFallDamage(PlayerBase* player) -> float { if (!mp_falldamage->value) { return 0; } @@ -146,7 +148,7 @@ namespace rz return player->fall_velocity * DAMAGE_FOR_FALL_SPEED * 1.25f; } - auto TeamPlayGameRules::PlayerCanTakeDamage(PlayerBase* player, EntityBase* attacker) -> qboolean { + auto TeamGameRules::PlayerCanTakeDamage(PlayerBase* player, EntityBase* attacker) -> qboolean { if (getGameState() != GameState::Playing && getRoundState() != RoundState::Playing) { return false; } @@ -159,9 +161,9 @@ namespace rz return false; } - auto TeamPlayGameRules::PlayerThink(PlayerBase* base) -> void { + auto TeamGameRules::PlayerThink(PlayerBase* base) -> void { auto& player = Players[base]; - if (!gameRules->isCanMove()) { + if (!isCanMove()) { player.setCanShoot(false); player.setButton(0); player.setButtonPressed(0); @@ -185,7 +187,7 @@ namespace rz } } - auto TeamPlayGameRules::PlayerSpawn(PlayerBase* base) -> void { + auto TeamGameRules::PlayerSpawn(PlayerBase* base) -> void { auto& player = Players[base]; if (player.isJustConnected()) { return; @@ -197,21 +199,39 @@ namespace rz base->auto_wep_switch = autoWeaponSwitch; } - auto TeamPlayGameRules::PlayerCanRespawn(PlayerBase* base) -> qboolean { + auto TeamGameRules::PlayerCanRespawn(PlayerBase* base) -> qboolean { if (getGameState() == GameState::Over) { return false; } - if (getRoundState() == RoundState::Terminate) { + switch (getRoundState()) { + case RoundState::Playing: { + const auto modeRef = Modes[getMode()]; + if (modeRef) { + const auto& mode = modeRef->get(); + if (mode.getRespawn() == RespawnType::Off) { + return false; + } + } + break; + } + case RoundState::Terminate: { + return false; + } + default: { + break; + } + } + const auto& player = Players[base]; + if (!player.isPlayableTeam()) { return false; } - // auto& player = Players[base]; // if (player.getMenu() == MenuName::ChooseAppearance) { // return false; // } return true; } - auto TeamPlayGameRules::PlayerKilled( + auto TeamGameRules::PlayerKilled( PlayerBase* victimBase, EntityVars* killerVars, EntityVars* inflictor @@ -247,12 +267,14 @@ namespace rz } } - auto TeamPlayGameRules::PointsForKill(PlayerBase*, PlayerBase*) -> int { + auto TeamGameRules::PointsForKill(PlayerBase*, PlayerBase*) -> int { return 1; } - auto TeamPlayGameRules::DeathNotice(PlayerBase* victimBase, EntityVars* killerVars, EntityVars* inflictorVars) - -> void { + auto TeamGameRules::DeathNotice( + PlayerBase* victimBase, EntityVars* killerVars, EntityVars* inflictorVars + ) + -> void { const auto& victim = Players[victimBase]; auto killerId = 0; std::string_view weaponName{"world"}; @@ -282,7 +304,7 @@ namespace rz sendDeathMsg(TO_ALL, killerId, victim.id(), weaponName, victim.isHeadshotKilled()); } - auto TeamPlayGameRules::GetPlayerSpawnSpot(PlayerBase* base) -> Edict* { + auto TeamGameRules::GetPlayerSpawnSpot(PlayerBase* base) -> Edict* { auto& player = Players[base]; auto spawn = base->GetCsPlayer()->EntSelectSpawnPoint(); // to be removed player.setOrigin(spawn->vars.origin + Vector(0, 0, 1)); @@ -378,7 +400,10 @@ namespace rz } */ - auto TeamPlayGameRules::GetPlayerRelationship(PlayerBase* player, EntityBase* target) -> PlayerRelationship { + auto TeamGameRules::GetPlayerRelationship(PlayerBase* player, EntityBase* target) -> PlayerRelationship { + if (player == target) { + return PlayerRelationship::Teammate; + } if (!player || !target) { return PlayerRelationship::NotTeammate; } @@ -391,7 +416,7 @@ namespace rz return PlayerRelationship::Teammate; } - auto TeamPlayGameRules::InitializePlayerCounts(int& aliveTr, int& aliveCt, int& deadTr, int& deadCt) -> void { + auto TeamGameRules::InitializePlayerCounts(int& aliveTr, int& aliveCt, int& deadTr, int& deadCt) -> void { enum { DEAD, ALIVE, @@ -410,7 +435,7 @@ namespace rz deadCt = playersCount[TEAM_HUMAN][DEAD]; } - auto TeamPlayGameRules::ShouldSwitchWeapon(PlayerBase* base, PlayerItemBase* weapon) -> qboolean { + auto TeamGameRules::ShouldSwitchWeapon(PlayerBase* base, PlayerItemBase* weapon) -> qboolean { if (!weapon->CanDeploy()) { return false; } @@ -442,7 +467,7 @@ namespace rz return false; } - auto TeamPlayGameRules::GetNextBestWeapon(PlayerBase* base, PlayerItemBase* weapon) -> qboolean { + auto TeamGameRules::GetNextBestWeapon(PlayerBase* base, PlayerItemBase* weapon) -> qboolean { if (!weapon->CanHolster()) { return false; } @@ -471,7 +496,7 @@ namespace rz } // TODO cache file string - auto TeamPlayGameRules::SendMotdToClient(const Player& player) -> void { + auto TeamGameRules::SendMotdToClient(const Player& player) -> void { sendServerName(player, CvarGetString("hostname")); auto length = 0; const auto motdFile = LoadFileForMe(CvarGetString("motdfile"), &length); diff --git a/rezombie/src/items/api/items.cpp b/rezombie/src/items/api/items.cpp index 00cc175..1061802 100644 --- a/rezombie/src/items/api/items.cpp +++ b/rezombie/src/items/api/items.cpp @@ -2,7 +2,6 @@ #include "rezombie/items/modules/item.h" #include "rezombie/player/players.h" #include "rezombie/core/api/amxx_helper.h" -#include namespace rz { @@ -127,11 +126,15 @@ namespace rz return HandleItemVar(amx, params, false); } - auto item_begin(Amx*, cell*) -> cell { + auto items_count(Amx*, cell*) -> cell { + return Items.count(); + } + + auto items_begin(Amx*, cell*) -> cell { return Items.begin(); } - auto item_end(Amx*, cell*) -> cell { + auto items_end(Amx*, cell*) -> cell { return Items.end(); } @@ -182,35 +185,18 @@ namespace rz return item.executeGive(player, itemId); } - auto register_translate(Amx* amx, cell* params) -> cell { - enum { - arg_count, - arg_lang_file, - }; - - const auto langFile = GetAmxString(amx, params[arg_lang_file]); - const auto filePath = str::Format("rezombie/translates/%s.txt", langFile); - std::filesystem::path path{str::BuildPathName(filePath)}; - if (!std::filesystem::exists(path)) { - return false; - } - MergeDefinitionFile(path.string().c_str()); - return true; - } - auto AmxxItem::registerNatives() const -> void { static AmxNativeInfo natives[] = { {"create_item", create_item}, {"get_item_var", get_item_var}, {"set_item_var", set_item_var}, - {"item_begin", item_begin}, - {"item_end", item_end}, + {"items_count", items_count}, + {"items_begin", items_begin}, + {"items_end", items_end}, {"find_item", find_item}, {"give_item", give_item}, {"give_item_by_id", give_item_by_id}, - {"register_translate", register_translate}, - {nullptr, nullptr}, }; AddNatives(natives); diff --git a/rezombie/src/main/api/main.cpp b/rezombie/src/main/api/main.cpp new file mode 100644 index 0000000..2bacfda --- /dev/null +++ b/rezombie/src/main/api/main.cpp @@ -0,0 +1,148 @@ +#include "rezombie/main/main.h" +#include "rezombie/main/api/main.h" +#include "rezombie/entity/extras.h" +#include "rezombie/colors/colors.h" +#include "rezombie/core/api/amxx_helper.h" +#include +#include +#include +#include + +namespace rz +{ + using namespace amx; + using namespace amxx; + using namespace core; + + auto register_translate(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_lang_file, + }; + + const auto langFile = GetAmxString(amx, params[arg_lang_file]); + const auto filePath = str::Format("rezombie/translates/%s.txt", langFile); + const std::filesystem::path path = str::BuildPathName(filePath); + if (!exists(path)) { + return false; + } + MergeDefinitionFile(path.string().c_str()); + return true; + } + + auto is_extra_exists(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_type, + arg_key, + }; + + const auto type = static_cast(params[arg_type]); + const auto key = GetAmxString(amx, params[arg_key]); + return GlobalExtras.isKeyExists(type, key); + } + + auto HandleExtra(Amx* amx, cell* params, bool isGetter) -> cell { + enum { + arg_count, + arg_type, + arg_key, + arg_3, + arg_4, + }; + + const auto type = static_cast(params[arg_type]); + const auto* key = GetAmxString(amx, params[arg_key], 0); + switch (type) { + case ExtraType::Int: { + auto& extra = GlobalExtras.getInts(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid global extra '%s' var (int)", key) + return extra[key]; + } else { + extra[key] = *Address(amx, params[arg_3]); + } + break; + } + case ExtraType::Float: { + auto& extra = GlobalExtras.getFloats(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid global extra '%s' var (float)", key) + return FloatToCell(extra[key]); + } else { + extra[key] = CellToFloat(*Address(amx, params[arg_3])); + } + break; + } + case ExtraType::String: { + auto& extra = GlobalExtras.getStrings(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid global extra '%s' var (string)", key) + SetAmxString(amx, params[arg_3], extra[key].c_str(), *Address(amx, params[arg_4])); + } else { + extra[key] = GetAmxString(amx, params[arg_3], 1); + } + break; + } + } + return true; + } + + auto get_extra(Amx* amx, cell* params) -> cell { + return HandleExtra(amx, params, true); + } + + auto set_extra(Amx* amx, cell* params) -> cell { + return HandleExtra(amx, params, false); + } + + //native set_entity_render(entity, mode = kRenderNormal, amount = 0, const color[] = "", fx = kRenderFxNone) + + auto set_entity_render(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_entity, + arg_mode, + arg_amount, + arg_color, + arg_fx, + }; + + using namespace type_conversion; + + const auto color = GetAmxString(amx, params[arg_color]); + const auto colorRef = Colors.parse(color); + if (!colorRef) { + return false; + } + const auto colors = *colorRef; + const int entityIndex = params[arg_entity]; + const auto mode = static_cast(params[arg_mode]); + const int amount = params[arg_amount]; + const auto fx = static_cast(params[arg_fx]); + const auto& entityEdict = EdictByIndex(entityIndex); + const auto& vars = &entityEdict->vars; + vars->render_mode = mode; + vars->render_amount = static_cast(amount); + vars->render_color = Vector(colors.getRed(), colors.getGreen(), colors.getBlue()); + vars->render_fx = fx; + return true; + } + + auto AmxxMain::registerNatives() const -> void { + static AmxNativeInfo natives[] = { + {"register_translate", register_translate}, + {"is_extra_exists", is_extra_exists}, + {"get_extra", get_extra}, + {"set_extra", set_extra}, + + {"set_entity_render", set_entity_render}, + + {nullptr, nullptr}, + }; + AddNatives(natives); + } +} diff --git a/rezombie/src/main/gamedll_hooks.cpp b/rezombie/src/main/gamedll_hooks.cpp index 09cf727..a670093 100644 --- a/rezombie/src/main/gamedll_hooks.cpp +++ b/rezombie/src/main/gamedll_hooks.cpp @@ -1,14 +1,15 @@ #include "rezombie/gamerules/game_rules.h" #include "rezombie/weapons/modules/weapon.h" #include "rezombie/player/players.h" -#include "rezombie/player/world_preview.h" -#include "rezombie/player/modules/nightvision.h" +#include "rezombie/preview/world_preview.h" #include "rezombie/map/environment.h" #include "rezombie/map/map_spawns.h" +#include "rezombie/map/extras.h" #include "rezombie/map/modules/map_cameras.h" -#include "rezombie/modelpreview/model_preview.h" +#include "rezombie/preview/join_preview.h" #include "rezombie/thirdcamera/third_camera.h" #include "rezombie/main/gamedll_hooks.h" +#include "rezombie/configs/main_config.h" #include "rezombie/messages/user_message.h" #include #include @@ -30,21 +31,11 @@ namespace rz MHookGameDllGetWeaponData(DELEGATE_ARG, true); } -/* - const std::unordered_map USELESS_ENTITIES = { - {"armoury_entity", 0}, - {"hostage_entity", 0}, - }; -*/ auto Spawn_Pre(const GameDllDispatchSpawnMChain& chain, Edict* entity) -> int { - if (entity->vars.class_name == "armoury_entity") { - RETURN_META_VALUE(Result::Supercede, -1); - } - if (entity->vars.class_name == "weaponbox") { - RETURN_META_VALUE(Result::Supercede, -1); - } - if (entity->vars.class_name == "hostage_entity") { - RETURN_META_VALUE(Result::Supercede, -1); + for (auto &className : MainConfig.getUselessEntities()) { + if (entity->vars.class_name == className.c_str()) { + RETURN_META_VALUE(Result::Supercede, -1); + } } return chain.CallNext(entity); } @@ -71,7 +62,7 @@ namespace rz ) -> void { IsServerActive = true; Environment.precache(); - gameRules->precache(); + GameRules.precache(); initUserMessagesIds(); VirtualHook::RegisterHooks(); Modules.precache(); @@ -79,6 +70,7 @@ namespace rz MapCameras.collect(); MapCameras.createEntity(); ModelPreview.createEntities(); + WorldPreview.createEntity(); ThirdCamera.createEntity(); } @@ -89,6 +81,7 @@ namespace rz IsServerActive = false; VirtualHook::UnregisterHooks(); Modules.clear(); + MapExtras.reset(); } auto AddToFullPack_Pre( @@ -102,27 +95,33 @@ namespace rz unsigned char* set ) -> qboolean { auto& host = Players[hostEntity]; - auto& thirdCamera = host.getThirdCameraVars(); + const auto& thirdCamera = host.getThirdCameraVars(); if (!thirdCamera.isEnabled()) { if (entity == ThirdCamera.getCamera()) { RETURN_META_VALUE(Result::Supercede, false); } } - auto& camera = host.getMapCameraVars(); + const auto& camera = host.getMapCameraVars(); if (!camera.isEnabled()) { if (entity == MapCameras.getCamera()) { RETURN_META_VALUE(Result::Supercede, false); } } - auto& preview = host.getPreviewVars(); - if (!preview.isEnabled()) { - if (entity == ModelPreview[PreviewType::ParentModel] || - entity == ModelPreview[PreviewType::AttachModel] || - entity == ModelPreview[PreviewType::ExtraAttachModel] + const auto& joinPreview = host.getJoinPreviewVars(); + if (!joinPreview.isEnabled()) { + if (entity == ModelPreview[JoinPreviewType::ParentModel] || + entity == ModelPreview[JoinPreviewType::AttachModel] || + entity == ModelPreview[JoinPreviewType::ExtraAttachModel] ) { RETURN_META_VALUE(Result::Supercede, false); } } + const auto& worldPreview = host.getWorldPreviewVars(); + if (!worldPreview.isEnabled()) { + if (entity == WorldPreview.getEntity()) { + RETURN_META_VALUE(Result::Supercede, false); + } + } return chain.CallNext(state, entityId, entity, hostEntity, hostFlags, isPlayer, set); } @@ -139,21 +138,21 @@ namespace rz //metamod::utils::LogConsole("host %d ent %d %s", IndexOfEdict(hostEntity), IndexOfEdict(entity), entity->vars.class_name.CStr()); auto& host = Players[hostEntity]; if (hostEntity == entity) { - if (host.getFlashlight().isEnabled()) { + if (host.Flashlight().isEnabled() && !host.Flashlight().getNextDynamicUpdate()) { state->effects |= EF_DIM_LIGHT; } - if (host.getNightVision().isEnabled()) { + if (host.NightVision().isEnabled()) { state->effects |= EF_BRIGHT_LIGHT; } } - auto& thirdCamera = host.getThirdCameraVars(); + const auto& thirdCamera = host.getThirdCameraVars(); if (thirdCamera.isEnabled()) { if (entity == ThirdCamera.getCamera()) { state->origin = thirdCamera.getOrigin(); state->angles = thirdCamera.getAngles(); } } - auto& mapCamera = host.getMapCameraVars(); + const auto& mapCamera = host.getMapCameraVars(); if (mapCamera.isEnabled()) { if (entity == MapCameras.getCamera()) { const auto& cameraRef = MapCameras[mapCamera.getCamera()]; @@ -164,20 +163,20 @@ namespace rz } } } - auto& preview = host.getPreviewVars(); - if (preview.isEnabled()) { - if (entity == ModelPreview[PreviewType::ParentModel]) { - state->origin = preview.getOrigin(); - state->angles = preview.getAngles(); + const auto& joinPreview = host.getJoinPreviewVars(); + if (joinPreview.isEnabled()) { + if (entity == ModelPreview[JoinPreviewType::ParentModel]) { + state->origin = joinPreview.getOrigin(); + state->angles = joinPreview.getAngles(); state->velocity = host.getVelocity(); - setModel(state, preview.getModel(PreviewType::ParentModel)); - } else if (entity == ModelPreview[PreviewType::AttachModel]) { - setModel(state, preview.getModel(PreviewType::AttachModel)); - } else if (entity == ModelPreview[PreviewType::ExtraAttachModel]) { - setModel(state, preview.getModel(PreviewType::ExtraAttachModel)); + setModel(state, joinPreview.getModel(JoinPreviewType::ParentModel)); + } else if (entity == ModelPreview[JoinPreviewType::AttachModel]) { + setModel(state, joinPreview.getModel(JoinPreviewType::AttachModel)); + } else if (entity == ModelPreview[JoinPreviewType::ExtraAttachModel]) { + setModel(state, joinPreview.getModel(JoinPreviewType::ExtraAttachModel)); } } - auto& worldPreview = host.getWorldPreviewVars(); + const auto& worldPreview = host.getWorldPreviewVars(); if (worldPreview.isEnabled()) { if (entity == WorldPreview.getEntity()) { state->origin = worldPreview.getOrigin(); diff --git a/rezombie/src/main/main.cpp b/rezombie/src/main/main.cpp index 57273d2..545b084 100644 --- a/rezombie/src/main/main.cpp +++ b/rezombie/src/main/main.cpp @@ -1,10 +1,10 @@ #include "rezombie/core/api/amxx_features_store.h" #include "rezombie/gamerules/game_rules.h" -#include "rezombie/weapons/weapons.h" #include "rezombie/main/engine_hooks.h" #include "rezombie/main/gamedll_hooks.h" #include "rezombie/main/message_hooks.h" #include "rezombie/main/main.h" +#include "rezombie/configs/main_config.h" #include #include #include @@ -18,9 +18,8 @@ namespace rz using namespace mhooks; auto OnAmxxAttach(const AmxxAttachMChain& chain) -> AmxxStatus { - auto rehldsEnabled = true; auto status = AmxxStatus::Failed; - if ((!rehldsEnabled || rehlds_api::Init()) && regamedll_api::Init()) { + if (rehlds_api::Init() && regamedll_api::Init()) { amxx_access::Init(); type_conversion::Init(); status = chain.CallNext(); @@ -29,14 +28,13 @@ namespace rz return status; } MHookAmxxPluginsLoaded(DELEGATE_ARG); - if (rehldsEnabled) { - RegisterEngineHooks(); - } + RegisterEngineHooks(); RegisterGameDllHooks(); RegisterGameRulesHooks(); RegisterMessageHooks(); RegisterPlayerHooks(); ApiStore.registerNatives(); + MainConfig.load(); return status; } diff --git a/rezombie/src/main/message_hooks.cpp b/rezombie/src/main/message_hooks.cpp index aa89dfc..7fb5cc2 100644 --- a/rezombie/src/main/message_hooks.cpp +++ b/rezombie/src/main/message_hooks.cpp @@ -8,6 +8,7 @@ namespace rz auto RegisterMessageHooks() -> void { MHookNetworkMessage("HideWeapon", DELEGATE_ARG); + MHookNetworkMessage("ScreenFade", DELEGATE_ARG); } auto MessageHideWeapon( @@ -23,4 +24,15 @@ namespace rz sendHideWeapon(client, args.GetInteger(0) | HIDE_HUD_TIMER); return true; } + + auto MessageScreenFade( + const NetworkMessageMChain&, + const MessageType&, + int, + const float*, + Edict*, + MessageArgs& + ) -> bool { + return true; + } } diff --git a/rezombie/src/map/api/extras.cpp b/rezombie/src/map/api/extras.cpp new file mode 100644 index 0000000..4a1b9e7 --- /dev/null +++ b/rezombie/src/map/api/extras.cpp @@ -0,0 +1,90 @@ +#include "rezombie/map/extras.h" +#include "rezombie/map/api/extras.h" +#include +#include "rezombie/core/api/amxx_helper.h" +#include + +namespace rz +{ + using namespace amx; + + auto is_map_extra_exists(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_type, + arg_key, + }; + + const auto type = static_cast(params[arg_type]); + const auto key = GetAmxString(amx, params[arg_key]); + return MapExtras.isKeyExists(type, key); + } + + auto HandleMapExtra(Amx* amx, cell* params, bool isGetter) -> cell { + enum { + arg_count, + arg_type, + arg_key, + arg_3, + arg_4, + }; + + const auto type = static_cast(params[arg_type]); + const auto* key = GetAmxString(amx, params[arg_key], 0); + switch (type) { + case ExtraType::Int: { + auto& extra = MapExtras.getInts(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid map extra '%s' var (int)", key) + return extra[key]; + } else { + extra[key] = *Address(amx, params[arg_3]); + } + break; + } + case ExtraType::Float: { + auto& extra = MapExtras.getFloats(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid map extra '%s' var (float)", key) + return FloatToCell(extra[key]); + } else { + extra[key] = CellToFloat(*Address(amx, params[arg_3])); + } + break; + } + case ExtraType::String: { + auto& extra = MapExtras.getStrings(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid map extra '%s' var (string)", key) + SetAmxString(amx, params[arg_3], extra[key].c_str(), *Address(amx, params[arg_4])); + } else { + extra[key] = GetAmxString(amx, params[arg_3], 1); + } + break; + } + } + return true; + } + + auto get_map_extra(Amx* amx, cell* params) -> cell { + return HandleMapExtra(amx, params, true); + } + + auto set_map_extra(Amx* amx, cell* params) -> cell { + return HandleMapExtra(amx, params, false); + } + + auto AmxxMapExtras::registerNatives() const -> void { + static AmxNativeInfo natives[] = { + {"is_map_extra_exists", is_map_extra_exists}, + {"get_map_extra", get_map_extra}, + {"set_map_extra", set_map_extra}, + + {nullptr, nullptr}, + }; + AddNatives(natives); + } +} diff --git a/rezombie/src/map/api/map_cameras.cpp b/rezombie/src/map/api/map_cameras.cpp index d2d5235..14712d8 100644 --- a/rezombie/src/map/api/map_cameras.cpp +++ b/rezombie/src/map/api/map_cameras.cpp @@ -66,11 +66,15 @@ namespace rz return HandleMapCamerasVar(amx, params, false); } - auto map_camera_begin(Amx*, cell*) -> cell { + auto map_cameras_count(Amx*, cell*) -> cell { + return MapCameras.count(); + } + + auto map_cameras_begin(Amx*, cell*) -> cell { return MapCameras.begin(); } - auto map_camera_end(Amx*, cell*) -> cell { + auto map_cameras_end(Amx*, cell*) -> cell { return MapCameras.end(); } @@ -78,8 +82,9 @@ namespace rz static AmxNativeInfo natives[] = { {"get_map_camera_var", get_map_camera_var}, {"set_map_camera_var", set_map_camera_var}, - {"map_camera_begin", map_camera_begin}, - {"map_camera_end", map_camera_end}, + {"map_cameras_count", map_cameras_count}, + {"map_cameras_begin", map_cameras_begin}, + {"map_cameras_end", map_cameras_end}, {nullptr, nullptr}, }; diff --git a/rezombie/src/messages/api/engine_message.cpp b/rezombie/src/messages/api/engine_message.cpp new file mode 100644 index 0000000..62636da --- /dev/null +++ b/rezombie/src/messages/api/engine_message.cpp @@ -0,0 +1,42 @@ +#include "rezombie/messages/api/engine_message.h" +#include "rezombie/messages/temporary_entity.h" +#include + +namespace rz +{ + using namespace amx; + using namespace amxx; + + auto message_beam_follow(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_entity, + arg_sprite_index, + arg_life, + arg_line_width, + arg_color, + }; + + // Check arg count + const auto entity = params[arg_entity]; + const auto spriteIndex = params[arg_sprite_index]; + const byte life = params[arg_life]; + const byte lineWidth = params[arg_line_width]; + const auto color = GetAmxString(amx, params[arg_color]); + const auto colorRef = Colors.parse(color); + if (!colorRef) { + return false; + } + TE_BeamFollow(entity, spriteIndex, life, lineWidth, *colorRef); + return true; + } + + auto AmxxEngineMessage::registerNatives() const -> void { + static AmxNativeInfo natives[] = { + {"message_beam_follow", message_beam_follow}, + + {nullptr, nullptr}, + }; + AddNatives(natives); + } +} diff --git a/rezombie/src/messages/api/user_message.cpp b/rezombie/src/messages/api/user_message.cpp index 1773632..16ef172 100644 --- a/rezombie/src/messages/api/user_message.cpp +++ b/rezombie/src/messages/api/user_message.cpp @@ -46,7 +46,7 @@ namespace rz const auto target = params[arg_target]; const auto attribFlags = params[arg_attrib_flags]; if (receiver) { - auto& player = Players[receiver]; + const auto& player = Players[receiver]; sendScoreAttrib(player, target, attribFlags); } else { sendScoreAttrib(TO_ALL, target, attribFlags); @@ -54,6 +54,25 @@ namespace rz return true; } + auto send_item_pickup(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_receiver, + arg_class_name, + }; + + // Check arg count + const auto receiver = params[arg_receiver]; + const auto className = GetAmxString(amx, params[arg_class_name], 0); + if (receiver) { + const auto& player = Players[receiver]; + sendItemPickup(player, className); + } else { + sendItemPickup(TO_ALL, className); + } + return true; + } + auto send_money(Amx* amx, cell* params) -> cell { enum { arg_count, @@ -68,7 +87,7 @@ namespace rz const auto amount = params[arg_amount]; const auto isTrackChange = params[arg_track_change]; if (receiver) { - auto& player = Players[receiver]; + const auto& player = Players[receiver]; sendMoney(player, amount, isTrackChange); } else { sendMoney(TO_ALL, amount, isTrackChange); @@ -91,7 +110,7 @@ namespace rz const auto sprite = GetAmxString(amx, params[arg_sprite], 0); const auto color = GetAmxString(amx, params[arg_color], 1); if (receiver) { - auto& player = Players[receiver]; + const auto& player = Players[receiver]; sendStatusIcon(player, status, sprite, color); } else { sendStatusIcon(TO_ALL, status, sprite, color); @@ -103,6 +122,7 @@ namespace rz static AmxNativeInfo natives[] = { {"send_death_msg", send_death_msg}, {"send_score_attrib", send_score_attrib}, + {"send_item_pickup", send_item_pickup}, {"send_money", send_money}, {"send_status_icon", send_status_icon}, diff --git a/rezombie/src/modelpreview/model_preview.cpp b/rezombie/src/modelpreview/model_preview.cpp deleted file mode 100644 index 31c2607..0000000 --- a/rezombie/src/modelpreview/model_preview.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "rezombie/modelpreview/model_preview.h" -#include -#include - -namespace rz -{ - using namespace cssdk; - using namespace metamod::engine; - - auto ModelPreview::createEntities() -> void { - auto entityClassName = AllocString("info_target"); - EntityVars* vars; - - setEntity(PreviewType::ParentModel, UTIL_CreateNamedEntity(entityClassName)); - vars = &getEntity(PreviewType::ParentModel)->vars; - vars->class_name = AllocString("preview_parent"); - vars->model_index = -1; - vars->effects = EF_BRIGHT_LIGHT; - - setEntity(PreviewType::AttachModel, UTIL_CreateNamedEntity(entityClassName)); - vars = &getEntity(PreviewType::AttachModel)->vars; - vars->class_name = AllocString("preview_attach"); - vars->model_index = -1; - vars->move_type = MoveTypeEntity::Follow; - vars->aim_entity = getEntity(PreviewType::ParentModel); - - setEntity(PreviewType::ExtraAttachModel, UTIL_CreateNamedEntity(entityClassName)); - vars = &getEntity(PreviewType::ExtraAttachModel)->vars; - vars->class_name = AllocString("preview_extra_attach"); - vars->model_index = -1; - vars->move_type = MoveTypeEntity::Follow; - vars->aim_entity = getEntity(PreviewType::ParentModel); - } -} diff --git a/rezombie/src/modelpreview/world_preview.cpp b/rezombie/src/modelpreview/world_preview.cpp deleted file mode 100644 index 3481288..0000000 --- a/rezombie/src/modelpreview/world_preview.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "rezombie/player/world_preview.h" -#include - -namespace rz -{ - using namespace cssdk; - using namespace metamod::engine; - - auto WorldPreview::createEntity() -> void { - auto entityClassName = AllocString("info_target"); - EntityVars* vars; - - setEntity(UTIL_CreateNamedEntity(entityClassName)); - vars = &getEntity()->vars; - vars->class_name = AllocString("world_preview"); - vars->model_index = -1; - } -} diff --git a/rezombie/src/modes/api/modes.cpp b/rezombie/src/modes/api/modes.cpp new file mode 100644 index 0000000..2df0873 --- /dev/null +++ b/rezombie/src/modes/api/modes.cpp @@ -0,0 +1,296 @@ +#include "rezombie/modes/api/modes.h" +#include "rezombie/modes/modules/modes.h" +#include "rezombie/main/util.h" +#include "rezombie/core/api/amxx_helper.h" +#include + +#include "rezombie/gamerules/game_rules.h" + +namespace rz +{ + using namespace amx; + using namespace amxx; + + auto AmxxModes::ModeStart(int modeId, int target) const -> void { + executeForward(ModesForward::ModeStart, modeId, target); + } + + auto AmxxModes::registerForwards() -> void { + using e = ForwardExecType; + using p = ForwardParam; + + setForward( + ModesForward::ModeStart, + RegisterForward("@mode_start", e::Ignore, p::Cell, p::Cell, p::Done) + ); + } + + enum class ModeVars : int { + Handle, + Name, + Description, + NoticeMessage, + Color, + DropChance, + MinimumPlayers, + RoundTime, + IsSupportTarget, + Respawn, + }; + + const std::unordered_map ModeVarsMap = { + {"handle", ModeVars::Handle}, + {"name", ModeVars::Name}, + {"description", ModeVars::Description}, + {"notice_message", ModeVars::NoticeMessage}, + {"color", ModeVars::Color}, + {"drop_chance", ModeVars::DropChance}, + {"minimum_players", ModeVars::MinimumPlayers}, + {"round_time", ModeVars::RoundTime}, + {"support_target", ModeVars::IsSupportTarget}, + {"respawn", ModeVars::Respawn}, + }; + + auto create_mode(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_handle, + arg_launch_forward, + arg_is_support_target, + }; + + using p = ForwardParam; + + // Check arg count + auto handle = GetAmxString(amx, params[arg_handle], 0); + const auto launchForward = RegisterSpForwardByName( + amx, GetAmxString(amx, params[arg_launch_forward], 1), + p::Cell, p::Done + ); + if (launchForward == FORWARD_INVALID) { + return 0; + } + const bool isSupportTarget = params[arg_is_support_target]; + const auto modeId = Modes.add(handle, launchForward, isSupportTarget); + return modeId; + } + + auto HandleModeVar(Amx* amx, cell* params, bool isGetter) -> cell { + enum { + arg_count, + arg_mode, + arg_var, + arg_3, + arg_4, + }; + + using vars = ModeVars; + + const int modeId = params[arg_mode]; + const auto modeRef = Modes[modeId]; + if (!modeRef) { + // Invalid index + return false; + } + const auto key = GetAmxString(amx, params[arg_var]); + const auto& var = getMapValue(ModeVarsMap, key); + CHECK_VAR_EXISTS("Invalid mode '%s' var", key) + auto& mode = modeRef->get(); + switch (*var) { + case vars::Handle: { + if (isGetter) { + SetAmxString(amx, params[arg_3], mode.getHandle().c_str(), params[arg_4]); + } else { + // Invalid set vars + } + break; + } + case vars::Name: { + if (isGetter) { + SetAmxString(amx, params[arg_3], mode.getName().c_str(), *Address(amx, params[arg_4])); + } else { + mode.setName(GetAmxString(amx, params[arg_3])); + } + break; + } + case vars::Description: { + if (isGetter) { + SetAmxString(amx, params[arg_3], mode.getDescription().c_str(), *Address(amx, params[arg_4])); + } else { + mode.setDescription(GetAmxString(amx, params[arg_3])); + } + break; + } + case vars::NoticeMessage: { + if (isGetter) { + SetAmxString(amx, params[arg_3], mode.getNoticeMessage().c_str(), *Address(amx, params[arg_4])); + } else { + mode.setNoticeMessage(GetAmxString(amx, params[arg_3])); + } + break; + } + case vars::Color: { + if (isGetter) { + SetAmxString(amx, params[arg_3], mode.getColor().c_str(), *Address(amx, params[arg_4])); + } else { + mode.setColor(GetAmxString(amx, params[arg_3])); + } + break; + } + case vars::DropChance: { + if (isGetter) { + return mode.getDropChance(); + } else { + mode.setDropChance(*Address(amx, params[arg_3])); + } + break; + } + case vars::MinimumPlayers: { + if (isGetter) { + return mode.getMinPlayers(); + } else { + mode.setMinPlayers(*Address(amx, params[arg_3])); + } + break; + } + case vars::RoundTime: { + if (isGetter) { + return mode.getRoundTime(); + } else { + mode.setRoundTime(*Address(amx, params[arg_3])); + } + break; + } + case vars::IsSupportTarget: { + if (isGetter) { + return mode.isSupportTarget(); + } else { + mode.setSupportTarget(*Address(amx, params[arg_3])); + } + break; + } + case vars::Respawn: { + if (isGetter) { + return toInt(mode.getRespawn()); + } else { + mode.setRespawn(static_cast(*Address(amx, params[arg_3]))); + } + break; + } + } + return true; + } + + auto get_mode_var(Amx* amx, cell* params) -> cell { + return HandleModeVar(amx, params, true); + } + + auto set_mode_var(Amx* amx, cell* params) -> cell { + return HandleModeVar(amx, params, false); + } + + auto mode_add_ambience_sound(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_mode, + arg_path, + }; + + const int modeId = params[arg_mode]; + const auto& modeRef = Modes[modeId]; + if (!modeRef) { + // Invalid index + return false; + } + auto& mode = modeRef->get(); + const auto path = GetAmxString(amx, params[arg_path]); + mode.addAmbienceSound(path); + return true; + } + + auto mode_random_ambience_sound(Amx* amx, cell* params) -> cell { + constexpr auto PLATFORM_MAX_PATH = 256; + + enum { + arg_count, + arg_mode, + arg_return, + }; + + const int modeId = params[arg_mode]; + const auto& modeRef = Modes[modeId]; + if (!modeRef) { + // Invalid index + return false; + } + const auto& mode = modeRef->get(); + const auto& path = mode.getRandomAmbienceSound(); + SetAmxStringUtf8Char(amx, params[arg_return], path.c_str(), path.length(), PLATFORM_MAX_PATH); + return true; + } + + auto modes_count(Amx*, cell*) -> cell { + return Modes.count(); + } + + auto modes_begin(Amx*, cell*) -> cell { + return Modes.begin(); + } + + auto modes_end(Amx*, cell*) -> cell { + return Modes.end(); + } + + auto find_mode(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_handle, + }; + + const auto handle = GetAmxString(amx, params[arg_handle]); + return Modes[handle]; + } + + auto launch_mode(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_mode, + arg_target, + }; + + const int modeId = params[arg_mode]; + const int target = params[arg_target]; + const auto modeRef = Modes[modeId]; + if (modeRef) { + //setMode(modeId); + const auto& mode = modeRef->get(); + /*if (mode.getRoundTime()) { + setTimer(mode.getRoundTime()); + } else { + setTimer(round_time); + }*/ + const auto target2 = mode.executeLaunch(target); + ModesApi.ModeStart(modeId, target2); + GameRules.setRoundState(RoundState::Playing); + } + return true; + } + + auto AmxxModes::registerNatives() const -> void { + static AmxNativeInfo natives[] = { + {"create_mode", create_mode}, + {"get_mode_var", get_mode_var}, + {"set_mode_var", set_mode_var}, + {"mode_add_ambience_sound", mode_add_ambience_sound}, + {"mode_random_ambience_sound", mode_random_ambience_sound}, + {"modes_count", modes_count}, + {"modes_begin", modes_begin}, + {"modes_end", modes_end}, + {"find_mode", find_mode}, + {"launch_mode", launch_mode}, + + {nullptr, nullptr}, + }; + AddNatives(natives); + } +} diff --git a/rezombie/src/player/api/jumps.cpp b/rezombie/src/player/api/jumps.cpp new file mode 100644 index 0000000..1dcbdad --- /dev/null +++ b/rezombie/src/player/api/jumps.cpp @@ -0,0 +1,89 @@ +#include "rezombie/player/api/jumps.h" +#include "rezombie/player/player.h" +#include "rezombie/player/players.h" +#include "rezombie/core/api/amxx_helper.h" + +namespace rz +{ + using namespace amxx; + + auto AmxxJumps::Jump(int player, int count) const -> void { + executeForward(JumpsForward::Jump, player, count); + } + + auto AmxxJumps::registerForwards() -> void { + using e = ForwardExecType; + using p = ForwardParam; + + setForward( + JumpsForward::Jump, + RegisterForward("@player_jump", e::Ignore, p::Cell, p::Cell, p::Done) + ); + } + + enum class RzJumpsVars { + Count, + Maximum, + }; + + const std::unordered_map JumpsVarsMap = { + {"count", RzJumpsVars::Count}, + {"maximum", RzJumpsVars::Maximum}, + }; + + auto HandleJumpsVar(Amx* amx, cell* params, bool isGetter) -> cell { + enum { + arg_count, + arg_player, + arg_var, + arg_3, + }; + + using vars = RzJumpsVars; + + const int playerId = params[arg_player]; + CHECK_PLAYER(playerId) + auto& player = Players[playerId]; + const auto key = GetAmxString(amx, params[arg_var]); + const auto& var = getMapValue(JumpsVarsMap, key); + CHECK_VAR_EXISTS("Invalid jumps '%s' var", key) + auto& jumps = player.Jumps(); + switch (*var) { + case vars::Count: { + if (isGetter) { + return jumps.getCount(); + } else { + jumps.setCount(player, *Address(amx, params[arg_3])); + } + break; + } + case vars::Maximum: { + if (isGetter) { + return jumps.getMaximum(); + } else { + jumps.setMaximum(*Address(amx, params[arg_3])); + } + break; + } + } + return true; + } + + auto get_jumps_var(Amx* amx, cell* params) -> cell { + return HandleJumpsVar(amx, params, true); + } + + auto set_jumps_var(Amx* amx, cell* params) -> cell { + return HandleJumpsVar(amx, params, false); + } + + auto AmxxJumps::registerNatives() const -> void { + static AmxNativeInfo natives[] = { + {"get_jumps_var", get_jumps_var}, + {"set_jumps_var", set_jumps_var}, + + {nullptr, nullptr}, + }; + AddNatives(natives); + } +} diff --git a/rezombie/src/player/api/long_jump.cpp b/rezombie/src/player/api/long_jump.cpp new file mode 100644 index 0000000..d88aef0 --- /dev/null +++ b/rezombie/src/player/api/long_jump.cpp @@ -0,0 +1,186 @@ +#include "rezombie/player/api/long_jump.h" +#include "rezombie/player/player.h" +#include "rezombie/player/players.h" +#include "rezombie/core/api/amxx_helper.h" + +namespace rz +{ + using namespace amxx; + + auto AmxxLongJump::Give(int player) const -> void { + executeForward(LongJumpForward::Give, player); + } + + auto AmxxLongJump::State(int player, int longJumpState) const -> void { + executeForward(LongJumpForward::State, player, longJumpState); + } + + auto AmxxLongJump::Activated(int player) const -> void { + executeForward(LongJumpForward::Activated, player); + } + + auto AmxxLongJump::CooldownTimer(int player, int timer) const -> void { + executeForward(LongJumpForward::CooldownTimer, player, timer); + } + + auto AmxxLongJump::registerForwards() -> void { + using e = ForwardExecType; + using p = ForwardParam; + + setForward( + LongJumpForward::Give, + RegisterForward("@give_long_jump", e::Ignore, p::Cell, p::Done) + ); + setForward( + LongJumpForward::State, + RegisterForward("@long_jump_state", e::Ignore, p::Cell, p::Cell, p::Done) + ); + setForward( + LongJumpForward::Activated, + RegisterForward("@long_jump_activated", e::Ignore, p::Cell, p::Done) + ); + setForward( + LongJumpForward::CooldownTimer, + RegisterForward("@long_jump_cooldown_timer", e::Ignore, p::Cell, p::Cell, p::Done) + ); + } + + enum class RzLongJumpVars { + State, + NextStateTime, + Force, + Height, + Cooldown, + CooldownTimer, + }; + + const std::unordered_map LongJumpVarsMap = { + {"state", RzLongJumpVars::State}, + {"next_state_time", RzLongJumpVars::NextStateTime}, + {"force", RzLongJumpVars::Force}, + {"height", RzLongJumpVars::Height}, + {"cooldown", RzLongJumpVars::Cooldown}, + {"cooldown_timer", RzLongJumpVars::CooldownTimer}, + }; + + auto HandleLongJumpVar(Amx* amx, cell* params, bool isGetter) -> cell { + enum { + arg_count, + arg_player, + arg_var, + arg_3, + }; + + using vars = RzLongJumpVars; + + const int playerId = params[arg_player]; + CHECK_PLAYER(playerId) + auto& player = Players[playerId]; + const auto key = GetAmxString(amx, params[arg_var]); + const auto& var = getMapValue(LongJumpVarsMap, key); + CHECK_VAR_EXISTS("Invalid long jump '%s' var", key) + auto& longJump = player.LongJump(); + switch (*var) { + case vars::State: { + if (isGetter) { + return toInt(longJump.getState()); + } else { + longJump.setState(player, static_cast(*Address(amx, params[arg_3]))); + } + break; + } + case vars::NextStateTime: { + if (isGetter) { + return FloatToCell(longJump.getNextStateTime()); + } else { + longJump.setNextStateTime(CellToFloat(*Address(amx, params[arg_3]))); + } + break; + } + case vars::Force: { + if (isGetter) { + return longJump.getForce(); + } else { + longJump.setForce(*Address(amx, params[arg_3])); + } + break; + } + case vars::Height: { + if (isGetter) { + return longJump.getHeight(); + } else { + longJump.setHeight(*Address(amx, params[arg_3])); + } + break; + } + case vars::Cooldown: { + if (isGetter) { + return longJump.getCooldown(); + } else { + longJump.setCooldown(*Address(amx, params[arg_3])); + } + break; + } + case vars::CooldownTimer: { + if (isGetter) { + return longJump.getCooldownTimer(); + } else { + longJump.setCooldownTimer(*Address(amx, params[arg_3])); + } + break; + } + } + return true; + } + + auto get_long_jump_var(Amx* amx, cell* params) -> cell { + return HandleLongJumpVar(amx, params, true); + } + + auto set_long_jump_var(Amx* amx, cell* params) -> cell { + return HandleLongJumpVar(amx, params, false); + } + + auto give_long_jump(Amx*, cell* params) -> cell { + enum { + arg_count, + arg_player, + arg_force, + arg_height, + arg_cooldown, + }; + + const int playerId = params[arg_player]; + const int force = params[arg_force]; + const int height = params[arg_height]; + const int cooldown = params[arg_cooldown]; + auto& player = Players[playerId]; + player.GiveLongJump(force, height, cooldown); + return true; + } + + auto remove_long_jump(Amx*, cell* params) -> cell { + enum { + arg_count, + arg_player, + }; + + const int playerId = params[arg_player]; + auto& player = Players[playerId]; + player.RemoveLongJump(); + return true; + } + + auto AmxxLongJump::registerNatives() const -> void { + static AmxNativeInfo natives[] = { + {"get_long_jump_var", get_long_jump_var}, + {"set_long_jump_var", set_long_jump_var}, + + {"give_long_jump", give_long_jump}, + {"remove_long_jump", remove_long_jump}, + + {nullptr, nullptr}, + }; + AddNatives(natives); + } +} diff --git a/rezombie/src/player/api/nightvision.cpp b/rezombie/src/player/api/nightvision.cpp index bde6a59..f596ad6 100644 --- a/rezombie/src/player/api/nightvision.cpp +++ b/rezombie/src/player/api/nightvision.cpp @@ -9,13 +9,11 @@ namespace rz enum class NightVisionVars : int { Color, - Alpha, Fog, }; const std::unordered_map NightVisionVarsMap = { {"color", NightVisionVars::Color}, - {"alpha", NightVisionVars::Alpha}, {"fog", NightVisionVars::Fog}, }; @@ -23,15 +21,13 @@ namespace rz enum { arg_count, arg_color, - arg_radius, arg_fog, }; // Check arg count const auto color = GetAmxString(amx, params[arg_color]); - const int radius = params[arg_radius]; const auto fogId = params[arg_fog]; - const auto nightVisionId = NightVisions.add(color, radius, fogId); + const auto nightVisionId = NightVisions.add(color, fogId); return nightVisionId; } @@ -66,15 +62,6 @@ namespace rz } break; } - case vars::Alpha: { - if (isGetter) { - return nightVision.getAlphaPercentage(); - } else { - // check 0..100 - nightVision.setAlphaPercentage(*Address(amx, params[arg_3])); - } - break; - } case vars::Fog: { if (isGetter) { return nightVision.getFog(); diff --git a/rezombie/src/player/api/player.cpp b/rezombie/src/player/api/player.cpp index 0ebc6d5..eeb8e7e 100644 --- a/rezombie/src/player/api/player.cpp +++ b/rezombie/src/player/api/player.cpp @@ -4,6 +4,7 @@ #include "rezombie/currency/modules/currency.h" #include "rezombie/messages/user_message.h" #include "rezombie/core/api/amxx_helper.h" +#include "rezombie/gamerules/game_rules.h" namespace rz { @@ -21,14 +22,6 @@ namespace rz return executeForward(PlayerForward::GiveDefaultItems, player, classId); } - auto AmxxPlayer::LongJumpState(int player, int longJumpState) const -> void { - executeForward(PlayerForward::LongJumpState, player, longJumpState); - } - - auto AmxxPlayer::LongJumpActivated(int player) const -> void { - executeForward(PlayerForward::LongJumpActivated, player); - } - auto AmxxPlayer::registerForwards() -> void { using e = ForwardExecType; using p = ForwardParam; @@ -41,14 +34,6 @@ namespace rz PlayerForward::GiveDefaultItems, RegisterForward("@player_give_default_items", e::Ignore, p::Cell, p::Cell, p::Done) ); - setForward( - PlayerForward::LongJumpState, - RegisterForward("@player_long_jump_state", e::Ignore, p::Cell, p::Cell, p::Done) - ); - setForward( - PlayerForward::LongJumpActivated, - RegisterForward("@player_long_jump_activated", e::Ignore, p::Cell, p::Done) - ); } enum class RzPlayerVars { @@ -61,23 +46,21 @@ namespace rz Currency, ActiveWeapon, Ammo, - //ExtraJumps, MapCamera, NextMapCameraTime, }; const std::unordered_map PlayerVarsMap = { - {"health", RzPlayerVars::Health}, - {"team", RzPlayerVars::Team}, - {"class", RzPlayerVars::Class}, - {"subclass", RzPlayerVars::Subclass}, - {"keep_subclass", RzPlayerVars::KeepSubclass}, - {"model", RzPlayerVars::Model}, - {"currency", RzPlayerVars::Currency}, - {"active_weapon", RzPlayerVars::ActiveWeapon}, - {"ammo", RzPlayerVars::Ammo}, - //{"extra_jumps", RzPlayerVars::ExtraJumps}, - {"map_camera", RzPlayerVars::MapCamera}, + {"health", RzPlayerVars::Health}, + {"team", RzPlayerVars::Team}, + {"class", RzPlayerVars::Class}, + {"subclass", RzPlayerVars::Subclass}, + {"keep_subclass", RzPlayerVars::KeepSubclass}, + {"model", RzPlayerVars::Model}, + {"currency", RzPlayerVars::Currency}, + {"active_weapon", RzPlayerVars::ActiveWeapon}, + {"ammo", RzPlayerVars::Ammo}, + {"map_camera", RzPlayerVars::MapCamera}, {"next_map_camera_time", RzPlayerVars::NextMapCameraTime}, }; @@ -92,14 +75,16 @@ namespace rz using vars = RzPlayerVars; - auto& player = Players[params[arg_player]]; + const int playerId = params[arg_player]; + CHECK_PLAYER(playerId) + auto& player = Players[playerId]; const auto key = GetAmxString(amx, params[arg_var]); const auto& var = getMapValue(PlayerVarsMap, key); CHECK_VAR_EXISTS("Invalid player '%s' var", key) switch (*var) { case vars::Health: { if (isGetter) { - return player.getHealth(); + return std::max(0, player.getHealth()); } else { // Invalid set var } @@ -182,14 +167,6 @@ namespace rz } break; } - /*case vars::ExtraJumps: { - if (isGetter) { - return player.getMaxExtraJumps(); - } else { - player.setMaxExtraJumps(*Address(amx, params[arg_3])); - } - break; - }*/ case vars::MapCamera: { auto& camera = player.getMapCameraVars(); if (isGetter) { @@ -220,6 +197,101 @@ namespace rz return HandlePlayerVar(amx, params, false); } + auto is_player_extra_exists(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_player, + arg_type, + arg_key, + }; + + const int playerId = params[arg_player]; + CHECK_PLAYER(playerId) + auto& player = Players[playerId]; + const auto type = static_cast(params[arg_type]); + const auto key = GetAmxString(amx, params[arg_key]); + return player.Extras().isKeyExists(type, key); + } + + auto HandlePlayerExtra(Amx* amx, cell* params, bool isGetter) -> cell { + enum { + arg_count, + arg_player, + arg_type, + arg_key, + arg_4, + arg_5, + }; + + const int playerId = params[arg_player]; + CHECK_PLAYER(playerId) + auto& player = Players[playerId]; + const auto type = static_cast(params[arg_type]); + const auto* key = GetAmxString(amx, params[arg_key], 0); + switch (type) { + case ExtraType::Int: { + auto& extra = player.Extras().getInts(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid player extra '%s' var (int)", key) + return extra[key]; + } else { + extra[key] = *Address(amx, params[arg_4]); + } + break; + } + case ExtraType::Float: { + auto& extra = player.Extras().getFloats(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid player extra '%s' var (float)", key) + return FloatToCell(extra[key]); + } else { + extra[key] = CellToFloat(*Address(amx, params[arg_4])); + } + break; + } + case ExtraType::String: { + auto& extra = player.Extras().getStrings(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid player extra '%s' var (string)", key) + SetAmxString(amx, params[arg_4], extra[key].c_str(), *Address(amx, params[arg_5])); + } else { + extra[key] = GetAmxString(amx, params[arg_4], 1); + } + break; + } + } + return true; + } + + auto get_player_extra(Amx* amx, cell* params) -> cell { + return HandlePlayerExtra(amx, params, true); + } + + auto set_player_extra(Amx* amx, cell* params) -> cell { + return HandlePlayerExtra(amx, params, false); + } + + auto is_valid_attacker(Amx*, cell* params) -> cell { + enum { + arg_count, + arg_attacker, + arg_player, + arg_self, + }; + + const int attackerId = params[arg_attacker]; + const int playerId = params[arg_player]; + const bool self = params[arg_self]; + const auto& attacker = Players[attackerId]; + const auto& player = Players[playerId]; + // connect attacker? + GameRules.PlayerCanTakeDamage(player, attacker); + return true; + } + auto change_player_class(Amx*, cell* params) -> cell { enum { arg_count, @@ -262,7 +334,7 @@ namespace rz const int playerId = params[arg_player]; const int flashlightId = params[arg_flashlight]; auto& player = Players[playerId]; - player.getFlashlight().setId(flashlightId); + player.Flashlight().setId(flashlightId); return true; } @@ -279,29 +351,6 @@ namespace rz return player.ChangeNightVision(nightVisionId); } - auto add_player_currency(Amx* amx, cell* params) -> cell { - enum { - arg_count, - arg_player, - arg_currency, - arg_amount, - arg_reason, - }; - - // Check arg count - const int playerId = params[arg_player]; - const auto& player = Players[playerId]; - const auto currencyId = params[arg_currency]; - const auto reason = GetAmxString(amx, params[arg_reason]); - const auto& currencyRef = Currency[currencyId]; - if (!currencyRef) { - // throw - return false; - } - const auto currency = currencyRef->get(); - return currency.executeSet(player, currency.executeGet(player) + params[arg_amount], reason); - } - auto player_joined(Amx*, cell* params) -> cell { enum { arg_count, @@ -357,36 +406,6 @@ namespace rz return player.isFrozen(); } - auto give_long_jump(Amx*, cell* params) -> cell { - enum { - arg_count, - arg_player, - arg_force, - arg_height, - arg_cooldown, - }; - - const int playerId = params[arg_player]; - const int force = params[arg_force]; - const int height = params[arg_height]; - const float cooldown = CellToFloat(params[arg_cooldown]); - auto& player = Players[playerId]; - player.GiveLongJump(force, height, cooldown); - return true; - } - - auto remove_long_jump(Amx*, cell* params) -> cell { - enum { - arg_count, - arg_player, - }; - - const int playerId = params[arg_player]; - auto& player = Players[playerId]; - player.RemoveLongJump(); - return true; - } - auto send_hud(Amx* amx, cell* params) -> cell { enum { arg_count, @@ -409,19 +428,19 @@ namespace rz cell fxTime; }; - auto length = 0; const int playerId = params[arg_player]; // check 0..3 const int channel = params[arg_channel]; const auto value = *reinterpret_cast(Address(amx, params[arg_hud_params])); - auto color1 = Colors.parse(CellToString(value.color1, sizeof(value.color1))); + const auto color1 = Colors.parse(CellToString(value.color1, sizeof(value.color1))); if (!color1) { return false; } - auto color2 = Colors.parse(CellToString(value.color2, sizeof(value.color2))); + const auto color2 = Colors.parse(CellToString(value.color2, sizeof(value.color2))); if (!color2) { return false; } + auto length = 0; const auto text = FormatAmxString(amx, params, arg_text, &length); const auto& hudParams = HudMessageParams() .setX(CellToFloat(value.x)) @@ -435,7 +454,7 @@ namespace rz .setFxTime(CellToFloat(value.fxTime)) .setChannel(channel); if (playerId) { - auto& player = Players[playerId]; + const auto& player = Players[playerId]; netHudMessage(player, hudParams, text); } else { netHudMessage(TO_ALL, hudParams, text); @@ -466,7 +485,7 @@ namespace rz auto length = 0; const int playerId = params[arg_player]; const auto value = *reinterpret_cast(Address(amx, params[arg_hud_params])); - auto color = Colors.parse(CellToString(value.color, sizeof(value.color))); + const auto color = Colors.parse(CellToString(value.color, sizeof(value.color))); if (!color) { return false; } @@ -481,7 +500,7 @@ namespace rz .setFadeOutTime(CellToFloat(value.fadeOutTime)) .setFxTime(CellToFloat(value.fxTime)); if (playerId) { - auto& player = Players[playerId]; + const auto& player = Players[playerId]; netDHudMessage(player, hudParams, text); } else { netDHudMessage(TO_ALL, hudParams, text); @@ -507,25 +526,26 @@ namespace rz auto AmxxPlayer::registerNatives() const -> void { static AmxNativeInfo natives[] = { - {"get_player_var", get_player_var}, - {"set_player_var", set_player_var}, - {"change_player_class", change_player_class}, - {"change_player_subclass", change_player_subclass}, - {"change_player_flashlight", change_player_flashlight}, + {"get_player_var", get_player_var}, + {"set_player_var", set_player_var}, + {"is_player_extra_exists", is_player_extra_exists}, + {"get_player_extra", get_player_extra}, + {"set_player_extra", set_player_extra}, + {"is_valid_attacker", is_valid_attacker}, + {"change_player_class", change_player_class}, + {"change_player_subclass", change_player_subclass}, + {"change_player_flashlight", change_player_flashlight}, {"change_player_night_vision", change_player_night_vision}, - {"player_joined", player_joined}, - {"respawn_player", respawn_player}, - {"add_player_currency", add_player_currency}, - {"freeze_player", freeze_player}, - {"is_player_freeze", is_player_freeze}, - {"give_long_jump", give_long_jump}, - {"remove_long_jump", remove_long_jump}, - - {"send_hud", send_hud}, - {"send_large_hud", send_large_hud}, - {"send_weapon_anim", send_weapon_anim}, - - {nullptr, nullptr}, + {"player_joined", player_joined}, + {"respawn_player", respawn_player}, + {"freeze_player", freeze_player}, + {"is_player_freeze", is_player_freeze}, + + {"send_hud", send_hud}, + {"send_large_hud", send_large_hud}, + {"send_weapon_anim", send_weapon_anim}, + + {nullptr, nullptr}, }; AddNatives(natives); } diff --git a/rezombie/src/player/api/player_class.cpp b/rezombie/src/player/api/player_class.cpp index a7c263d..c748ba4 100644 --- a/rezombie/src/player/api/player_class.cpp +++ b/rezombie/src/player/api/player_class.cpp @@ -19,8 +19,10 @@ namespace rz using e = ForwardExecType; using p = ForwardParam; - registerForward(PlayerClassForward::ChangeClassPre, "@change_class_pre", e::Continue, p::Cell, p::Cell, p::Cell); - registerForward(PlayerClassForward::ChangeClassPost, "@change_class_post", e::Ignore, p::Cell, p::Cell, p::Cell); + registerForward(PlayerClassForward::ChangeClassPre, "@change_class_pre", e::Continue, p::Cell, p::Cell, + p::Cell); + registerForward(PlayerClassForward::ChangeClassPost, "@change_class_post", e::Ignore, p::Cell, p::Cell, + p::Cell); } auto create_class(Amx* amx, cell* params) -> cell { @@ -50,14 +52,14 @@ namespace rz }; const std::unordered_map PlayerClassVarsMap = { - {"handle", PlayerClassVars::Handle}, - {"name", PlayerClassVars::Name}, - {"team", PlayerClassVars::Team}, - {"hud_color", PlayerClassVars::HudColor}, - {"props", PlayerClassVars::Props}, - {"models", PlayerClassVars::Models}, - {"sounds", PlayerClassVars::Sounds}, - {"melee", PlayerClassVars::Melee}, + {"handle", PlayerClassVars::Handle}, + {"name", PlayerClassVars::Name}, + {"team", PlayerClassVars::Team}, + {"hud_color", PlayerClassVars::HudColor}, + {"props", PlayerClassVars::Props}, + {"models", PlayerClassVars::Models}, + {"sounds", PlayerClassVars::Sounds}, + {"melee", PlayerClassVars::Melee}, {"forward_give_default_items", PlayerClassVars::ForwardGiveDefaultItems}, }; @@ -73,15 +75,16 @@ namespace rz using vars = PlayerClassVars; using p = ForwardParam; - const auto playerClassRef = Classes[params[arg_class]]; - if (!playerClassRef) { + const int classId = params[arg_class]; + const auto classRef = Classes[classId]; + if (!classRef) { // Invalid index return false; } const auto key = GetAmxString(amx, params[arg_var]); const auto& var = getMapValue(PlayerClassVarsMap, key); CHECK_VAR_EXISTS("Invalid class '%s' var", key) - auto& playerClass = playerClassRef->get(); + auto& playerClass = classRef->get(); switch (*var) { case vars::Handle: { if (isGetter) { @@ -173,11 +176,100 @@ namespace rz return HandleClassVar(amx, params, false); } - auto class_begin(Amx*, cell*) -> cell { + auto is_class_extra_exists(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_class, + arg_type, + arg_key, + }; + + const int classId = params[arg_class]; + const auto classRef = Classes[classId]; + if (!classRef) { + // Invalid index + return false; + } + auto& playerClass = classRef->get(); + const auto type = static_cast(params[arg_type]); + const auto key = GetAmxString(amx, params[arg_key]); + return playerClass.getExtras().isKeyExists(type, key); + } + + auto HandleClassExtra(Amx* amx, cell* params, bool isGetter) -> cell { + enum { + arg_count, + arg_class, + arg_type, + arg_key, + arg_4, + arg_5, + }; + + const int classId = params[arg_class]; + const auto classRef = Classes[classId]; + if (!classRef) { + // Invalid index + return false; + } + auto& playerClass = classRef->get(); + const auto type = static_cast(params[arg_type]); + const auto* key = GetAmxString(amx, params[arg_key], 0); + switch (type) { + case ExtraType::Int: { + auto& extra = playerClass.getExtras().getInts(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid class extra '%s' var (int)", key) + return extra[key]; + } else { + extra[key] = *Address(amx, params[arg_4]); + } + break; + } + case ExtraType::Float: { + auto& extra = playerClass.getExtras().getFloats(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid class extra '%s' var (float)", key) + return FloatToCell(extra[key]); + } else { + extra[key] = CellToFloat(*Address(amx, params[arg_4])); + } + break; + } + case ExtraType::String: { + auto& extra = playerClass.getExtras().getStrings(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid class extra '%s' var (string)", key) + SetAmxString(amx, params[arg_4], extra[key].c_str(), *Address(amx, params[arg_5])); + } else { + extra[key] = GetAmxString(amx, params[arg_4], 1); + } + break; + } + } + return true; + } + + auto get_class_extra(Amx* amx, cell* params) -> cell { + return HandleClassExtra(amx, params, true); + } + + auto set_class_extra(Amx* amx, cell* params) -> cell { + return HandleClassExtra(amx, params, false); + } + + auto classes_count(Amx*, cell*) -> cell { + return Classes.count(); + } + + auto classes_begin(Amx*, cell*) -> cell { return Classes.begin(); } - auto class_end(Amx*, cell*) -> cell { + auto classes_end(Amx*, cell*) -> cell { return Classes.end(); } @@ -193,14 +285,18 @@ namespace rz auto AmxxPlayerClass::registerNatives() const -> void { static AmxNativeInfo natives[] = { - {"create_class", create_class}, + {"create_class", create_class}, {"get_class_var", get_class_var}, {"set_class_var", set_class_var}, - {"class_begin", class_begin}, - {"class_end", class_end}, - {"find_class", find_class}, + {"is_class_extra_exists", is_class_extra_exists}, + {"get_class_extra", get_class_extra}, + {"set_class_extra", set_class_extra}, + {"classes_count", classes_count}, + {"classes_begin", classes_begin}, + {"classes_end", classes_end}, + {"find_class", find_class}, - {nullptr, nullptr}, + {nullptr, nullptr}, }; AddNatives(natives); } diff --git a/rezombie/src/player/api/player_subclass.cpp b/rezombie/src/player/api/player_subclass.cpp index 5c0c906..6f7f4d7 100644 --- a/rezombie/src/player/api/player_subclass.cpp +++ b/rezombie/src/player/api/player_subclass.cpp @@ -172,11 +172,15 @@ namespace rz return HandleSubclassVar(amx, params, false); } - auto subclass_begin(Amx*, cell*) -> cell { + auto subclasses_count(Amx*, cell*) -> cell { + return Subclasses.count(); + } + + auto subclasses_begin(Amx*, cell*) -> cell { return Subclasses.begin(); } - auto subclass_end(Amx*, cell*) -> cell { + auto subclasses_end(Amx*, cell*) -> cell { return Subclasses.end(); } @@ -195,8 +199,9 @@ namespace rz {"create_subclass", create_subclass}, {"get_subclass_var", get_subclass_var}, {"set_subclass_var", set_subclass_var}, - {"subclass_begin", subclass_begin}, - {"subclass_end", subclass_end}, + {"subclasses_count", subclasses_count}, + {"subclasses_begin", subclasses_begin}, + {"subclasses_end", subclasses_end}, {"find_subclass", find_subclass}, {nullptr, nullptr}, diff --git a/rezombie/src/player/core/player_base.cpp b/rezombie/src/player/core/player_base.cpp index be0c4c8..3ec856d 100644 --- a/rezombie/src/player/core/player_base.cpp +++ b/rezombie/src/player/core/player_base.cpp @@ -138,6 +138,14 @@ namespace rz base_->can_shoot = canShoot; } + auto Player::getDeadTime() const -> float { + return base_->dead_time; + } + + auto Player::setDeadTime(float time) -> void { + base_->dead_time = time; + } + auto Player::getHideHud() const -> int { return base_->hide_hud; } @@ -186,6 +194,10 @@ namespace rz return base_->observer_target.Get(); } + auto Player::setWeaponVolume(int volume) -> void { + base_->weapon_volume = volume; + } + auto Player::getButtonLast() const -> int { return base_->button_last; } diff --git a/rezombie/src/player/core/player_cstrike.cpp b/rezombie/src/player/core/player_cstrike.cpp index b2a1e03..d77fe04 100644 --- a/rezombie/src/player/core/player_cstrike.cpp +++ b/rezombie/src/player/core/player_cstrike.cpp @@ -6,48 +6,43 @@ namespace rz { using namespace cssdk; - auto Player::GiveDefaultItems() -> void - { + auto Player::GiveDefaultItems() -> void { cstrike_->GiveDefaultItems(); } - auto Player::RemoveAllItems(bool removeSuit) -> void - { + auto Player::RemoveAllItems(bool removeSuit) -> void { cstrike_->RemoveAllItems(removeSuit); } - auto Player::GiveItem(const char* itemName) -> EntityBase* - { + auto Player::GiveItem(const char* itemName) -> EntityBase* { return cstrike_->GiveNamedItemEx(itemName); } - auto Player::DropPlayerItem(const char* itemName) -> void - { + auto Player::DropPlayerItem(const char* itemName) -> void { cstrike_->DropPlayerItem(itemName); } - auto Player::SwitchWeapon(PlayerItemBase* weapon) -> bool - { + auto Player::SwitchWeapon(PlayerItemBase* weapon) -> bool { return cstrike_->SwitchWeapon(weapon); } - auto Player::SetAnimation(PlayerAnim playerAnim) -> void - { + auto Player::SetAnimation(PlayerAnim playerAnim) -> void { cstrike_->SetAnimation(playerAnim); } - auto Player::TeamChangeUpdate() -> void - { + auto Player::TeamChangeUpdate() -> void { cstrike_->TeamChangeUpdate(); } - auto Player::Reset() -> void - { + auto Player::Reset() -> void { cstrike_->Reset(); } - auto Player::SpawnEquip() -> void - { + auto Player::SpawnEquip() -> void { cstrike_->OnSpawnEquip(true, false); } + + auto Player::SetScoreboardAttributes(PlayerBase* destination) -> void { + cstrike_->SetScoreboardAttributes(destination); + } } diff --git a/rezombie/src/player/core/player_entity_vars.cpp b/rezombie/src/player/core/player_entity_vars.cpp index 5e8ffde..1276964 100644 --- a/rezombie/src/player/core/player_entity_vars.cpp +++ b/rezombie/src/player/core/player_entity_vars.cpp @@ -2,104 +2,88 @@ #include "rezombie/player/player.h" #include "rezombie/colors/colors.h" -#include namespace rz { using namespace cssdk; - auto Player::getHealth() const -> int - { + auto Player::getHealth() const -> int { return static_cast(vars_->health); } - auto Player::setHealth(int health) -> void - { + auto Player::setHealth(int health) -> void { vars_->health = static_cast(health); } - auto Player::getMaxHealth() const -> int - { + auto Player::getMaxHealth() const -> int { return static_cast(vars_->max_health); } - auto Player::setMaxHealth(int maxHealth) -> void - { + auto Player::setMaxHealth(int maxHealth) -> void { vars_->max_health = static_cast(maxHealth); } - auto Player::getArmor() const -> int - { + auto Player::getArmor() const -> int { return static_cast(vars_->armor_value); } - auto Player::setArmor(int armor) -> void - { + auto Player::setArmor(int armor) -> void { vars_->armor_value = static_cast(armor); } - auto Player::getMaxSpeed() const -> int - { + auto Player::getMaxSpeed() const -> int { return static_cast(vars_->max_speed); } - auto Player::setMaxSpeed(int maxSpeed) -> void - { + auto Player::setMaxSpeed(int maxSpeed) -> void { vars_->max_speed = static_cast(maxSpeed); } - auto Player::getGravity() const - { + auto Player::getGravity() const { return vars_->gravity; } - auto Player::setGravity(float gravity) -> void - { + auto Player::setGravity(float gravity) -> void { vars_->gravity = gravity; } - auto Player::getFlags() const -> int - { + auto Player::getGroundEntity() const -> Edict* { + return vars_->ground_entity; + } + + auto Player::getFlags() const -> int { return vars_->flags; } - auto Player::setFlags(int flags) -> void - { + auto Player::setFlags(int flags) -> void { vars_->flags = flags; } - auto Player::getDeadFlag() const - { + auto Player::getDeadFlag() const -> DeathState { return vars_->dead_flag; } - auto Player::setDeadFlag(DeathState deadFlag) -> void - { + auto Player::setDeadFlag(DeathState deadFlag) -> void { vars_->dead_flag = deadFlag; } - auto Player::setViewModel(unsigned int viewModel) -> void - { + auto Player::setViewModel(unsigned int viewModel) -> void { vars_->view_model = static_cast(viewModel); } - auto Player::setWeaponModel(unsigned int weaponModel) -> void - { + auto Player::setWeaponModel(unsigned int weaponModel) -> void { vars_->weapon_model = static_cast(weaponModel); } - auto Player::setRenderMode(Rendering mode) -> void - { + auto Player::setRenderMode(Rendering mode) -> void { vars_->render_mode = mode; } - auto Player::setRenderAmount(int amount) -> void - { + auto Player::setRenderAmount(int amount) -> void { vars_->render_amount = static_cast(amount); } - auto Player::setRenderColor(const std::string& color) -> void - { + auto Player::setRenderColor(const std::string& color) -> void { const auto valueRef = Colors.parse(color); if (!valueRef) { return; @@ -108,213 +92,187 @@ namespace rz vars_->render_color = Vector(value.getRed(), value.getGreen(), value.getBlue()); } - auto Player::setRenderFx(RenderingFx fx) -> void - { + auto Player::setRenderFx(RenderingFx fx) -> void { vars_->render_fx = fx; } - auto Player::getSkin() const -> int - { + auto Player::getNextThink() const -> float { + return vars_->next_think; + } + + auto Player::setNextThink(float time) -> void { + vars_->next_think = time; + } + + auto Player::getMoveType() const -> MoveTypeEntity { + return vars_->move_type; + } + + auto Player::setMoveType(MoveTypeEntity moveType) -> void { + vars_->move_type = moveType; + } + + auto Player::getSkin() const -> int { return vars_->skin; } - auto Player::setSkin(int skin) -> void - { + auto Player::setSkin(int skin) -> void { vars_->skin = skin; } - auto Player::getBody() const -> int - { + auto Player::getBody() const -> int { return vars_->body; } - auto Player::setBody(int body) -> void - { + auto Player::setBody(int body) -> void { vars_->body = body; } - auto Player::getEffects() const -> int - { + auto Player::getEffects() const -> int { return vars_->effects; } - auto Player::setEffects(int effects) -> void - { + auto Player::setEffects(int effects) -> void { vars_->effects = effects; } - auto Player::getFrags() const -> int - { + auto Player::getFrags() const -> int { return static_cast(vars_->frags); } - auto Player::setFrags(int frags) -> void - { + auto Player::setFrags(int frags) -> void { vars_->frags = static_cast(frags); } - auto Player::getOrigin() const -> Vector - { + auto Player::getOrigin() const -> Vector { return vars_->origin; } - auto Player::setOrigin(Vector origin) -> void - { + auto Player::setOrigin(Vector origin) -> void { vars_->origin = origin; } - auto Player::getAngles() const -> Vector - { + auto Player::getAngles() const -> Vector { return vars_->angles; } - auto Player::setAngles(Vector angles) -> void - { + auto Player::setAngles(Vector angles) -> void { vars_->angles = angles; } - auto Player::getVelocity() const -> Vector& - { + auto Player::getVelocity() const -> Vector& { return vars_->velocity; } - auto Player::setVelocity(Vector velocity) -> void - { + auto Player::setVelocity(Vector velocity) -> void { vars_->velocity = velocity; } - auto Player::getViewAngle() const -> Vector& - { + auto Player::getViewAngle() const -> Vector& { return vars_->viewing_angle; } - auto Player::setViewAngle(Vector viewAngle) -> void - { + auto Player::setViewAngle(Vector viewAngle) -> void { vars_->viewing_angle = viewAngle; } - auto Player::setFixAngleMode(FixAngleMode fixAngleMod) -> void - { + auto Player::setFixAngleMode(FixAngleMode fixAngleMod) -> void { vars_->fix_angle = fixAngleMod; } - auto Player::getViewOfs() const -> Vector - { + auto Player::getViewOfs() const -> Vector { return vars_->view_ofs; } - auto Player::setViewOfs(Vector viewOfs) -> void - { + auto Player::setViewOfs(Vector viewOfs) -> void { vars_->view_ofs = viewOfs; } - auto Player::setModelIndex(int modelIndex) -> void - { + auto Player::setModelIndex(int modelIndex) -> void { vars_->model_index = modelIndex; } - auto Player::getPunchAngle() const -> Vector& - { + auto Player::getPunchAngle() const -> Vector& { return vars_->punch_angle; } - auto Player::setPunchAngle(Vector punchAngle) -> void - { + auto Player::setPunchAngle(Vector punchAngle) -> void { vars_->punch_angle = punchAngle; } - auto Player::getNetName() const - { + auto Player::getNetName() const { return vars_->net_name; } - auto Player::getWeapons() const -> int - { + auto Player::getWeapons() const -> int { return vars_->weapons; } - auto Player::setWeapons(int weapons) -> void - { + auto Player::setWeapons(int weapons) -> void { vars_->weapons = weapons; } - auto Player::getImpulse() const -> int - { + auto Player::getImpulse() const -> int { return vars_->impulse; } - auto Player::setImpulse(int impulse) -> void - { + auto Player::setImpulse(int impulse) -> void { vars_->impulse = impulse; } - auto Player::getWeaponAnim() const -> int - { + auto Player::getWeaponAnim() const -> int { return vars_->weapon_anim; } - auto Player::setWeaponAnim(int weaponAnim) -> void - { + auto Player::setWeaponAnim(int weaponAnim) -> void { vars_->weapon_anim = weaponAnim; } - auto Player::isInDuck() const -> qboolean - { + auto Player::isInDuck() const -> qboolean { return vars_->in_duck; } - auto Player::getDuckTime() const -> float - { + auto Player::getDuckTime() const -> float { return vars_->duck_time; } - auto Player::getButton() const -> int - { + auto Player::getButton() const -> int { return vars_->button; } - auto Player::setButton(int button) -> void - { + auto Player::setButton(int button) -> void { vars_->button = button; } - auto Player::getOldButtons() const -> int - { + auto Player::getOldButtons() const -> int { return vars_->old_buttons; } - auto Player::setOldButtons(int oldButtons) -> void - { + auto Player::setOldButtons(int oldButtons) -> void { vars_->old_buttons = oldButtons; } - auto Player::getWaterLevel() const -> int - { + auto Player::getWaterLevel() const -> int { return vars_->water_level; } - auto Player::setWaterLevel(int waterLevel) -> void - { + auto Player::setWaterLevel(int waterLevel) -> void { vars_->water_level = waterLevel; } - auto Player::getObserverMode() const -> ObserverMode - { + auto Player::getObserverMode() const -> ObserverMode { return static_cast(vars_->i_user1); } - auto Player::setIUser1(ObserverMode observerMode) -> void - { + auto Player::setIUser1(ObserverMode observerMode) -> void { vars_->i_user1 = toInt(observerMode); } - auto Player::getIUser3() const -> int - { + auto Player::getIUser3() const -> int { return vars_->i_user3; } - auto Player::setIUser3(int iUser3) -> void - { + auto Player::setIUser3(int iUser3) -> void { vars_->i_user3 = iUser3; } } diff --git a/rezombie/src/player/extra_jumps.cpp b/rezombie/src/player/extra_jumps.cpp deleted file mode 100644 index 59875b9..0000000 --- a/rezombie/src/player/extra_jumps.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "rezombie/player/player.h" - -namespace rz -{ - auto Player::ExtraJump() -> void { - auto& extraJump = getExtraJump(); - if (getFlags() & FL_ON_GROUND) { - extraJump.setCount(0); - return; - } - if (getOldButtons() & IN_JUMP) { - return; - } - if (extraJump.getCount() >= extraJump.getMaximum()) { - return; - } - auto& velocity = getVelocity(); - velocity.z = sqrt(2 * 800 * 45.0f); - setVelocity(velocity); - extraJump.setCount(extraJump.getCount() + 1); - } -} diff --git a/rezombie/src/player/flashlight.cpp b/rezombie/src/player/flashlight.cpp index 0e8967c..d9bcb93 100644 --- a/rezombie/src/player/flashlight.cpp +++ b/rezombie/src/player/flashlight.cpp @@ -6,72 +6,74 @@ namespace rz { auto Player::FlashlightUpdate() -> void { - const auto& flashlightRef = Flashlights[getFlashlight().getId()]; + auto& flashlight = Flashlight(); + const auto& flashlightRef = Flashlights[flashlight.getId()]; if (flashlightRef) { setHideHud(getHideHud() & ~HIDE_HUD_FLASHLIGHT); } else { setHideHud(getHideHud() | HIDE_HUD_FLASHLIGHT); return; } - const auto& flashlight = flashlightRef->get(); - auto& playerFlashlight = getFlashlight(); - if (playerFlashlight.getTime() <= g_global_vars->time) { - if (playerFlashlight.isEnabled()) { - if (playerFlashlight.getBattery()) { - playerFlashlight.setBattery(playerFlashlight.getBattery() - 1); - if (playerFlashlight.getBattery() <= 0) { - playerFlashlight.setEnabled(false); - playerFlashlight.setTime(g_global_vars->time + flashlight.getChargeTime()); - playerFlashlight.setNextDynamicUpdate(0); - sendFlashlight(*this, false, playerFlashlight.getBattery()); + const auto& fl = flashlightRef->get(); + if (flashlight.getTime() <= g_global_vars->time) { + if (flashlight.isEnabled()) { + if (flashlight.getBattery()) { + flashlight.setBattery(flashlight.getBattery() - 1); + if (flashlight.getBattery() <= 0) { + flashlight.setEnabled(false); + flashlight.setTime(g_global_vars->time + fl.getChargeTime()); + flashlight.setNextDynamicUpdate(0); + sendFlashlight(*this, false, flashlight.getBattery()); } else { - playerFlashlight.setTime(g_global_vars->time + flashlight.getDrainTime()); - sendFlashBattery(*this, playerFlashlight.getBattery()); + flashlight.setTime(g_global_vars->time + fl.getDrainTime()); + sendFlashBattery(*this, flashlight.getBattery()); } } } else { - if (playerFlashlight.getBattery() < 100) { - playerFlashlight.setBattery(playerFlashlight.getBattery() + 1); - playerFlashlight.setTime(g_global_vars->time + flashlight.getChargeTime()); - sendFlashBattery(*this, playerFlashlight.getBattery()); + if (flashlight.getBattery() < 100) { + flashlight.setBattery(flashlight.getBattery() + 1); + flashlight.setTime(g_global_vars->time + fl.getChargeTime()); + sendFlashBattery(*this, flashlight.getBattery()); } else { - playerFlashlight.setTime(0); + flashlight.setTime(0); } } } - if (playerFlashlight.getNextDynamicUpdate() <= g_global_vars->time) { - playerFlashlight.setNextDynamicUpdate(g_global_vars->time + 0.1f); - TraceResult trace; - MakeVectors(getViewAngle()); - auto end = getGunPosition() + g_global_vars->vec_forward * static_cast(flashlight.getDistance()); - TraceLine(getGunPosition(), end, TR_IGNORE_MONSTERS, *this, &trace); - if (trace.fraction != 1.f) { - SendNetMessage(*this, SvcMessage::TempEntity, [&]() { - TE_DynamicLight(trace.end_position, flashlight.getSize(), flashlight.getColor(), 3, 0); - }); - } + if (!flashlight.getNextDynamicUpdate() || flashlight.getNextDynamicUpdate() > g_global_vars->time) { + return; + } + flashlight.setNextDynamicUpdate(g_global_vars->time + 0.1f); + TraceResult trace; + MakeVectors(getViewAngle()); + const auto end = getGunPosition() + g_global_vars->vec_forward * static_cast(fl.getDistance()); + TraceLine(getGunPosition(), end, TR_IGNORE_NONE, *this, &trace); + if (trace.fraction == 1.f) { + return; } + SendNetMessage(*this, SvcMessage::TempEntity, [&] { + TE_DynamicLight(trace.end_position, fl.getSize(), fl.getColor(), 3, 0); + }); } auto Player::SwitchFlashlight(bool isEnabled) -> void { - const auto& flashlightRef = Flashlights[getFlashlight().getId()]; + auto& flashlight = Flashlight(); + const auto& flashlightRef = Flashlights[flashlight.getId()]; if (!flashlightRef) { return; } - const auto& flashlight = flashlightRef->get(); - auto& playerFlashlight = getFlashlight(); + const auto& fl = flashlightRef->get(); if (isEnabled) { - playerFlashlight.setEnabled(true); - playerFlashlight.setTime(g_global_vars->time + flashlight.getDrainTime()); - sendFlashlight(*this, true, playerFlashlight.getBattery()); - if (flashlight.getSize()) { - playerFlashlight.setNextDynamicUpdate(1.f); + flashlight.setEnabled(true); + flashlight.setTime(g_global_vars->time + fl.getDrainTime()); + sendFlashlight(*this, true, flashlight.getBattery()); + if (fl.getSize()) { + flashlight.setNextDynamicUpdate(1.f); } } else { - playerFlashlight.setEnabled(false); - playerFlashlight.setTime(g_global_vars->time + flashlight.getChargeTime()); - playerFlashlight.setNextDynamicUpdate(0); - sendFlashlight(*this, false, playerFlashlight.getBattery()); + flashlight.setEnabled(false); + flashlight.setTime(g_global_vars->time + fl.getChargeTime()); + flashlight.setNextDynamicUpdate(0); + sendFlashlight(*this, false, flashlight.getBattery()); } } } diff --git a/rezombie/src/player/preview.cpp b/rezombie/src/player/join_preview.cpp similarity index 93% rename from rezombie/src/player/preview.cpp rename to rezombie/src/player/join_preview.cpp index c44c5ef..72bd85a 100644 --- a/rezombie/src/player/preview.cpp +++ b/rezombie/src/player/join_preview.cpp @@ -3,7 +3,7 @@ namespace rz { auto Player::setPreview(bool isEnabled) -> void { - auto& preview = getPreviewVars(); + auto& preview = getJoinPreviewVars(); preview.setEnabled(isEnabled); /*if (preview.isEnabled()) { SetView(*this, ModelPreview.getCamera()); @@ -21,7 +21,7 @@ namespace rz if (!cameraRef) { return; } - auto& preview = getPreviewVars(); + auto& preview = getJoinPreviewVars(); if (!preview.isEnabled()) { return; } diff --git a/rezombie/src/player/jumps.cpp b/rezombie/src/player/jumps.cpp new file mode 100644 index 0000000..98c7ca3 --- /dev/null +++ b/rezombie/src/player/jumps.cpp @@ -0,0 +1,38 @@ +#include "rezombie/player/player.h" +#include "rezombie/player/api/jumps.h" + +namespace rz +{ + auto Player::JumpThink() -> void { + if (!(getFlags() & FL_ON_GROUND) || !getGroundEntity()) { + return; + } + Jumps().setCount(*this, 0); + } + + auto Player::Jump() -> void { + if (getFlags() & FL_WATER_JUMP) { + return; + } + if (getWaterLevel() >= 2) { + return; + } + if (!(getButtonPressed() & IN_JUMP)) { + return; + } + auto& jumps = Jumps(); + if (jumps.getCount() >= jumps.getMaximum() && jumps.getMaximum() != -1) { + return; + } + jumps.setCount(*this, jumps.getCount() + 1); + } + + auto JumpsVars::setCount(const int player, const int count) -> void { + const auto oldCount = getCount(); + count_ = count; + if (oldCount == count) { + return; + } + JumpsApi.Jump(player, count); + } +} diff --git a/rezombie/src/player/long_jump.cpp b/rezombie/src/player/long_jump.cpp index d3a52b6..564222e 100644 --- a/rezombie/src/player/long_jump.cpp +++ b/rezombie/src/player/long_jump.cpp @@ -1,24 +1,23 @@ -#include "rezombie/player/api/player.h" +#include "rezombie/player/api/long_jump.h" #include "rezombie/player/player.h" -#include "rezombie/messages/user_message.h" namespace rz { - auto Player::GiveLongJump(int force, int height, float cooldown) -> void { - auto& longJump = getLongJump(); - longJump.setState(LongJumpState::Ready); + auto Player::GiveLongJump(int force, int height, int cooldown) -> void { + auto& longJump = LongJump(); + longJump.setState(*this, LongJumpState::Ready); longJump.setForce(force); longJump.setHeight(height); longJump.setCooldown(cooldown); - sendItemPickup(*this, ITEM_LONG_JUMP); + LongJumpApi.Give(*this); } auto Player::RemoveLongJump() -> void { - getLongJump().reset(); + LongJump().reset(*this); } - auto Player::LongJump() -> void { - auto& longJump = getLongJump(); + auto Player::ActivateLongJump() -> void { + const auto& longJump = LongJump(); if (longJump.getState() != LongJumpState::Ready) { return; } @@ -40,26 +39,33 @@ namespace rz if (!((getButton() & IN_DUCK) && getDuckTime() > 0 && getVelocity().Length() > 50)) { return; } - MakeVectors(getViewAngle()); - Vector velocity = g_global_vars->vec_forward * static_cast(longJump.getForce()); - velocity.z = g_global_vars->vec_forward.z * static_cast(longJump.getHeight()); - setVelocity(velocity); - if (longJump.getCooldown() != 0.f) { - longJump.setNextStateTime(g_global_vars->time + longJump.getCooldown()); - longJump.setState(LongJumpState::Cooldown); - } - PlayerApi.LongJumpActivated(*this); + LongJumpApi.Activated(*this); } auto Player::LongJumpCooldown() -> void { - auto& longJump = getLongJump(); + auto& longJump = LongJump(); if (longJump.getState() != LongJumpState::Cooldown) { return; } if (longJump.getNextStateTime() > g_global_vars->time) { return; } - longJump.setNextStateTime(0.f); - longJump.setState(LongJumpState::Ready); + longJump.setNextStateTime(g_global_vars->time + 1.f); + longJump.setCooldownTimer(longJump.getCooldownTimer() - 1); + if (longJump.getCooldownTimer() > 0) { + LongJumpApi.CooldownTimer(*this, longJump.getCooldownTimer()); + } else { + longJump.setNextStateTime(0.f); + longJump.setState(*this, LongJumpState::Ready); + } + } + + auto LongJumpVars::setState(int player, LongJumpState state) -> void { + const auto oldState = getState(); + state_ = state; + if (oldState == state) { + return; + } + LongJumpApi.State(player, toInt(state)); } } diff --git a/rezombie/src/player/nightvision.cpp b/rezombie/src/player/nightvision.cpp index 4b4b9d0..36af27d 100644 --- a/rezombie/src/player/nightvision.cpp +++ b/rezombie/src/player/nightvision.cpp @@ -1,56 +1,41 @@ #include "rezombie/player/player.h" -#include "rezombie/player/api/player.h" -#include "rezombie/player/api/player_class.h" -#include "rezombie/player/api/player_subclass.h" -#include "rezombie/player/modules/player_class.h" -#include "rezombie/player/modules/player_subclass.h" -#include "rezombie/player/modules/player_sounds.h" -#include "rezombie/player/modules/flashlight.h" -#include "rezombie/models/modules/models.h" -#include "rezombie/models/modules/models_pack.h" -#include "rezombie/weapons/modules/weapon.h" -#include "rezombie/player/players.h" -#include "rezombie/entity/wrappers/player_base_wrapper.h" -#include "rezombie/main/util.h" +#include "rezombie/player/modules/nightvision.h" #include "rezombie/map/environment.h" #include "rezombie/messages/user_message.h" -#include "rezombie/messages/temporary_entity.h" -#include -#include -#include namespace rz { - auto Player::ChangeNightVision(int nightVisionId) -> bool { + auto Player::ChangeNightVision(const int nightVisionId) -> bool { const auto& nightVisionRef = NightVisions[nightVisionId]; if (!nightVisionRef) { return false; } - getNightVision().setId(nightVisionId); + auto& nightVision = NightVision(); + nightVision.setId(nightVisionId); SwitchNightVision(true); return true; } - auto Player::SwitchNightVision(bool isEnabled) -> void { + auto Player::SwitchNightVision(const bool isEnabled) -> void { + auto& nightVision = NightVision(); if (isEnabled) { - const auto& nightVisionRef = NightVisions[getNightVision().getId()]; + const auto& nightVisionRef = NightVisions[nightVision.getId()]; if (!nightVisionRef) { return; } - getNightVision().setEnabled(true); - const auto& nightVision = nightVisionRef->get(); + nightVision.setEnabled(true); + const auto& nv = nightVisionRef->get(); netLightStyle(*this, 0, "z"); - sendFog(*this, nightVision.getFog()); + sendFog(*this, nv.getFog()); sendScreenFade( *this, 0, 0, FADE_MODULATE | FADE_STAY_OUT, - nightVision.getColor(), - nightVision.getAlphaPercentage() + nv.getColor() ); } else { - getNightVision().setEnabled(false); + nightVision.setEnabled(false); netLightStyle(*this, 0, Environment.getLight()); sendFog(*this); sendScreenFade(*this); diff --git a/rezombie/src/player/player.cpp b/rezombie/src/player/player.cpp index e85c9ed..58adf88 100644 --- a/rezombie/src/player/player.cpp +++ b/rezombie/src/player/player.cpp @@ -9,12 +9,10 @@ #include "rezombie/models/modules/models_pack.h" #include "rezombie/weapons/modules/weapon.h" #include "rezombie/player/players.h" -#include "rezombie/entity/wrappers/player_base_wrapper.h" #include "rezombie/main/util.h" -#include "rezombie/map/environment.h" #include "rezombie/messages/user_message.h" -#include "rezombie/messages/temporary_entity.h" #include +#include #include namespace rz @@ -22,279 +20,279 @@ namespace rz using namespace core; using namespace metamod; -/* - void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) - { - m_canSwitchObserverModes = false; + /* + void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) + { + m_canSwitchObserverModes = false; - if (m_LastHitGroup == HITGROUP_HEAD) - m_bHeadshotKilled = true; + if (m_LastHitGroup == HITGROUP_HEAD) + m_bHeadshotKilled = true; - CBaseEntity *pAttackerEntity = CBaseEntity::Instance(pevAttacker); + CBaseEntity *pAttackerEntity = CBaseEntity::Instance(pevAttacker); - if (!m_bKilledByBomb) - { - g_pGameRules->PlayerKilled(this, pevAttacker, g_pevLastInflictor); - } + if (!m_bKilledByBomb) + { + g_pGameRules->PlayerKilled(this, pevAttacker, g_pevLastInflictor); + } - MESSAGE_BEGIN(MSG_ONE, gmsgNVGToggle, nullptr, pev); - WRITE_BYTE(0); - MESSAGE_END(); + MESSAGE_BEGIN(MSG_ONE, gmsgNVGToggle, nullptr, pev); + WRITE_BYTE(0); + MESSAGE_END(); - m_bNightVisionOn = false; + m_bNightVisionOn = false; - for (int i = 1; i <= gpGlobals->maxClients; i++) - { - CBasePlayer *pObserver = UTIL_PlayerByIndex(i); + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + CBasePlayer *pObserver = UTIL_PlayerByIndex(i); - if (!pObserver) - continue; + if (!pObserver) + continue; - if (pObserver->IsObservingPlayer(this)) - { - MESSAGE_BEGIN(MSG_ONE, gmsgNVGToggle, nullptr, pObserver->pev); - WRITE_BYTE(0); - MESSAGE_END(); + if (pObserver->IsObservingPlayer(this)) + { + MESSAGE_BEGIN(MSG_ONE, gmsgNVGToggle, nullptr, pObserver->pev); + WRITE_BYTE(0); + MESSAGE_END(); - pObserver->m_bNightVisionOn = false; - } + pObserver->m_bNightVisionOn = false; + } - if (pObserver->m_hObserverTarget == this) - pObserver->m_flNextFollowTime = 0.0f; - } + if (pObserver->m_hObserverTarget == this) + pObserver->m_flNextFollowTime = 0.0f; + } - if (m_pTank) - { - m_pTank->Use(this, this, USE_OFF, 0); - m_pTank = nullptr; - } + if (m_pTank) + { + m_pTank->Use(this, this, USE_OFF, 0); + m_pTank = nullptr; + } - SetAnimation(PLAYER_DIE); + SetAnimation(PLAYER_DIE); - if (m_pActiveItem && m_pActiveItem->m_pPlayer) - { - switch (m_pActiveItem->m_iId) + if (m_pActiveItem && m_pActiveItem->m_pPlayer) { - case WEAPON_HEGRENADE: + switch (m_pActiveItem->m_iId) { - CHEGrenade *pHEGrenade = static_cast(m_pActiveItem); - if ((pev->button & IN_ATTACK) && m_rgAmmo[pHEGrenade->m_iPrimaryAmmoType]) + case WEAPON_HEGRENADE: { - ThrowGrenade(pHEGrenade, (pev->origin + pev->view_ofs), pev->angles, 1.5, pHEGrenade->m_usCreateExplosion); - m_rgAmmo[m_pActiveItem->PrimaryAmmoIndex()]--; - pHEGrenade->m_flStartThrow = 0; + CHEGrenade *pHEGrenade = static_cast(m_pActiveItem); + if ((pev->button & IN_ATTACK) && m_rgAmmo[pHEGrenade->m_iPrimaryAmmoType]) + { + ThrowGrenade(pHEGrenade, (pev->origin + pev->view_ofs), pev->angles, 1.5, pHEGrenade->m_usCreateExplosion); + m_rgAmmo[m_pActiveItem->PrimaryAmmoIndex()]--; + pHEGrenade->m_flStartThrow = 0; + } + break; } - break; - } - case WEAPON_FLASHBANG: - { - CFlashbang *pFlashbang = static_cast(m_pActiveItem); - if ((pev->button & IN_ATTACK) && m_rgAmmo[pFlashbang->m_iPrimaryAmmoType]) + case WEAPON_FLASHBANG: { - ThrowGrenade(pFlashbang, (pev->origin + pev->view_ofs), pev->angles, 1.5); - m_rgAmmo[m_pActiveItem->PrimaryAmmoIndex()]--; - pFlashbang->m_flStartThrow = 0; + CFlashbang *pFlashbang = static_cast(m_pActiveItem); + if ((pev->button & IN_ATTACK) && m_rgAmmo[pFlashbang->m_iPrimaryAmmoType]) + { + ThrowGrenade(pFlashbang, (pev->origin + pev->view_ofs), pev->angles, 1.5); + m_rgAmmo[m_pActiveItem->PrimaryAmmoIndex()]--; + pFlashbang->m_flStartThrow = 0; + } + break; } - break; - } - case WEAPON_SMOKEGRENADE: - { - CSmokeGrenade *pSmoke = static_cast(m_pActiveItem); - if ((pev->button & IN_ATTACK) && m_rgAmmo[pSmoke->m_iPrimaryAmmoType]) + case WEAPON_SMOKEGRENADE: { - ThrowGrenade(pSmoke, (pev->origin + pev->view_ofs), pev->angles, 1.5, pSmoke->m_usCreateSmoke); - m_rgAmmo[m_pActiveItem->PrimaryAmmoIndex()]--; - pSmoke->m_flStartThrow = 0; + CSmokeGrenade *pSmoke = static_cast(m_pActiveItem); + if ((pev->button & IN_ATTACK) && m_rgAmmo[pSmoke->m_iPrimaryAmmoType]) + { + ThrowGrenade(pSmoke, (pev->origin + pev->view_ofs), pev->angles, 1.5, pSmoke->m_usCreateSmoke); + m_rgAmmo[m_pActiveItem->PrimaryAmmoIndex()]--; + pSmoke->m_flStartThrow = 0; + } + break; } - break; + default: + break; } - default: - break; } - } - - pev->modelindex = m_modelIndexPlayer; - pev->deadflag = DEAD_DYING; - pev->movetype = MOVETYPE_TOSS; - pev->takedamage = DAMAGE_NO; - - pev->gamestate = HITGROUP_SHIELD_DISABLED; - m_bShieldDrawn = false; - pev->flags &= ~FL_ONGROUND; + pev->modelindex = m_modelIndexPlayer; + pev->deadflag = DEAD_DYING; + pev->movetype = MOVETYPE_TOSS; + pev->takedamage = DAMAGE_NO; -#ifdef REGAMEDLL_FIXES - // FlashlightTurnOff() - pev->effects &= ~EF_DIMLIGHT; -#endif + pev->gamestate = HITGROUP_SHIELD_DISABLED; + m_bShieldDrawn = false; -#ifndef REGAMEDLL_ADD - if (fadetoblack.value == 0.0) - { - pev->iuser1 = OBS_CHASE_FREE; - pev->iuser2 = ENTINDEX(edict()); - pev->iuser3 = ENTINDEX(ENT(pevAttacker)); + pev->flags &= ~FL_ONGROUND; - m_hObserverTarget = UTIL_PlayerByIndexSafe(pev->iuser3); + #ifdef REGAMEDLL_FIXES + // FlashlightTurnOff() + pev->effects &= ~EF_DIMLIGHT; + #endif - MESSAGE_BEGIN(MSG_ONE, gmsgADStop, nullptr, pev); - MESSAGE_END(); - } - else - { - UTIL_ScreenFade(this, Vector(0, 0, 0), 3, 3, 255, (FFADE_OUT | FFADE_STAYOUT)); - } -#else - - float flDyingDuration = GetSequenceDuration() + CGameRules::GetDyingTime(); - switch ((int)fadetoblack.value) + #ifndef REGAMEDLL_ADD + if (fadetoblack.value == 0.0) { - default: - { - pev->iuser1 = OBS_CHASE_FREE; - pev->iuser2 = ENTINDEX(edict()); - pev->iuser3 = ENTINDEX(ENT(pevAttacker)); + pev->iuser1 = OBS_CHASE_FREE; + pev->iuser2 = ENTINDEX(edict()); + pev->iuser3 = ENTINDEX(ENT(pevAttacker)); - m_hObserverTarget = UTIL_PlayerByIndexSafe(pev->iuser3); + m_hObserverTarget = UTIL_PlayerByIndexSafe(pev->iuser3); - MESSAGE_BEGIN(MSG_ONE, gmsgADStop, nullptr, pev); - MESSAGE_END(); + MESSAGE_BEGIN(MSG_ONE, gmsgADStop, nullptr, pev); + MESSAGE_END(); + } + else + { + UTIL_ScreenFade(this, Vector(0, 0, 0), 3, 3, 255, (FFADE_OUT | FFADE_STAYOUT)); + } + #else - break; - } - case FADETOBLACK_STAY: - { - UTIL_ScreenFade(this, Vector(0, 0, 0), 0.8f, flDyingDuration, 255, (FFADE_OUT | FFADE_STAYOUT)); - break; - } - case FADETOBLACK_AT_DYING: + float flDyingDuration = GetSequenceDuration() + CGameRules::GetDyingTime(); + switch ((int)fadetoblack.value) { - pev->iuser1 = OBS_CHASE_FREE; - pev->iuser2 = ENTINDEX(edict()); - pev->iuser3 = ENTINDEX(ENT(pevAttacker)); - - m_hObserverTarget = UTIL_PlayerByIndexSafe(pev->iuser3); + default: + { + pev->iuser1 = OBS_CHASE_FREE; + pev->iuser2 = ENTINDEX(edict()); + pev->iuser3 = ENTINDEX(ENT(pevAttacker)); - MESSAGE_BEGIN(MSG_ONE, gmsgADStop, nullptr, pev); - MESSAGE_END(); + m_hObserverTarget = UTIL_PlayerByIndexSafe(pev->iuser3); - UTIL_ScreenFade(this, Vector(0, 0, 0), 0.8f, flDyingDuration, 255, (FFADE_OUT)); + MESSAGE_BEGIN(MSG_ONE, gmsgADStop, nullptr, pev); + MESSAGE_END(); - break; - } - } -#endif // REGAMEDLL_ADD - - SetScoreboardAttributes(); - - if (m_iThrowDirection) - { - switch (m_iThrowDirection) - { - case THROW_FORWARD: - { - UTIL_MakeVectors(pev->angles); - pev->velocity = gpGlobals->v_forward * RANDOM_FLOAT(100, 200); - pev->velocity.z = RANDOM_FLOAT(50, 100); break; } - case THROW_BACKWARD: + case FADETOBLACK_STAY: { - UTIL_MakeVectors(pev->angles); - pev->velocity = gpGlobals->v_forward * RANDOM_FLOAT(-100, -200); - pev->velocity.z = RANDOM_FLOAT(50, 100); + UTIL_ScreenFade(this, Vector(0, 0, 0), 0.8f, flDyingDuration, 255, (FFADE_OUT | FFADE_STAYOUT)); break; } - case THROW_HITVEL: + case FADETOBLACK_AT_DYING: { - if (FClassnameIs(pevAttacker, "player")) - { - UTIL_MakeVectors(pevAttacker->angles); + pev->iuser1 = OBS_CHASE_FREE; + pev->iuser2 = ENTINDEX(edict()); + pev->iuser3 = ENTINDEX(ENT(pevAttacker)); + + m_hObserverTarget = UTIL_PlayerByIndexSafe(pev->iuser3); + + MESSAGE_BEGIN(MSG_ONE, gmsgADStop, nullptr, pev); + MESSAGE_END(); + + UTIL_ScreenFade(this, Vector(0, 0, 0), 0.8f, flDyingDuration, 255, (FFADE_OUT)); - pev->velocity = gpGlobals->v_forward * RANDOM_FLOAT(200, 300); - pev->velocity.z = RANDOM_FLOAT(200, 300); - } - break; - } - case THROW_BOMB: - { - // TODO: fix test demo - pev->velocity = m_vBlastVector * (1.0f / m_vBlastVector.Length()) * float(2300.0f - m_vBlastVector.Length()) * 0.25f; - pev->velocity.z = (2300.0f - m_vBlastVector.Length()) / 2.75f; - break; - } - case THROW_GRENADE: - { - pev->velocity = m_vBlastVector * (1 / m_vBlastVector.Length()) * (500 - m_vBlastVector.Length()); - pev->velocity.z = (350 - m_vBlastVector.Length()) * 1.5; break; } - case THROW_HITVEL_MINUS_AIRVEL: + } + #endif // REGAMEDLL_ADD + + SetScoreboardAttributes(); + + if (m_iThrowDirection) + { + switch (m_iThrowDirection) { - if (FClassnameIs(pevAttacker, "player")) + case THROW_FORWARD: { - UTIL_MakeVectors(pevAttacker->angles); - pev->velocity = gpGlobals->v_forward * RANDOM_FLOAT(200, 300); + UTIL_MakeVectors(pev->angles); + pev->velocity = gpGlobals->v_forward * RANDOM_FLOAT(100, 200); + pev->velocity.z = RANDOM_FLOAT(50, 100); + break; } - break; + case THROW_BACKWARD: + { + UTIL_MakeVectors(pev->angles); + pev->velocity = gpGlobals->v_forward * RANDOM_FLOAT(-100, -200); + pev->velocity.z = RANDOM_FLOAT(50, 100); + break; + } + case THROW_HITVEL: + { + if (FClassnameIs(pevAttacker, "player")) + { + UTIL_MakeVectors(pevAttacker->angles); + + pev->velocity = gpGlobals->v_forward * RANDOM_FLOAT(200, 300); + pev->velocity.z = RANDOM_FLOAT(200, 300); + } + break; + } + case THROW_BOMB: + { + // TODO: fix test demo + pev->velocity = m_vBlastVector * (1.0f / m_vBlastVector.Length()) * float(2300.0f - m_vBlastVector.Length()) * 0.25f; + pev->velocity.z = (2300.0f - m_vBlastVector.Length()) / 2.75f; + break; + } + case THROW_GRENADE: + { + pev->velocity = m_vBlastVector * (1 / m_vBlastVector.Length()) * (500 - m_vBlastVector.Length()); + pev->velocity.z = (350 - m_vBlastVector.Length()) * 1.5; + break; + } + case THROW_HITVEL_MINUS_AIRVEL: + { + if (FClassnameIs(pevAttacker, "player")) + { + UTIL_MakeVectors(pevAttacker->angles); + pev->velocity = gpGlobals->v_forward * RANDOM_FLOAT(200, 300); + } + break; + } + default: + break; } - default: - break; - } - pev->angles.y = UTIL_VecToAngles(-pev->velocity).y; - pev->v_angle.y = pev->angles.y; + pev->angles.y = UTIL_VecToAngles(-pev->velocity).y; + pev->v_angle.y = pev->angles.y; - m_iThrowDirection = THROW_NONE; - } + m_iThrowDirection = THROW_NONE; + } - m_iClientHealth = 0; - MESSAGE_BEGIN(MSG_ONE, gmsgHealth, nullptr, pev); - WRITE_BYTE(m_iClientHealth); - MESSAGE_END(); + m_iClientHealth = 0; + MESSAGE_BEGIN(MSG_ONE, gmsgHealth, nullptr, pev); + WRITE_BYTE(m_iClientHealth); + MESSAGE_END(); - MESSAGE_BEGIN(MSG_ONE, gmsgCurWeapon, nullptr, pev); - WRITE_BYTE(0); - WRITE_BYTE(0xFF); - WRITE_BYTE(0xFF); - MESSAGE_END(); + MESSAGE_BEGIN(MSG_ONE, gmsgCurWeapon, nullptr, pev); + WRITE_BYTE(0); + WRITE_BYTE(0xFF); + WRITE_BYTE(0xFF); + MESSAGE_END(); - SendFOV(0); + SendFOV(0); - CSGameRules()->CheckWinConditions(); - m_bNotKilled = false; + CSGameRules()->CheckWinConditions(); + m_bNotKilled = false; - BuyZoneIcon_Clear(this); + BuyZoneIcon_Clear(this); -#ifdef REGAMEDLL_ADD - CSPlayer()->OnKilled(); -#endif + #ifdef REGAMEDLL_ADD + CSPlayer()->OnKilled(); + #endif - SetThink(&CBasePlayer::PlayerDeathThink); - pev->nextthink = gpGlobals->time + 0.1f; - pev->solid = SOLID_NOT; + SetThink(&CBasePlayer::PlayerDeathThink); + pev->nextthink = gpGlobals->time + 0.1f; + pev->solid = SOLID_NOT; - if ((pev->health < -9000 && iGib != GIB_NEVER) || iGib == GIB_ALWAYS) - { + if ((pev->health < -9000 && iGib != GIB_NEVER) || iGib == GIB_ALWAYS) + { -#ifndef REGAMEDLL_FIXES - pev->solid = SOLID_NOT; -#endif - GibMonster(); - pev->effects |= EF_NODRAW; + #ifndef REGAMEDLL_FIXES + pev->solid = SOLID_NOT; + #endif + GibMonster(); + pev->effects |= EF_NODRAW; -#ifndef REGAMEDLL_FIXES - CSGameRules()->CheckWinConditions(); -#endif - return; - } + #ifndef REGAMEDLL_FIXES + CSGameRules()->CheckWinConditions(); + #endif + return; + } - DeathSound(); + DeathSound(); - pev->angles.x = 0; - pev->angles.z = 0; - } -*/ + pev->angles.x = 0; + pev->angles.z = 0; + } + */ auto Player::init(PlayerBase* base) -> void { edict_ = base->GetEdict(); vars_ = &edict_->vars; @@ -321,24 +319,63 @@ namespace rz chain->CallNext(base); return; } - if (gameRules->isCanMove()) { + if (GameRules.isCanMove()) { player.setIUser3(player.getIUser3() & ~NO_MOVE_PLAYER_FLAGS); } - auto newClass = gameRules->defaultPlayerClass(Team::Human); - if (gameRules->getGameState() == GameState::Playing && gameRules->getRoundState() == RoundState::Playing) { - newClass = gameRules->defaultPlayerClass(Team::Zombie); - } + const auto newClass = GameRules.defaultPlayerClass(GameRules.getRespawnTeam()); if (player.getClass() != newClass) { player.setKilled(true); player.setClass(newClass); } player.ChangeClass(player.getClass(), &player, true); + // check body for alive const auto body = player.getBody(); chain->CallNext(base); player.setBody(body); //player.setThirdCamera(true); } + auto Player_TakeDamage( + ReHookPlayerTakeDamage* chain, + PlayerBase* base, + EntityVars* inflictorVars, + EntityVars* attackerVars, + float& damage, + int damageType + ) -> qboolean { + const auto& weaponRef = Weapons[inflictorVars->impulse]; + if (weaponRef) { + const auto& weapon = weaponRef->get(); + if (weapon.getAlwaysDamage() != -1) { + damage = static_cast(weapon.getAlwaysDamage()); + } + } + return chain->CallNext(base, inflictorVars, attackerVars, damage, damageType); + } + + auto Player_Killed(ReHookPlayerKilled* chain, PlayerBase* base, EntityVars* attackerVars, int gib) -> void { + if (attackerVars && attackerVars != base->vars) { + const auto& attackerBase = EntityPrivateData(attackerVars->containing_entity); + if (attackerBase != nullptr) { + const auto& attacker = Players[attackerBase]; + const auto& activeItem = attacker.getActiveItem(); // to inflictor + if (activeItem != nullptr) { + const auto& weaponRef = Weapons[activeItem->vars->impulse]; + if (weaponRef) { + const auto& weapon = weaponRef->get(); + if (weapon.getGibs()) { + gib = GIB_ALWAYS; + } + } + } + } + } + chain->CallNext(base, attackerVars, gib); + auto& player = Players[base]; + player.setIUser1(ObserverMode::None); + //player.setThirdCamera(true); + } + auto Player_PreThink(ReHookPlayerPreThink* chain, PlayerBase* base) { chain->CallNext(base); auto& player = Players[base]; @@ -347,6 +384,7 @@ namespace rz if (!player.isAlive()) { return; } + player.WorldPreviewUpdate(); if (player.isFrozen() && player.getFreezeEndTime() <= g_global_vars->time) { player.RemoveFreeze(); } @@ -358,15 +396,16 @@ namespace rz auto& player = Players[base]; if (player.isAlive()) { if (player.getImpulse() == 100) { - player.SwitchFlashlight(!player.getFlashlight().isEnabled()); + player.SwitchFlashlight(!player.Flashlight().isEnabled()); player.setImpulse(0); } } chain->CallNext(base); + player.ThirdCameraUpdate(); if (!player.isAlive()) { return; } - player.ThirdCameraUpdate(); + player.JumpThink(); } auto Player_AddPlayerItem(ReHookPlayerAddPlayerItem*, PlayerBase* base, PlayerItemBase* item) -> qboolean { @@ -387,7 +426,7 @@ namespace rz } item->next = player.getPlayerItems(itemSlot); player.setPlayerItems(itemSlot, item); - if (gameRules->ShouldSwitchWeapon(player, item)) { + if (GameRules.ShouldSwitchWeapon(player, item)) { player.SwitchWeapon(item); } player.setHideHud(player.getHideHud() & ~HIDE_HUD_WEAPONS); @@ -451,12 +490,12 @@ namespace rz } auto Player_Jump(ReHookPlayerJump* chain, PlayerBase* base) -> void { - chain->CallNext(base); + //chain->CallNext(base); auto& player = Players[base]; if (player.getIUser3() & NO_MOVE_PLAYER_FLAGS) { return; } - player.ExtraJump(); + player.Jump(); player.LongJump(); } @@ -475,6 +514,17 @@ namespace rz // no op } + auto Player_Radio( + ReHookPlayerRadio* chain, + PlayerBase* base, + const char* message, + const char* messageVerbose, + short pitch, + bool showIcon + ) -> void { + // No op + } + auto Player_ResetMaxSpeed(ReHookPlayerResetMaxSpeed*, PlayerBase* base) -> void { auto& player = Players[base]; // if joining @@ -482,7 +532,7 @@ namespace rz player.setMaxSpeed(900); return; } - if (!gameRules->isCanMove() || player.isFrozen()) { + if (!GameRules.isCanMove() || player.isFrozen()) { player.setMaxSpeed(1); return; } @@ -494,15 +544,14 @@ namespace rz } } - auto Player_Pain(ReHookPlayerPain* chain, PlayerBase* base, HitBoxGroup lastHitGroup, bool hasArmour) - -> void { + auto Player_Pain(ReHookPlayerPain* chain, PlayerBase* base, HitBoxGroup lastHitGroup, bool hasArmour) -> void { const auto& player = Players[base]; const auto soundsRef = PlayerSounds[player.getSounds()]; if (!soundsRef) { chain->CallNext(base, lastHitGroup, hasArmour); return; } - const auto& sound = soundsRef->get(); + auto& sound = soundsRef->get(); if (lastHitGroup == HitBoxGroup::Head) { if (player.getHelmet()) { UTIL_EmitSound(player, SoundChannel::Voice, sound.getRandom(PlayerSoundType::ArmoredHead)); @@ -527,7 +576,7 @@ namespace rz chain->CallNext(base); return; } - const auto& sound = soundsRef->get(); + auto& sound = soundsRef->get(); UTIL_EmitSound(player, SoundChannel::Voice, sound.getRandom(PlayerSoundType::Death)); } @@ -563,7 +612,75 @@ namespace rz chain.CallNext(base); return; }*/ + } + auto Player_DeathThink(ReHookPlayerDeathThink* chain, PlayerBase* base) -> void { + auto& player = Players[base]; + if (player.getJoiningState() != JoinState::Joined) { + return; + } + if (player.getFlags() & FL_ON_GROUND) { + const float forward = player.getVelocity().Length() - 20; + if (forward <= 0) { + player.setVelocity(VECTOR_ZERO); + } else { + player.setVelocity(forward * player.getVelocity().Normalize()); + } + } + + if (player.hasWeapons()) { + player.forEachItem([&player](PlayerItem* item) { + if (item->CanDrop()) { + player.DropPlayerItem(item); + item->vars->velocity.x = RandomFloat(24.0, 64.0) * (RandomLong(0, 1) ? 1.f : -1.f); + item->vars->velocity.y = RandomFloat(24.0, 64.0) * (RandomLong(0, 1) ? 1.f : -1.f); + item->vars->velocity.z = RandomFloat(64.0, 128.0); + } + return false; + }); + player.RemoveAllItems(true); + player.setDeadTime(g_global_vars->time + 2); + sendBarTime(player, 2); + } + + if (player.getMoveType() != MoveTypeEntity::None && (player.getFlags() & FL_ON_GROUND)) { + player.setMoveType(MoveTypeEntity::None); + } + + auto angles = player.getAngles(); + angles.x = 0; + player.setAngles(angles); + + if (player.getDeadFlag() == DeathState::Dying) { + if (base->vars->model_index && !base->sequence_finished) { + auto interval = g_global_vars->time - base->vars->anim_time; + if (interval <= 0.001f) { + base->vars->anim_time = g_global_vars->time; + } else { + if (base->vars->anim_time == 0.f) { + interval = 0.f; + } + base->vars->frame += interval * base->frame_rate; + base->vars->anim_time = g_global_vars->time; + if (base->vars->frame >= 255.f) { + base->vars->frame = 255.f; + base->sequence_finished = true; + } + } + } else { + player.setDeadFlag(DeathState::Dead); + player.setEffects(player.getEffects() | EF_NO_INTERPOLATE); + } + } + if (player.getDeadTime() <= g_global_vars->time) { + if (GameRules.PlayerCanRespawn(player)) { + player.RoundRespawn(); + } else { + //if ({// && !(physics_flags & PFLAG_OBSERVER)) { + base->GetCsPlayer()->StartDeathCam(); + //} + } + } } auto InternalCommand(ReHookInternalCommand* chain, Edict* client, const char* command, const char* arg1) -> void { @@ -573,37 +690,32 @@ namespace rz chain->CallNext(client, command, arg1); } return; - } else if (str::Equals(command, "nightvision")) { - if (!player.isAlive() || !player.getNightVision().isEnabled()) { + } + if (str::Equals(command, "nightvision")) { + if (!player.isAlive() || !player.NightVision().getId()) { return; } - if (g_global_vars->time >= player.getLastCommandTime(TrackCommands::NightVision)) { - player.setLastCommandTime(TrackCommands::NightVision, g_global_vars->time + 0.3f); - player.SwitchNightVision(!player.getNightVision().isEnabled()); - } - return; - } else { - if (player.SelectItem(command)) { + if (g_global_vars->time < player.getLastCommandTime(TrackCommands::NightVision)) { return; } + player.setLastCommandTime(TrackCommands::NightVision, g_global_vars->time + 0.3f); + player.SwitchNightVision(!player.NightVision().isEnabled()); + return; + } + if (player.SelectItem(command)) { + return; } chain->CallNext(client, command, arg1); } - auto Player_Killed(ReHookPlayerKilled* chain, PlayerBase* victim, EntityVars* attacker, int gib) -> void { - chain->CallNext(victim, attacker, gib); - //victim->SetThink(&PlayerBaseWrapper::PlayerDeathThink); - auto& player = Players[victim]; - player.setIUser1(ObserverMode::None); - //player.setThirdCamera(true); - } - auto RegisterPlayerHooks() -> void { - auto hooks = regamedll_api::HookChains(); + auto* hooks = regamedll_api::HookChains(); hooks->InternalCommand()->RegisterHook(&InternalCommand); hooks->PlayerSpawn()->RegisterHook(&Player_Spawn); + hooks->PlayerTakeDamage()->RegisterHook(&Player_TakeDamage); + hooks->PlayerKilled()->RegisterHook(&Player_Killed); hooks->PlayerPreThink()->RegisterHook(&Player_PreThink); hooks->PlayerPostThink()->RegisterHook(&Player_PostThink); hooks->PlayerAddPlayerItem()->RegisterHook(&Player_AddPlayerItem); @@ -617,26 +729,13 @@ namespace rz hooks->PlayerUpdateClientData()->RegisterHook(&Player_UpdateClientData); hooks->PlayerImpulseCommands()->RegisterHook(&Player_ImpulseCommands); hooks->PlayerAddAccount()->RegisterHook(&Player_AddAccount); + hooks->PlayerRadio()->RegisterHook(&Player_Radio); hooks->PlayerPain()->RegisterHook(&Player_Pain); hooks->PlayerDeathSound()->RegisterHook(&Player_DeathSound); hooks->PlayerJoiningThink()->RegisterHook(&Player_JoiningThink); - - hooks->PlayerKilled()->RegisterHook(&Player_Killed); - } - - /* - auto Radio( - IReGameHook_CBasePlayer_Radio* chain, - CBasePlayer* basePlayer, - const char* message, - const char* messageVerbose, - short pitch, - bool showIcon - ) -> void { - // No op + hooks->PlayerDeathThink()->RegisterHook(&Player_DeathThink); } -*/ /*auto chooseAppearance(IReGameHook_HandleMenu_ChooseAppearance* chain, CBasePlayer* basePlayer, int slot) -> void { @@ -714,7 +813,7 @@ namespace rz if (!classRef) { return result; } - auto& playerClass = classRef->get(); + const auto& playerClass = classRef->get(); setClass(classId); setTeam(playerClass.getTeam()); setProps(playerClass.getProps()); @@ -773,14 +872,14 @@ namespace rz setProps(subclass.getProps()); setSounds(subclass.getSounds()); setMelee(subclass.getMelee()); - getNightVision().setId(0); + //getNightVision().setId(0); //switchFlashlight ChangeModel(subclass.getModel()); PlayerSubclassApi.ChangeSubclassPost(*this, subclassId); return result; } - auto Player::ChangeProps(int propsId, bool spawn) -> bool { + auto Player::ChangeProps(int propsId, bool isSpawn) -> bool { const auto propsRef = Props[propsId]; if (!propsRef) { return false; @@ -799,7 +898,7 @@ namespace rz setRenderColor(props.getRenderColor()); setRenderFx(props.getRenderFx()); SetFootSteps(props.getFootSteps()); - if (spawn) { + if (isSpawn) { GiveArmor(std::max(props.getArmor(), getArmor()), std::max(props.getHelmet(), getHelmet())); } else { GiveArmor(props.getArmor(), props.getHelmet()); diff --git a/rezombie/src/player/player_vars.cpp b/rezombie/src/player/player_vars.cpp index 6529325..b5255c8 100644 --- a/rezombie/src/player/player_vars.cpp +++ b/rezombie/src/player/player_vars.cpp @@ -1,7 +1,6 @@ #pragma once #include "rezombie/player/player.h" -#include "rezombie/player/api/player.h" namespace rz { @@ -14,11 +13,12 @@ namespace rz setMelee(0); //setNightVision(0); //setNightVisionEnabled(false); - getExtraJump().reset(); - getLongJump().reset(); + Jumps().reset(*this); + LongJump().reset(*this); setFreezeEndTime(0.f); if (isInit) { ResetSubclasses(); + Extras().reset(); } } diff --git a/rezombie/src/player/player_weapons.cpp b/rezombie/src/player/player_weapons.cpp index 29556e7..e3a9bcf 100644 --- a/rezombie/src/player/player_weapons.cpp +++ b/rezombie/src/player/player_weapons.cpp @@ -9,6 +9,7 @@ #include "rezombie/player/modules/player_props.h" #include #include +#include namespace rz { @@ -62,7 +63,7 @@ namespace rz if ((getWeapons() & ~(1 << WEAPON_SUIT)) == 0) { setHideHud(getHideHud() | HIDE_HUD_WEAPONS); } - gameRules->GetNextBestWeapon(*this, item); + GameRules.GetNextBestWeapon(*this, item); MakeVectors(getAngles()); item->vars->origin = getOrigin() + g_global_vars->vec_forward * 10; @@ -221,12 +222,12 @@ namespace rz } auto Player::GiveWeapon(int weaponIndex, GiveType giveType) -> EntityBase* { - auto weaponRef = Weapons[weaponIndex]; + const auto& weaponRef = Weapons[weaponIndex]; if (!weaponRef) { return nullptr; } auto& weapon = weaponRef->get(); - DropOrReplace(weapon.getInventorySlot(), giveType); + DropOrReplace(weapon.getSlot(), giveType); return CreateBaseWeapon(weaponIndex, weapon); } @@ -432,4 +433,78 @@ namespace rz SetOrigin(grenadeEntity, origin); return grenade; } + + auto MeleeDefaultAttack( + Player& player, + Knife* knife, + float damage, + float distance, + float backDamageMultiplier + ) -> MeleeAttackResult { + MakeVectors(player.getViewAngle()); + const auto direction = g_global_vars->vec_forward; + const auto src = player.getGunPosition(); + const auto end = src + direction * distance; + auto trace = TraceResult(); + //gpGlobals->trace_flags = FTRACE_KNIFE; + TraceLine(src, end, TR_IGNORE_NONE, player, &trace); +/* + if (trace.fraction >= 1.0f) { + //gpGlobals->trace_flags = FTRACE_KNIFE; + UTIL_TraceHull(vecSrc, vecEnd, TR_IGNORE_NONE, head_hull, m_pPlayer->edict(), &trace); + //gpGlobals->trace_flags = 0; + + if (trace.fraction < 1.0f) { + // Calculate the point of intersection of the line (or hull) and the object we hit + // This is and approximation of the "best" intersection + CBaseEntity* pHit = CBaseEntity::Instance(trace.pHit); + + if (!pHit || pHit->IsBSPModel()) { + FindHullIntersection(vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict()); + } + + // This is the point on the actual surface (the hull could have hit space) + vecEnd = trace.vecEndPos; + } + } +*/ + player.SetAnimation(PlayerAnim::Attack1); + if (trace.fraction >= 1.f) { + return MeleeAttackResult::Miss; + } + const auto entity = EntityPrivateData(trace.entity_hit); + if (backDamageMultiplier > 0.f) { + if (entity && entity->IsPlayer()) { + const auto los = Vector2D(direction.x, direction.y);//.Normalize(); + MakeVectors(entity->vars->angles); + const auto entityDirection = g_global_vars->vec_forward; + const auto entityLos = Vector2D(entityDirection.x, entityDirection.y); + const auto dot = los.DotProduct(entityLos); + if (dot > 0.8f) { + damage *= backDamageMultiplier; + } + MakeVectors(player.getViewAngle()); + } + } + regamedll_api::Funcs()->clear_multi_damage(); + entity->TraceAttack(player.getEntVars(), damage, direction, &trace, (DMG_NEVER_GIB | DMG_BULLET)); + regamedll_api::Funcs()->apply_multi_damage(player.getEntVars(), player.getEntVars()); + const auto classify = entity->GetClassify(); + if (classify != Classify::None && classify != Classify::Machine && classify != Classify::Vehicle) { + if (entity->IsAlive()) { + knife->trace_hit_ = trace; + player.setWeaponVolume(static_cast(0.1f * KNIFE_WALL_HIT_VOLUME)); + } else { + player.setWeaponVolume(static_cast(KNIFE_BODY_HIT_VOLUME)); + } + return MeleeAttackResult::Hit; + } + regamedll_api::Funcs()->texture_type_play_sound( + &trace, + src, + src + (end - src) * 2, + toInt(BulletType::PlayerCrowbar) + ); + return MeleeAttackResult::HitWall; + } } diff --git a/rezombie/src/player/players.cpp b/rezombie/src/player/players.cpp index f0e25dd..6d51afc 100644 --- a/rezombie/src/player/players.cpp +++ b/rezombie/src/player/players.cpp @@ -7,18 +7,30 @@ namespace rz using namespace vhooks; class PlayerVirtuals : public PlayerBase { - static VirtualHook playerOnCreate; - static VirtualHook botOnCreate; + static VirtualHook playerCreate; + static VirtualHook playerDestroy; + static VirtualHook botCreate; + static VirtualHook botDestroy; protected: auto create() -> void; + auto destroy() -> void; }; - VirtualHook PlayerVirtuals::playerOnCreate("player", HookIndex::OnCreate, &PlayerVirtuals::create); - VirtualHook PlayerVirtuals::botOnCreate("bot", HookIndex::OnCreate, &PlayerVirtuals::create); + VirtualHook PlayerVirtuals::playerCreate("player", HookIndex::OnCreate, &PlayerVirtuals::create); + VirtualHook PlayerVirtuals::botCreate("bot", HookIndex::OnCreate, &PlayerVirtuals::create); auto PlayerVirtuals::create() -> void { - playerOnCreate.Call(this); + playerCreate.Call(this); + link = new Extras(); Players[this].init(this); } + + VirtualHook PlayerVirtuals::playerDestroy("player", HookIndex::OnDestroy, &PlayerVirtuals::destroy); + VirtualHook PlayerVirtuals::botDestroy("bot", HookIndex::OnDestroy, &PlayerVirtuals::destroy); + + auto PlayerVirtuals::destroy() -> void { + delete link; + playerCreate.Call(this); + } } diff --git a/rezombie/src/player/third_camera.cpp b/rezombie/src/player/third_camera.cpp index 66e6e83..a74e9a5 100644 --- a/rezombie/src/player/third_camera.cpp +++ b/rezombie/src/player/third_camera.cpp @@ -1,5 +1,6 @@ #include "rezombie/player/player.h" #include "rezombie/thirdcamera/third_camera.h" +#include namespace rz { @@ -21,6 +22,8 @@ namespace rz float maxDistance; float maxRightOffset; + //metamod::utils::LogConsole("%.0f %.0f %.0f", getViewAngle().x, getViewAngle().y, getViewAngle().z); + bool isZooming; auto distance = 96.f;//gViewCamera[id][ViewCamera_Distance]; auto rightOffset = 0.f;//gViewCamera[id][ViewCamera_RightOffset]; diff --git a/rezombie/src/player/world_preview.cpp b/rezombie/src/player/world_preview.cpp deleted file mode 100644 index 4878233..0000000 --- a/rezombie/src/player/world_preview.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "rezombie/player/player.h" -#include "rezombie/player/world_preview.h" - -namespace rz -{ - auto Player::setWorldPreview(bool isEnabled) -> void { - auto& preview = getWorldPreviewVars(); - preview.setEnabled(isEnabled); - } - - auto Player::WorldPreviewUpdate() -> void { - auto& preview = getWorldPreviewVars(); - if (!preview.isEnabled()) { - return; - } - MakeVectors(getAngles()); - auto previewOrigin = getOrigin() + g_global_vars->vec_forward * WorldPreview.getViewForwardDistance(); - auto previewAngles = getAngles(); - preview.setOrigin(previewOrigin); - preview.setAngles(previewAngles); - } -} diff --git a/rezombie/src/modelpreview/api/model_preview.cpp b/rezombie/src/preview/api/join_preview.cpp similarity index 75% rename from rezombie/src/modelpreview/api/model_preview.cpp rename to rezombie/src/preview/api/join_preview.cpp index 10603d2..d5f579b 100644 --- a/rezombie/src/modelpreview/api/model_preview.cpp +++ b/rezombie/src/preview/api/join_preview.cpp @@ -1,6 +1,7 @@ -#include "rezombie/modelpreview/api/model_preview.h" +#include "rezombie/preview/api/join_preview.h" #include "rezombie/player/players.h" -#include +#include "rezombie/core/api/amxx_helper.h" +#include "amxx/api.h" namespace rz { @@ -34,11 +35,8 @@ namespace rz auto& player = Players[params[arg_player]]; const auto key = GetAmxString(amx, params[arg_var]); const auto& var = getMapValue(ModelPreviewVarsMap, key); - if (!var) { - // Invalid index - return false; - } - auto& preview = player.getPreviewVars(); + CHECK_VAR_EXISTS("Invalid model preview '%s' var", key) + auto& preview = player.getJoinPreviewVars(); switch (*var) { case vars::IsEnabled: { if (isGetter) { @@ -50,25 +48,25 @@ namespace rz } case vars::ParentModel: { if (isGetter) { - return preview.getModel(PreviewType::ParentModel); + return preview.getModel(JoinPreviewType::ParentModel); } else { - preview.setModel(PreviewType::ParentModel, *Address(amx, params[arg_3])); + preview.setModel(JoinPreviewType::ParentModel, *Address(amx, params[arg_3])); } break; } case vars::AttachModel: { if (isGetter) { - return preview.getModel(PreviewType::AttachModel); + return preview.getModel(JoinPreviewType::AttachModel); } else { - preview.setModel(PreviewType::AttachModel, *Address(amx, params[arg_3])); + preview.setModel(JoinPreviewType::AttachModel, *Address(amx, params[arg_3])); } break; } case vars::ExtraAttachModel: { if (isGetter) { - return preview.getModel(PreviewType::ExtraAttachModel); + return preview.getModel(JoinPreviewType::ExtraAttachModel); } else { - preview.setModel(PreviewType::ExtraAttachModel, *Address(amx, params[arg_3])); + preview.setModel(JoinPreviewType::ExtraAttachModel, *Address(amx, params[arg_3])); } break; } diff --git a/rezombie/src/preview/api/world_preview.cpp b/rezombie/src/preview/api/world_preview.cpp new file mode 100644 index 0000000..e3c012e --- /dev/null +++ b/rezombie/src/preview/api/world_preview.cpp @@ -0,0 +1,86 @@ +#include "rezombie/preview/api/world_preview.h" +#include "rezombie/core/api/amxx_helper.h" +#include "rezombie/player/players.h" +#include "rezombie/main/util.h" +#include + +namespace rz +{ + using namespace amx; + using namespace amxx; + + enum class RzWorldPreviewVars : int { + IsEnabled, + Model, + MaxDistance, + }; + + const std::unordered_map WorldPreviewVarsMap = { + {"enabled", RzWorldPreviewVars::IsEnabled}, + {"model", RzWorldPreviewVars::Model}, + {"max_distance", RzWorldPreviewVars::MaxDistance}, + }; + + auto HandleWorldPreviewVar(Amx* amx, cell* params, bool isGetter) -> cell { + enum { + arg_count, + arg_player, + arg_var, + arg_3, + }; + + using vars = RzWorldPreviewVars; + + const int playerId = params[arg_player]; + auto& player = Players[playerId]; + const auto key = GetAmxString(amx, params[arg_var]); + const auto& var = getMapValue(WorldPreviewVarsMap, key); + CHECK_VAR_EXISTS("Invalid world preview '%s' var", key) + auto& preview = player.getWorldPreviewVars(); + switch (*var) { + case vars::IsEnabled: { + if (isGetter) { + return preview.isEnabled(); + } else { + preview.setEnabled(*Address(amx, params[arg_3])); + } + break; + } + case vars::Model: { + if (isGetter) { + return preview.getModel(); + } else { + preview.setModel(*Address(amx, params[arg_3])); + } + break; + } + case vars::MaxDistance: { + if (isGetter) { + return preview.getMaxDistance(); + } else { + preview.setMaxDistance(*Address(amx, params[arg_3])); + } + break; + } + } + return true; + } + + auto get_world_preview_var(Amx* amx, cell* params) -> cell { + return HandleWorldPreviewVar(amx, params, true); + } + + auto set_world_preview_var(Amx* amx, cell* params) -> cell { + return HandleWorldPreviewVar(amx, params, false); + } + + auto AmxxWorldPreview::registerNatives() const -> void { + static AmxNativeInfo natives[] = { + {"get_world_preview_var", get_world_preview_var}, + {"set_world_preview_var", set_world_preview_var}, + + {nullptr, nullptr}, + }; + AddNatives(natives); + } +} diff --git a/rezombie/src/preview/join_preview.cpp b/rezombie/src/preview/join_preview.cpp new file mode 100644 index 0000000..bba275b --- /dev/null +++ b/rezombie/src/preview/join_preview.cpp @@ -0,0 +1,34 @@ +#include "rezombie/preview/join_preview.h" +#include "metamod/engine.h" +#include "metamod/gamedll.h" + +namespace rz +{ + using namespace cssdk; + using namespace metamod::engine; + + auto ModelPreview::createEntities() -> void { + auto entityClassName = AllocString("info_target"); + EntityVars* vars; + + setEntity(JoinPreviewType::ParentModel, UTIL_CreateNamedEntity(entityClassName)); + vars = &getEntity(JoinPreviewType::ParentModel)->vars; + vars->class_name = AllocString("preview_parent"); + vars->model_index = -1; + vars->effects = EF_BRIGHT_LIGHT; + + setEntity(JoinPreviewType::AttachModel, UTIL_CreateNamedEntity(entityClassName)); + vars = &getEntity(JoinPreviewType::AttachModel)->vars; + vars->class_name = AllocString("preview_attach"); + vars->model_index = -1; + vars->move_type = MoveTypeEntity::Follow; + vars->aim_entity = getEntity(JoinPreviewType::ParentModel); + + setEntity(JoinPreviewType::ExtraAttachModel, UTIL_CreateNamedEntity(entityClassName)); + vars = &getEntity(JoinPreviewType::ExtraAttachModel)->vars; + vars->class_name = AllocString("preview_extra_attach"); + vars->model_index = -1; + vars->move_type = MoveTypeEntity::Follow; + vars->aim_entity = getEntity(JoinPreviewType::ParentModel); + } +} diff --git a/rezombie/src/preview/world_preview.cpp b/rezombie/src/preview/world_preview.cpp new file mode 100644 index 0000000..d6f1bf0 --- /dev/null +++ b/rezombie/src/preview/world_preview.cpp @@ -0,0 +1,39 @@ +#include "rezombie/player/player.h" +#include "rezombie/preview/world_preview.h" + +namespace rz +{ + auto WorldPreview::createEntity() -> void { + auto entityClassName = AllocString("info_target"); + EntityVars* vars; + + setEntity(UTIL_CreateNamedEntity(entityClassName)); + vars = &getEntity()->vars; + vars->class_name = AllocString("world_preview"); + vars->model_index = -1; + vars->move_type = MoveTypeEntity::NoClip; + } + + auto Player::setWorldPreview(bool isEnabled) -> void { + auto& preview = getWorldPreviewVars(); + preview.setEnabled(isEnabled); + } + + auto Player::WorldPreviewUpdate() -> void { + auto& preview = getWorldPreviewVars(); + if (!preview.isEnabled()) { + return; + } + MakeVectors(getViewAngle()); + auto angles = getAngles(); + auto end = getGunPosition() + g_global_vars->vec_forward * static_cast(preview.getMaxDistance()); + TraceResult trace; + TraceLine(getGunPosition(), end, TR_IGNORE_MONSTERS, *this, &trace); + if (trace.fraction != 1.f) { + end = trace.end_position; + VecToAngles(trace.plane_normal, angles); + } + preview.setOrigin(end); + preview.setAngles(angles); + } +} diff --git a/rezombie/src/sounds/api/sounds.cpp b/rezombie/src/sounds/api/sounds.cpp new file mode 100644 index 0000000..23c09f3 --- /dev/null +++ b/rezombie/src/sounds/api/sounds.cpp @@ -0,0 +1,34 @@ +#include "rezombie/sounds/api/sounds.h" +#include "rezombie/sounds/sounds.h" +#include + +namespace rz +{ + using namespace amxx; + + auto play_ambience_sound(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_sound_path, + }; + + const auto soundPath = GetAmxString(amx, params[arg_sound_path]); + Sounds.playAmbienceSound(soundPath); + return true; + } + + auto stop_ambience_sound(Amx* amx, cell* params) -> cell { + Sounds.stopAmbienceSound(); + return true; + } + + auto AmxxSounds::registerNatives() const -> void { + static AmxNativeInfo natives[] = { + {"play_ambience_sound", play_ambience_sound}, + {"stop_ambience_sound", stop_ambience_sound}, + + {nullptr, nullptr}, + }; + AddNatives(natives); + } +} diff --git a/rezombie/src/sounds/sounds.cpp b/rezombie/src/sounds/sounds.cpp new file mode 100644 index 0000000..0c6cc67 --- /dev/null +++ b/rezombie/src/sounds/sounds.cpp @@ -0,0 +1,46 @@ +#include "rezombie/sounds/sounds.h" +#include "rezombie/player/players.h" +#include + +namespace rz +{ + auto Sounds::playAmbienceSound(const std::string& soundPath) -> void { + stopAmbienceSound(); + lastAmbienceSound_ = soundPath; + Players.forEachConnected([&soundPath](const auto& player) { + rehlds_api::Funcs()->sv_emit_sound2( + player, + player, + SoundChannel::Auto, + soundPath.c_str(), + VOL_NORM, + ATTN_NORM, + 0, + PITCH_NORM, + 0, + nullptr + ); + }); + } + + auto Sounds::stopAmbienceSound() -> void { + if (lastAmbienceSound_.empty()) { + return; + } + Players.forEachConnected([this](const auto& player) { + rehlds_api::Funcs()->sv_emit_sound2( + player, + player, + SoundChannel::Auto, + lastAmbienceSound_.c_str(), + VOL_NORM, + ATTN_NORM, + SND_STOP, + PITCH_NORM, + 0, + nullptr + ); + }); + lastAmbienceSound_.clear(); + } +} diff --git a/rezombie/src/thirdcamera/api/third_camera.cpp b/rezombie/src/thirdcamera/api/third_camera.cpp index c53f7c2..9aec9e7 100644 --- a/rezombie/src/thirdcamera/api/third_camera.cpp +++ b/rezombie/src/thirdcamera/api/third_camera.cpp @@ -43,25 +43,25 @@ namespace rz switch (*value) { case var::ParentModel: { if (isGetter) { - return preview->getModel(PreviewType::ParentModel); + return preview->getModel(JoinPreviewType::ParentModel); } else { - preview->setModel(PreviewType::ParentModel, *Address(amx, params[arg_3])); + preview->setModel(JoinPreviewType::ParentModel, *Address(amx, params[arg_3])); } break; } case var::AttachModel: { if (isGetter) { - return preview->getModel(PreviewType::AttachModel); + return preview->getModel(JoinPreviewType::AttachModel); } else { - preview->setModel(PreviewType::AttachModel, *Address(amx, params[arg_3])); + preview->setModel(JoinPreviewType::AttachModel, *Address(amx, params[arg_3])); } break; } case var::ExtraAttachModel: { if (isGetter) { - return preview->getModel(PreviewType::ExtraAttachModel); + return preview->getModel(JoinPreviewType::ExtraAttachModel); } else { - preview->setModel(PreviewType::ExtraAttachModel, *Address(amx, params[arg_3])); + preview->setModel(JoinPreviewType::ExtraAttachModel, *Address(amx, params[arg_3])); } break; } diff --git a/rezombie/src/thirdcamera/third_camera.cpp b/rezombie/src/thirdcamera/third_camera.cpp index d588738..435ec3a 100644 --- a/rezombie/src/thirdcamera/third_camera.cpp +++ b/rezombie/src/thirdcamera/third_camera.cpp @@ -1,6 +1,5 @@ #include "rezombie/thirdcamera/third_camera.h" #include -#include namespace rz { @@ -15,5 +14,8 @@ namespace rz vars->class_name = AllocString("third_camera"); vars->model_index = PrecacheModel(AllocString("models/w_hegrenade.mdl"));//-1; vars->move_type = MoveTypeEntity::NoClip; + vars->render_mode = Rendering::TransAlpha; + vars->render_fx = RenderingFx::None; + vars->render_amount = 0; } } diff --git a/rezombie/src/weapons/api/melee.cpp b/rezombie/src/weapons/api/melee.cpp index b85e7ea..7731483 100644 --- a/rezombie/src/weapons/api/melee.cpp +++ b/rezombie/src/weapons/api/melee.cpp @@ -1,121 +1,63 @@ #include "rezombie/weapons/api/melee.h" #include "rezombie/player/players.h" -#include "amxx/api.h" +#include "rezombie/weapons/modules/weapon.h" +#include namespace rz { using namespace amxx; -/* - auto AMX_NATIVE_CALL rz_get_melee_var(Amx* amx, cell* params) -> cell - { - enum - { - arg_count, - arg_melee, - arg_var, - arg_3, - arg_4, - }; - const int meleeId = params[arg_melee]; - const auto meleeRef = meleeModule[meleeId]; - if (!meleeRef) { - // Invalid index - return false; - } - const auto& melee = meleeRef->get(); - using var = MeleeVars; - switch (static_cast(params[arg_var])) { - case var::Handle: { - SetAmxString(amx, params[arg_3], melee.getHandle().c_str(), params[arg_4]); - break; - } - case var::ViewModel: { - SetAmxString(amx, params[arg_3], melee.getViewModel().c_str(), params[arg_4]); - break; - } - case var::ModelsPack: { - SetAmxString(amx, params[arg_3], melee.getPlayerModel().c_str(), params[arg_4]); - break; - } - case var::WorldModel: { - SetAmxString(amx, params[arg_3], melee.getWorldModel().c_str(), params[arg_4]); - break; - } - case var::WeaponList: { - // TODO - break; - } - case var::Name: { - SetAmxString(amx, params[arg_3], melee.getName().c_str(), params[arg_4]); - break; - } - default: { - // Invalid WeaponVar - return false; - } - } - return true; + auto AmxxMelee::AttackPre(int player, MeleeAttackType type) const -> ForwardReturn { + return executeForward(MeleeForward::AttackPre, player, toInt(type)); + } + + auto AmxxMelee::AttackPost(int player, MeleeAttackType type, MeleeAttackResult result) const -> void { + executeForward(MeleeForward::AttackPost, player, toInt(type), toInt(result)); + } + + auto AmxxMelee::registerForwards() -> void { + using e = ForwardExecType; + using p = ForwardParam; + + setForward( + MeleeForward::AttackPre, + RegisterForward("@melee_attack_pre", e::Ignore, p::Cell, p::Cell, p::Done) + ); + setForward( + MeleeForward::AttackPost, + RegisterForward("@melee_attack_post", e::Ignore, p::Cell, p::Cell, p::Cell, p::Done) + ); } - auto AMX_NATIVE_CALL rz_set_melee_var(Amx* amx, cell* params) -> cell - { - enum - { + auto melee_add_sound(Amx* amx, cell* params) -> cell { + enum { arg_count, arg_melee, - arg_var, - arg_value, + arg_type, + arg_path, }; const int meleeId = params[arg_melee]; - const auto meleeRef = meleeModule[meleeId]; + const auto meleeRef = Weapons[meleeId]; if (!meleeRef) { // Invalid index return false; } - auto& melee = meleeRef->get(); - using var = MeleeVars; - switch (static_cast(params[arg_var])) { - case var::Handle: { - // Invalid set var - break; - } - case var::ViewModel: { - melee.setViewModel(GetAmxString(amx, params[arg_value])); - break; - } - case var::ModelsPack: { - melee.setPlayerModel(GetAmxString(amx, params[arg_value])); - break; - } - case var::WorldModel: { - melee.setWorldModel(GetAmxString(amx, params[arg_value])); - break; - } - case var::WeaponList: { - // TODO - break; - } - case var::Name: { - melee.setName(GetAmxString(amx, params[arg_value])); - break; - } - default: { - // Invalid WeaponVar - return false; - } + const auto& melee = dynamic_cast(&meleeRef->get()); + if (melee == nullptr) { + return false; } + const auto type = static_cast(params[arg_type]); + const auto path = GetAmxString(amx, params[arg_path]); + melee->add(type, path); return true; - }*/ + } - auto AmxxMelee::registerNatives() const -> void - { + auto AmxxMelee::registerNatives() const -> void { static AmxNativeInfo natives[] = { - //{"rz_get_melee_var", rz_get_melee_var}, - //{"rz_set_melee_var", rz_set_melee_var}, + {"melee_add_sound", melee_add_sound}, - {nullptr, nullptr }, + {nullptr, nullptr}, }; AddNatives(natives); } diff --git a/rezombie/src/weapons/api/weapons.cpp b/rezombie/src/weapons/api/weapons.cpp index 54ee443..406f3f5 100644 --- a/rezombie/src/weapons/api/weapons.cpp +++ b/rezombie/src/weapons/api/weapons.cpp @@ -1,18 +1,19 @@ #include "rezombie/weapons/api/weapon.h" #include "rezombie/weapons/modules/weapon.h" #include "rezombie/player/players.h" +#include "rezombie/core/api/amxx_helper.h" #include #include -#include namespace rz { - using namespace metamod::engine; using namespace amx; using namespace amxx; + using namespace metamod::engine; enum class WeaponVars : int { Handle, + Type, Name, ViewModel, PlayerModel, @@ -20,9 +21,11 @@ namespace rz Hud, MaxClip, MaxAmmo, - InventorySlot, + Slot, Weight, Flags, + AlwaysDamage, + Gibs, BaseAccuracy, CrosshairSize, ForwardDeploy, @@ -36,27 +39,30 @@ namespace rz }; const std::unordered_map WeaponVarsMap = { - {"handle", WeaponVars::Handle}, - {"name", WeaponVars::Name}, - {"view_model", WeaponVars::ViewModel}, - {"player_model", WeaponVars::PlayerModel}, - {"world_model", WeaponVars::WorldModel}, - {"hud", WeaponVars::Hud}, - {"max_clip", WeaponVars::MaxClip}, - {"max_ammo", WeaponVars::MaxAmmo}, - {"inventory_slot", WeaponVars::InventorySlot}, - {"weight", WeaponVars::Weight}, - {"flags", WeaponVars::Flags}, - {"base_accuracy", WeaponVars::BaseAccuracy}, - {"crosshair_size", WeaponVars::CrosshairSize}, - {"forward_deploy", WeaponVars::ForwardDeploy}, - {"forward_holster", WeaponVars::ForwardHolster}, - {"forward_max_speed", WeaponVars::ForwardMaxSpeed}, - {"forward_primary_attack", WeaponVars::ForwardPrimaryAttack}, + {"handle", WeaponVars::Handle}, + {"type", WeaponVars::Type}, + {"name", WeaponVars::Name}, + {"view_model", WeaponVars::ViewModel}, + {"player_model", WeaponVars::PlayerModel}, + {"world_model", WeaponVars::WorldModel}, + {"hud", WeaponVars::Hud}, + {"max_clip", WeaponVars::MaxClip}, + {"max_ammo", WeaponVars::MaxAmmo}, + {"slot", WeaponVars::Slot}, + {"weight", WeaponVars::Weight}, + {"flags", WeaponVars::Flags}, + {"always_damage", WeaponVars::AlwaysDamage}, + {"gibs", WeaponVars::Gibs}, + {"base_accuracy", WeaponVars::BaseAccuracy}, + {"crosshair_size", WeaponVars::CrosshairSize}, + {"forward_deploy", WeaponVars::ForwardDeploy}, + {"forward_holster", WeaponVars::ForwardHolster}, + {"forward_max_speed", WeaponVars::ForwardMaxSpeed}, + {"forward_primary_attack", WeaponVars::ForwardPrimaryAttack}, {"forward_secondary_attack", WeaponVars::ForwardSecondaryAttack}, - {"forward_reload", WeaponVars::ForwardReload}, - {"forward_idle", WeaponVars::ForwardIdle}, - {"forward_fire_remaining", WeaponVars::ForwardFireRemaining}, + {"forward_reload", WeaponVars::ForwardReload}, + {"forward_idle", WeaponVars::ForwardIdle}, + {"forward_fire_remaining", WeaponVars::ForwardFireRemaining}, }; auto create_weapon(Amx* amx, cell* params) -> cell { @@ -98,7 +104,8 @@ namespace rz return false; } auto& baseWeapon = weaponRef->get(); - const auto weapon = dynamic_cast(&baseWeapon); + const auto& weapon = dynamic_cast(&baseWeapon); + const auto& melee = dynamic_cast(&baseWeapon); switch (*var) { case vars::Handle: { if (isGetter) { @@ -108,6 +115,14 @@ namespace rz } break; } + case vars::Type: { + if (isGetter) { + return toInt(baseWeapon.getWeaponType()); + } else { + // Invalid set var + } + break; + } case vars::Name: { if (isGetter) { SetAmxString(amx, params[arg_3], baseWeapon.getName().c_str(), *Address(amx, params[arg_4])); @@ -164,11 +179,11 @@ namespace rz } break; } - case vars::InventorySlot: { + case vars::Slot: { if (isGetter) { - return toInt(baseWeapon.getInventorySlot()); + return toInt(baseWeapon.getSlot()); } else { - baseWeapon.setInventorySlot(static_cast(*Address(amx, params[arg_3]))); + baseWeapon.setSlot(static_cast(*Address(amx, params[arg_3]))); } break; } @@ -188,6 +203,22 @@ namespace rz } break; } + case vars::AlwaysDamage: { + if (isGetter) { + return baseWeapon.getAlwaysDamage(); + } else { + baseWeapon.setAlwaysDamage(*Address(amx, params[arg_3])); + } + break; + } + case vars::Gibs: { + if (isGetter) { + return baseWeapon.getGibs(); + } else { + baseWeapon.setGibs(*Address(amx, params[arg_3])); + } + break; + } case vars::BaseAccuracy: { if (weapon == nullptr) { return false; @@ -259,10 +290,18 @@ namespace rz if (isGetter) { return baseWeapon.getPrimaryAttackForward(); } else { - const auto primaryAttack = RegisterSpForwardByName( - amx, GetAmxString(amx, params[arg_3]), - p::Cell, p::Cell, p::Cell, p::Cell, p::Done - ); + int primaryAttack; + if (melee != nullptr) { + primaryAttack = RegisterSpForwardByName( + amx, GetAmxString(amx, params[arg_3]), + p::Cell, p::Cell, p::Done + ); + } else { + primaryAttack = RegisterSpForwardByName( + amx, GetAmxString(amx, params[arg_3]), + p::Cell, p::Cell, p::Cell, p::Cell, p::Done + ); + } if (primaryAttack == FORWARD_INVALID) { return false; } @@ -345,11 +384,100 @@ namespace rz return HandleWeaponVars(amx, params, false); } - auto weapon_begin(Amx*, cell*) -> cell { + auto is_weapon_extra_exists(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_weapon, + arg_type, + arg_key, + }; + + const int weaponId = params[arg_weapon]; + const auto& weaponRef = Weapons[weaponId]; + if (!weaponRef) { + // Invalid index + return false; + } + auto& weapon = weaponRef->get(); + const auto type = static_cast(params[arg_type]); + const auto key = GetAmxString(amx, params[arg_key]); + return weapon.getExtras().isKeyExists(type, key); + } + + auto HandleWeaponExtra(Amx* amx, cell* params, bool isGetter) -> cell { + enum { + arg_count, + arg_weapon, + arg_type, + arg_key, + arg_4, + arg_5, + }; + + const int weaponId = params[arg_weapon]; + const auto& weaponRef = Weapons[weaponId]; + if (!weaponRef) { + // Invalid index + return false; + } + auto& weapon = weaponRef->get(); + const auto type = static_cast(params[arg_type]); + const auto* key = GetAmxString(amx, params[arg_key], 0); + switch (type) { + case ExtraType::Int: { + auto& extra = weapon.getExtras().getInts(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid weapon extra '%s' var (int)", key) + return extra[key]; + } else { + extra[key] = *Address(amx, params[arg_4]); + } + break; + } + case ExtraType::Float: { + auto& extra = weapon.getExtras().getFloats(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid weapon extra '%s' var (float)", key) + return FloatToCell(extra[key]); + } else { + extra[key] = CellToFloat(*Address(amx, params[arg_4])); + } + break; + } + case ExtraType::String: { + auto& extra = weapon.getExtras().getStrings(); + if (isGetter) { + const auto& var = getMapValue(extra, key); + CHECK_VAR_EXISTS("Invalid weapon extra '%s' var (string)", key) + SetAmxString(amx, params[arg_4], extra[key].c_str(), *Address(amx, params[arg_5])); + } else { + extra[key] = GetAmxString(amx, params[arg_4], 1); + } + break; + } + } + return true; + } + + auto get_weapon_extra(Amx* amx, cell* params) -> cell { + return HandleWeaponExtra(amx, params, true); + } + + auto set_weapon_extra(Amx* amx, cell* params) -> cell { + return HandleWeaponExtra(amx, params, false); + } + + auto weapons_count(Amx*, cell*) -> cell { + return Weapons.count(); + } + + auto weapons_begin(Amx*, cell*) -> cell { return Weapons.begin(); } - auto weapon_end(Amx*, cell*) -> cell { + auto weapons_end(Amx*, cell*) -> cell { return Weapons.end(); } @@ -363,6 +491,23 @@ namespace rz return Weapons[handle]; } + auto is_weapon(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_weapon_entity, + }; + + const int weaponEntityIndex = params[arg_weapon_entity]; + const auto weaponEdict = EdictByIndex(weaponEntityIndex); + // CHECK_ENTITY + const int weaponId = weaponEdict->vars.impulse; + const auto weaponRef = Weapons[weaponId]; + if (!weaponRef) { + return 0; + } + return weaponId; + } + auto give_weapon(Amx* amx, cell* params) -> cell { enum { arg_count, @@ -523,8 +668,9 @@ namespace rz const auto originRef = Address(amx, params[arg_origin]); const auto velocityRef = Address(amx, params[arg_velocity]); const float actionTime = CellToFloat(params[arg_action_time]); - const Vector origin{CellToFloat(originRef[0]), CellToFloat(originRef[1]), CellToFloat(originRef[2])}; - const Vector velocity{CellToFloat(velocityRef[0]), CellToFloat(velocityRef[1]), CellToFloat(velocityRef[2])}; + const auto origin = Vector(CellToFloat(originRef[0]), CellToFloat(originRef[1]), CellToFloat(originRef[2])); + const auto velocity = Vector(CellToFloat(velocityRef[0]), CellToFloat(velocityRef[1]), + CellToFloat(velocityRef[2])); auto& player = Players[playerId]; const auto weaponEdict = EdictByIndex(weaponEntityIndex); const auto baseWeapon = EntityPrivateData(weaponEdict); @@ -532,25 +678,52 @@ namespace rz return grenade->EdictIndex(); } + auto melee_default_attack(Amx* amx, cell* params) -> cell { + enum { + arg_count, + arg_weapon_entity, + arg_player, + arg_damage, + arg_distance, + arg_back_damage_multiplier, + }; + + const int weaponEntityIndex = params[arg_weapon_entity]; + const int playerId = params[arg_player]; + const auto damage = static_cast(params[arg_damage]); + const auto distance = static_cast(params[arg_distance]); + const auto backDamageMultiplier = CellToFloat(params[arg_back_damage_multiplier]); + auto& player = Players[playerId]; + const auto weaponEdict = EdictByIndex(weaponEntityIndex); + const auto baseWeapon = EntityPrivateData(weaponEdict); + return toInt(MeleeDefaultAttack(player, baseWeapon, damage, distance, backDamageMultiplier)); + } + auto AmxxWeapon::registerNatives() const -> void { static AmxNativeInfo natives[] = { - {"create_weapon", create_weapon}, - {"get_weapon_var", get_weapon_var}, - {"set_weapon_var", set_weapon_var}, - {"weapon_begin", weapon_begin}, - {"weapon_end", weapon_end}, - {"find_weapon", find_weapon}, - - {"give_weapon", give_weapon}, - {"give_weapon_by_id", give_weapon_by_id}, - - {"weapon_default_deploy", weapon_default_deploy}, - {"weapon_default_reload", weapon_default_reload}, + {"create_weapon", create_weapon}, + {"get_weapon_var", get_weapon_var}, + {"set_weapon_var", set_weapon_var}, + {"is_weapon_extra_exists", is_weapon_extra_exists}, + {"get_weapon_extra", get_weapon_extra}, + {"set_weapon_extra", set_weapon_extra}, + {"weapons_count", weapons_count}, + {"weapons_begin", weapons_begin}, + {"weapons_end", weapons_end}, + {"find_weapon", find_weapon}, + + {"is_weapon", is_weapon}, + {"give_weapon", give_weapon}, + {"give_weapon_by_id", give_weapon_by_id}, + + {"weapon_default_deploy", weapon_default_deploy}, + {"weapon_default_reload", weapon_default_reload}, {"weapon_default_shotgun_reload", weapon_default_shotgun_reload}, - {"weapon_kick_back", weapon_kick_back}, - {"weapon_throw_grenade", weapon_throw_grenade}, + {"weapon_kick_back", weapon_kick_back}, + {"weapon_throw_grenade", weapon_throw_grenade}, + {"melee_default_attack", melee_default_attack}, - {nullptr, nullptr}, + {nullptr, nullptr}, }; AddNatives(natives); } diff --git a/rezombie/src/weapons/melee.cpp b/rezombie/src/weapons/melee.cpp index 03c3da9..bf0db9a 100644 --- a/rezombie/src/weapons/melee.cpp +++ b/rezombie/src/weapons/melee.cpp @@ -1,6 +1,8 @@ #include "rezombie/weapons/modules/weapon.h" #include "rezombie/weapons/melee.h" +#include "rezombie/weapons/api/melee.h" #include "rezombie/player/players.h" +#include "rezombie/messages/user_message.h" #include namespace rz @@ -8,6 +10,38 @@ namespace rz using namespace cssdk; using namespace vhooks; + VirtualHook MeleeVirtuals::addToPlayer( + WEAPON_MELEE, + HookIndex::Item_AddToPlayer, + &MeleeVirtuals::MeleeAddToPlayer + ); + + auto MeleeVirtuals::MeleeAddToPlayer(PlayerBase* base) -> qboolean { + const auto meleeRef = Weapons[vars->impulse]; + if (!meleeRef) { + return addToPlayer.Call(this, base); + } + const auto& melee = meleeRef->get(); + player = base; + auto& player = Players[base]; + const auto& itemInfo = GetCsPlayerItem()->item_info; + player.setWeapons(player.getWeapons() | (1 << toInt(itemInfo.id))); + sendWeaponList( + player, + melee.getHud().c_str(), + primary_ammo_type, + itemInfo.max_ammo1, + secondary_ammo_type, + itemInfo.max_ammo2, + itemInfo.slot, + itemInfo.position, + itemInfo.id, + itemInfo.flags + ); + sendWeapPickup(player, itemInfo.id); + return true; + } + VirtualHook MeleeVirtuals::deploy( WEAPON_MELEE, HookIndex::Item_Deploy, @@ -15,14 +49,42 @@ namespace rz ); auto MeleeVirtuals::MeleeDeploy() -> qboolean { - const auto meleeRef = Weapons[vars->impulse]; + const auto& meleeRef = Weapons[vars->impulse]; if (!meleeRef) { return deploy.Call(this); } - auto& melee = meleeRef->get(); - //EMIT_SOUND(m_pPlayer->edict(), CHAN_ITEM, "weapons/knife_deploy1.wav", 0.3, 2.4); - WeaponDefaultDeploy(Players[player], this, 3, "knife"); - return melee.executeDeploy(EdictIndex(), player->EdictIndex()); + bool result; + auto& owner = Players[player]; + auto& melee = dynamic_cast(meleeRef->get()); + if (melee.getDeployForward() != FORWARD_INVALID) { + result = melee.executeDeploy(EdictIndex(), owner); + } else { + result = WeaponDefaultDeploy(owner, this, KNIFE_DRAW, "knife"); + if (result) { + UTIL_EmitSound(GetEdict(), SoundChannel::Item, melee.getRandom(MeleeSound::Deploy)); + } + } + return result; + } + + VirtualHook MeleeVirtuals::maxSpeed( + WEAPON_MELEE, + HookIndex::Item_GetMaxSpeed, + &MeleeVirtuals::MeleeMaxSpeed + ); + + auto MeleeVirtuals::MeleeMaxSpeed() -> float { + const auto& meleeRef = Weapons[vars->impulse]; + if (!meleeRef) { + return maxSpeed.Call(this); + } + auto result = 250; + const auto& melee = meleeRef->get(); + if (melee.getMaxSpeedForward() == FORWARD_INVALID) { + const auto& owner = Players[player]; + result = melee.executeMaxSpeed(EdictIndex(), owner, player->fov); + } + return static_cast(result); } VirtualHook MeleeVirtuals::primaryAttack( @@ -32,14 +94,44 @@ namespace rz ); auto MeleeVirtuals::MeleePrimaryAttack() -> void { - const auto meleeRef = Weapons[vars->impulse]; + const auto& meleeRef = Weapons[vars->impulse]; if (!meleeRef) { primaryAttack.Call(this); return; } - auto& melee = meleeRef->get(); - primaryAttack.Call(this); - // melee.executePrimaryAttack(EdictIndex(), player->EdictIndex(), clip, player->ammo[primary_ammo_type]); + auto& owner = Players[player]; + auto result = MeleeAttackResult::Miss; + if (MeleeApi.AttackPre(owner, Primary) <= ForwardReturn::Continue) { + auto& melee = dynamic_cast(meleeRef->get()); + if (melee.getPrimaryAttackForward() != FORWARD_INVALID) { + result = melee.executeMeleePrimaryAttack(EdictIndex(), owner); + } else { + result = MeleeDefaultAttack(owner, dynamic_cast(this), 15, 32); + owner.SendWeaponAnim(RandomLong(KNIFE_MIDDLE_ATTACK1_HIT, KNIFE_MIDDLE_ATTACK2_HIT)); + switch (result) { + case MeleeAttackResult::Miss: { + next_primary_attack = 0.35f; + next_secondary_attack = 0.5f; + UTIL_EmitSound(GetEdict(), SoundChannel::Weapon, melee.getRandom(MeleeSound::Slash)); + break; + } + case MeleeAttackResult::Hit: { + next_primary_attack = 0.4f; + next_secondary_attack = 0.5f; + UTIL_EmitSound(GetEdict(), SoundChannel::Weapon, melee.getRandom(MeleeSound::Hit)); + break; + } + case MeleeAttackResult::HitWall: { + next_primary_attack = 0.4f; + next_secondary_attack = 0.5f; + UTIL_EmitSound(GetEdict(), SoundChannel::Item, melee.getRandom(MeleeSound::HitWall)); + break; + } + } + time_weapon_idle = 2.f; + } + } + MeleeApi.AttackPost(owner, Primary, result); } VirtualHook MeleeVirtuals::secondaryAttack( @@ -49,13 +141,146 @@ namespace rz ); auto MeleeVirtuals::MeleeSecondaryAttack() -> void { - const auto meleeRef = Weapons[vars->impulse]; + const auto& meleeRef = Weapons[vars->impulse]; if (!meleeRef) { secondaryAttack.Call(this); return; } - auto& melee = meleeRef->get(); - secondaryAttack.Call(this); - // melee.executeSecondaryAttack(EdictIndex(), player->EdictIndex(), weapon_state, player->fov); + auto& owner = Players[player]; + auto result = MeleeAttackResult::Miss; + if (MeleeApi.AttackPre(owner, Secondary) <= ForwardReturn::Continue) { + auto& melee = dynamic_cast(meleeRef->get()); + if (melee.getSecondaryAttackForward() != FORWARD_INVALID) { + result = melee.executeMeleeSecondaryAttack(EdictIndex(), owner); + } else { + result = MeleeDefaultAttack(owner, dynamic_cast(this), 65, 48, 3); + switch (result) { + case MeleeAttackResult::Miss: { + next_primary_attack = 1.f; + next_secondary_attack = 1.f; + owner.SendWeaponAnim(KNIFE_STAB_MISS); + UTIL_EmitSound(GetEdict(), SoundChannel::Weapon, melee.getRandom(MeleeSound::Slash)); + break; + } + case MeleeAttackResult::Hit: { + next_primary_attack = 1.1f; + next_secondary_attack = 1.1f; + owner.SendWeaponAnim(KNIFE_STAB_HIT); + UTIL_EmitSound(GetEdict(), SoundChannel::Weapon, melee.getRandom(MeleeSound::Stab)); + break; + } + case MeleeAttackResult::HitWall: { + next_primary_attack = 1.1f; + next_secondary_attack = 1.1f; + owner.SendWeaponAnim(KNIFE_STAB_HIT); + UTIL_EmitSound(GetEdict(), SoundChannel::Item, melee.getRandom(MeleeSound::HitWall)); + break; + } + } + time_weapon_idle = 2.f; + } + } + MeleeApi.AttackPost(owner, Secondary, result); } + + VirtualHook MeleeVirtuals::idle( + WEAPON_MELEE, + HookIndex::Weapon_WeaponIdle, + &MeleeVirtuals::MeleeIdle + ); + + auto MeleeVirtuals::MeleeIdle() -> void { + const auto& meleeRef = Weapons[vars->impulse]; + if (!meleeRef) { + idle.Call(this); + return; + } + auto& owner = Players[player]; + const auto& melee = meleeRef->get(); + if (melee.getIdleForward() != FORWARD_INVALID) { + melee.executeIdle(EdictIndex(), owner, time_weapon_idle); + } else { + ResetEmptySound(); + if (time_weapon_idle > 0.f) { + return; + } + time_weapon_idle = 20.f; + owner.SendWeaponAnim(KNIFE_IDLE); + } + } + + VirtualHook MeleeVirtuals::create( + WEAPON_MELEE, + HookIndex::OnCreate, + &MeleeVirtuals::MeleeCreate + ); + + auto MeleeVirtuals::MeleeCreate() -> void { + create.Call(this); + link = new Extras(); + } + + VirtualHook MeleeVirtuals::destroy( + WEAPON_MELEE, + HookIndex::OnDestroy, + &MeleeVirtuals::MeleeDestroy + ); + + auto MeleeVirtuals::MeleeDestroy() -> void { + delete link; + destroy.Call(this); + } + + /* + void FindHullIntersection(const Vector& vecSrc, TraceResult& tr, float* mins, float* maxs, Edict* pEntity) { + int i, j, k; + float distance; + float* minmaxs[2] = {mins, maxs}; + TraceResult tmpTrace; + Vector vecHullEnd = tr.end_position; + Vector vecEnd; + + distance = 1e6f; + + vecHullEnd = vecSrc + ((vecHullEnd - vecSrc) * 2); + //g_global_vars->trace_flags = FTRACE_KNIFE; + TraceLine(vecSrc, vecHullEnd, TR_IGNORE_NONE, pEntity, &tmpTrace); + + if (tmpTrace.fraction < 1.0f) { + tr = tmpTrace; + return; + } + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < 2; k++) { + vecEnd.x = vecHullEnd.x + minmaxs[i][0]; + vecEnd.y = vecHullEnd.y + minmaxs[j][1]; + vecEnd.z = vecHullEnd.z + minmaxs[k][2]; + + //gpGlobals->trace_flags = FTRACE_KNIFE; + TraceLine(vecSrc, vecEnd, TR_IGNORE_NONE, pEntity, &tmpTrace); + + if (tmpTrace.fraction < 1.0f) { + auto thisDistance = (tmpTrace.end_position - vecSrc).Length(); + + if (thisDistance < distance) { + tr = tmpTrace; + distance = thisDistance; + } + } + } + } + } + } + + void CKnife::WeaponIdle() { + ResetEmptySound(); + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) + return; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 20.0f; + SendWeaponAnim(KNIFE_IDLE, UseDecrement() != FALSE); + } + */ } diff --git a/rezombie/src/weapons/weapons.cpp b/rezombie/src/weapons/weapons.cpp index 8f864ab..482aad0 100644 --- a/rezombie/src/weapons/weapons.cpp +++ b/rezombie/src/weapons/weapons.cpp @@ -20,11 +20,11 @@ namespace rz auto WeaponVirtuals::HolderSpawn() -> void { spawn.Call(this); - const auto weaponRef = Weapons[vars->impulse]; + const auto& weaponRef = Weapons[vars->impulse]; if (!weaponRef) { return; } - const auto itemInfo = GetCsPlayerItem()->item_info; + const auto& itemInfo = GetCsPlayerItem()->item_info; id = itemInfo.id; clip = itemInfo.max_clip; primary_ammo_type = toInt(itemInfo.id); @@ -37,15 +37,15 @@ namespace rz &WeaponVirtuals::HolderAddToPlayer ); - auto WeaponVirtuals::HolderAddToPlayer(PlayerBase* basePlayer) -> qboolean { + auto WeaponVirtuals::HolderAddToPlayer(PlayerBase* base) -> qboolean { const auto weaponRef = Weapons[vars->impulse]; if (!weaponRef) { - return addToPlayer.Call(this, basePlayer); + return addToPlayer.Call(this, base); } const auto& weapon = weaponRef->get(); - player = basePlayer; - auto& player = Players[basePlayer]; - auto itemInfo = GetCsPlayerItem()->item_info; + player = base; + auto& player = Players[base]; + const auto& itemInfo = GetCsPlayerItem()->item_info; player.setWeapons(player.getWeapons() | (1 << toInt(itemInfo.id))); sendWeaponList( player, @@ -70,14 +70,14 @@ namespace rz ); auto WeaponVirtuals::HolderGetItemInfo(ItemInfo* info) -> qboolean { - const auto weaponRef = Weapons[vars->impulse]; + const auto& weaponRef = Weapons[vars->impulse]; if (!weaponRef) { return getItemInfo.Call(this, info); } - auto& weapon = weaponRef->get(); + const auto& weapon = weaponRef->get(); const auto fakeId = static_cast(vars->i_user1); id = fakeId; - info->slot = toInt(weapon.getInventorySlot()) - 1; + info->slot = toInt(weapon.getSlot()) - 1; info->position = regamedll_api::GetItemInfo(fakeId)->position; info->ammo1 = nullptr; info->max_ammo1 = weapon.getMaxAmmo(); @@ -98,17 +98,17 @@ namespace rz ); auto WeaponVirtuals::HolderDeploy() -> qboolean { - const auto weaponRef = Weapons[vars->impulse]; + const auto& weaponRef = Weapons[vars->impulse]; if (!weaponRef) { return deploy.Call(this); } - auto& weapon = weaponRef->get(); - auto& player = Players[this->player]; - auto isDeployed = weapon.executeDeploy(EdictIndex(), player); - if (isDeployed) { + const auto& weapon = weaponRef->get(); + const auto& player = Players[this->player]; + const auto result = weapon.executeDeploy(EdictIndex(), player); + if (result) { vars->effects &= ~EF_NO_DRAW; } - return isDeployed; + return result; } VirtualHook WeaponVirtuals::holster( @@ -118,12 +118,12 @@ namespace rz ); auto WeaponVirtuals::HolderHolster(int skipLocal) -> void { - const auto weaponRef = Weapons[vars->impulse]; + const auto& weaponRef = Weapons[vars->impulse]; if (!weaponRef) { holster.Call(this, skipLocal); return; } - auto& weapon = weaponRef->get(); + const auto& weapon = weaponRef->get(); auto& player = Players[this->player]; in_reload = false; vars->effects |= EF_NO_DRAW; @@ -138,8 +138,8 @@ namespace rz &WeaponVirtuals::HolderAttachToPlayer ); - auto WeaponVirtuals::HolderAttachToPlayer(PlayerBase* basePlayer) -> void { - const auto& player = Players[basePlayer]; + auto WeaponVirtuals::HolderAttachToPlayer(PlayerBase* base) -> void { + const auto& player = Players[base]; vars->move_type = MoveTypeEntity::Follow; vars->solid = SolidType::NotSolid; vars->aim_entity = player; @@ -158,38 +158,39 @@ namespace rz &WeaponVirtuals::HolderUpdateClientData ); - auto WeaponVirtuals::HolderUpdateClientData(PlayerBase* basePlayer) -> qboolean { + // TODO: why? + auto WeaponVirtuals::HolderUpdateClientData(PlayerBase* base) -> qboolean { const auto weaponRef = Weapons[vars->impulse]; if (!weaponRef) { - return updateClientData.Call(this, basePlayer); + return updateClientData.Call(this, base); } - const auto& player = Players[basePlayer]; + const auto& player = Players[base]; auto send = false; auto state = 0; const PlayerItemBase* activeItem = player.getActiveItem(); if (activeItem == this) { - state = basePlayer->on_target ? WEAPON_IS_ON_TARGET : 1; + state = base->on_target ? WEAPON_IS_ON_TARGET : 1; } - if (!basePlayer->weapon) { + if (!base->weapon) { send = true; } - if (activeItem == this || basePlayer->client_active_item == this) { - if (activeItem != basePlayer->client_active_item) { + if (activeItem == this || base->client_active_item == this) { + if (activeItem != base->client_active_item) { send = true; } } if (clip != client_clip || state != client_weapon_state || - static_cast(basePlayer->field_of_view) != basePlayer->client_fov) { + static_cast(base->field_of_view) != base->client_fov) { send = true; } if (send) { sendCurWeapon(player, state, id, clip); client_clip = clip; client_weapon_state = state; - basePlayer->weapon = true; + base->weapon = true; } if (next) { - next->UpdateClientData(basePlayer); + next->UpdateClientData(base); } return true; } @@ -205,7 +206,7 @@ namespace rz if (!weaponRef) { return maxSpeed.Call(this); } - auto& weapon = weaponRef->get(); + const auto& weapon = weaponRef->get(); return static_cast(weapon.executeMaxSpeed(EdictIndex(), player->EdictIndex(), player->fov)); } @@ -216,12 +217,12 @@ namespace rz ); auto WeaponVirtuals::HolderItemSlot() -> InventorySlot { - const auto weaponRef = Weapons[vars->impulse]; + const auto& weaponRef = Weapons[vars->impulse]; if (!weaponRef) { return itemSlot.Call(this); } - auto& weapon = weaponRef->get(); - return weapon.getInventorySlot(); + const auto& weapon = weaponRef->get(); + return weapon.getSlot(); } VirtualHook WeaponVirtuals::primaryAttack( @@ -231,12 +232,12 @@ namespace rz ); auto WeaponVirtuals::HolderPrimaryAttack() -> void { - const auto weaponRef = Weapons[vars->impulse]; + const auto& weaponRef = Weapons[vars->impulse]; if (!weaponRef) { primaryAttack.Call(this); return; } - auto& weapon = weaponRef->get(); + const auto& weapon = weaponRef->get(); weapon.executePrimaryAttack(EdictIndex(), player->EdictIndex(), clip, player->ammo[primary_ammo_type]); } @@ -247,12 +248,12 @@ namespace rz ); auto WeaponVirtuals::HolderSecondaryAttack() -> void { - const auto weaponRef = Weapons[vars->impulse]; + const auto& weaponRef = Weapons[vars->impulse]; if (!weaponRef) { secondaryAttack.Call(this); return; } - auto& weapon = weaponRef->get(); + const auto& weapon = weaponRef->get(); weapon.executeSecondaryAttack(EdictIndex(), player->EdictIndex(), weapon_state, player->fov); } @@ -263,12 +264,12 @@ namespace rz ); auto WeaponVirtuals::HolderReload() -> void { - const auto weaponRef = Weapons[vars->impulse]; + const auto& weaponRef = Weapons[vars->impulse]; if (!weaponRef) { reload.Call(this); return; } - auto& weapon = weaponRef->get(); + const auto& weapon = weaponRef->get(); weapon.executeReload(EdictIndex(), player->EdictIndex()); } @@ -279,12 +280,12 @@ namespace rz ); auto WeaponVirtuals::HolderIdle() -> void { - const auto weaponRef = Weapons[vars->impulse]; + const auto& weaponRef = Weapons[vars->impulse]; if (!weaponRef) { idle.Call(this); return; } - auto& weapon = weaponRef->get(); + const auto& weapon = weaponRef->get(); weapon.executeIdle(EdictIndex(), player->EdictIndex(), time_weapon_idle); } @@ -386,7 +387,7 @@ namespace rz (itemInfo.max_clip == WEAPON_NO_CLIP && !player->ammo[primary_ammo_type])) { fire_on_empty = true; } - if (player->can_shoot && gameRules->isCanMove()) { + if (player->can_shoot && GameRules.isCanMove()) { if (player->vars->water_level == 3 && (itemInfo.flags & ITEM_FLAG_NO_FIRE_UNDER_WATER)) { PlayEmptySound(); next_primary_attack = 0.15f; @@ -431,4 +432,26 @@ namespace rz } // HandleInfiniteAmmo(); } + + VirtualHook WeaponVirtuals::create( + WEAPON_PLACEHOLDER, + HookIndex::OnCreate, + &WeaponVirtuals::HolderCreate + ); + + auto WeaponVirtuals::HolderCreate() -> void { + create.Call(this); + link = new Extras(); + } + + VirtualHook WeaponVirtuals::destroy( + WEAPON_PLACEHOLDER, + HookIndex::OnDestroy, + &WeaponVirtuals::HolderDestroy + ); + + auto WeaponVirtuals::HolderDestroy() -> void { + delete link; + destroy.Call(this); + } } diff --git a/rezombie/src/wrappers/player_base_wrapper.cpp b/rezombie/src/wrappers/player_base_wrapper.cpp deleted file mode 100644 index e3a2d5c..0000000 --- a/rezombie/src/wrappers/player_base_wrapper.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "rezombie/entity/wrappers/player_base_wrapper.h" -#include "rezombie/gamerules/game_rules.h" -#include "rezombie/player/players.h" -#include "rezombie/player/modules/player_props.h" - -namespace rz -{ - auto PlayerBaseWrapper::PlayerDeathThink() -> void { - vars->dead_flag = DeathState::Alive; - return; - if (joining_state != JoinState::Joined) { - return; - } - if (vars->flags & FL_ON_GROUND) { - const float forward = vars->velocity.Length() - 20; - if (forward <= 0) { - vars->velocity = VECTOR_ZERO; - } else { - vars->velocity = forward * vars->velocity.Normalize(); - } - } - - if (HasWeapons()) { - GetCsPlayer()->RemoveAllItems(true); - //PackDeadPlayerItems(); - } - - vars->angles.x = 0; - - if (vars->model_index && !sequence_finished && vars->dead_flag == DeathState::Dying) { - //StudioFrameAdvance(); - return; - } - - if (vars->move_type != MoveTypeEntity::None && (vars->flags & FL_ON_GROUND)) { - vars->move_type = MoveTypeEntity::None; - } - - if (vars->dead_flag == DeathState::Dying) { - dead_time = g_global_vars->time; - vars->dead_flag = DeathState::Dead; - } - - //StopAnimation(); - vars->effects |= EF_NO_INTERPOLATE; -/* - if (vars->dead_flag != DeathState::Respawnable) { - if (HasTimePassedSinceDeath(CGameRules::GetDyingTime()) && !(physics_flags & PFLAG_OBSERVER)) { - StartDeathCam(); - } - } -*/ - if (vars->dead_flag == DeathState::Dead && team != TeamName::Unassigned && team != TeamName::Spectator) { - if (gameRules->PlayerCanRespawn(this)) { - //if (forcerespawn.value <= 0 || (m_iTeam != CT && m_iTeam != TERRORIST)) { - vars->dead_flag = DeathState::Respawnable; - //} - } - vars->next_think = g_global_vars->time + 0.1f; - return; - } - - if (vars->dead_flag == DeathState::Respawnable) { - /*if (GetObserverMode() != OBS_NONE && (m_iTeam == UNASSIGNED || m_iTeam == SPECTATOR)) { - return; - } - if (m_iMenu == Menu_ChooseAppearance || m_iJoiningState == SHOWTEAMSELECT) { - return; - }*/ - Spawn(); - vars->button = 0; - vars->next_think = -1; - } - } - - auto PlayerBaseWrapper::HasWeapons() -> bool { - for (const auto& item: player_items) { - if (item) { - return true; - } - } - return false; - } -} diff --git a/rezombie/src/wrappers/player_item_wrapper.cpp b/rezombie/src/wrappers/player_item_wrapper.cpp index b071458..799895e 100644 --- a/rezombie/src/wrappers/player_item_wrapper.cpp +++ b/rezombie/src/wrappers/player_item_wrapper.cpp @@ -35,7 +35,7 @@ namespace rz } AttachToPlayer(player); UTIL_EmitSound(player, SoundChannel::Item, "items/gunpickup2.wav"); - if (player.getActiveItem() != this && gameRules->ShouldSwitchWeapon(player, this)) { + if (player.getActiveItem() != this && GameRules.ShouldSwitchWeapon(player, this)) { player.SwitchWeapon(this); } SetTouch(nullptr);