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<