Daniel_Cortez
03.12.2019, 09:13
Что это такое?
Этот инклуд позволяет использовать псевдооператор switchrand() - аналог switch со случайным выполнением одного из кейсов (case).
Где это может понадобиться?
В любых системах, где нужно случайно выбрать один из кейсов в switch, и при этом нумерация в кейсах прерывается (например, "1, 2, 3, 6, 7").
Допустим, решили вы сделать пикап, который выдаёт случайный приз:
switch(random(6))
{
case 0:
{
new money = random(4000) + 1000;
GivePlayerMoney(playerid, money);
new string[14 + 4 + 1];
format(string, sizeof(string), "Вы получили $%d!", money);
SendClientMessage(playerid, -1, string);
}
case 1:
{
new money = random(2000) + 1000;
GivePlayerMoney(playerid, -money);
new string[14 + 4 + 1];
format(string, sizeof(string), "Вы потеряли $%d!", money);
SendClientMessage(playerid, -1, string);
}
case 2:
{
#if !defined FLOAT_INFINITY
const Float:FLOAT_INFINITY = Float:0x7F800000;
#endif
SetPlayerHealth(playerid, FLOAT_INFINITY);
SendClientMessage(playerid, -1, "Вы получили бессмертие (до респавна)!");
}
case 3:
{
GivePlayerWeapon(playerid, WEAPON_DEAGLE, 300);
SendClientMessage(playerid, -1, "Вы получили пистолет!");
}
case 4, 5:
{
new Float:x, Float:y, Float:z, Float:a;
GetPlayerPos(playerid, x, y, z);
GetPlayerFacingAngle(playerid, a);
new vehicleid = CreateVehicle(562, x, y, z, a, -1, -1, 1 * 60);
SetVehicleParamsEx(vehicleid,
VEHICLE_PARAMS_ON, VEHICLE_PARAMS_OFF, VEHICLE_PARAMS_OFF,
VEHICLE_PARAMS_OFF, VEHICLE_PARAMS_OFF, VEHICLE_PARAMS_OFF,
VEHICLE_PARAMS_OFF);
PutPlayerInVehicle(playerid, vehicleid, 0);
SendClientMessage(playerid, -1, "Вы получили а-а-а-втомобиль!");
}
}
И всё, вроде бы, хорошо, система работает, а игроки довольны. Но тут в одном из обновлений вам нужно убрать case 1, ибо игроки расстраиваются, когда у них отбирают деньги. Если вы просто удалите его - система не будет работать в 1 случае из 6, ибо random() всё ещё будет иногда выдавать единицу. Чтобы это исправить, придётся сделать что-то одно:
Объединить 1-й кейс с каким-то другим (например, case 0, 1:), но это фактически увеличит шанс выпадения другого приза.
Добавить какой-то новый приз вместо удалённого (придётся думать и писать новый код, что, естественно, большущий минус :mamba:).
Сместить номера всех кейсов, которые шли после единицы, + исправить значение в random().
Придумать костыль по типу добавления goto, который бы отправлял обработчик в позицию перед switch, дабы random() сгенерировало новое число.
И если на подобном switch с малым количеством кейсов все перечисленные пункты могут показаться незначительными, то представьте, что switch у вас состоит из 50, 100 и т.д. кейсов. В этом случае switchrand довольно сильно упростит поддержку кода, сняв с вас и нужду думать насчёт того, чтоб все кейсы были по порядку, и нужду в изменении значения, указанного в random() при изменении количества кейсов.
Ещё один пример ситуации - RP-мод с системой фракций (банд/мафий/организаций), в котором при выполнении какого-то задания нужно отправить игрока в одну из трёх армий. При этом так получилось, что ID армий в списке фракций - 2, 15, 22.
В случае со switchrand решение будет выглядеть примерно так:
switchrand()
{
case 2:
{
// ...
}
case 15:
{
// ...
}
case 22:
{
// ...
}
}
Без switchrand есть 2 варианта решения:
Поместить все нужные данные в массивы, определять рандомно индекс и уже отображать игроку нужную информацию из массивов согласно получившемуся индексу (но если у нас для каждой отдельной фракции нужно выполнить уникальный код, могут возникнуть проблемы. Да и в целом код получится довольно сложным и менее гибким относительно варианта switchrand).
Сделать нечто подобное:
new army_frac[] = {2, 15, 22};
new fid = army_frac[random(sizeof(army_frac))];
switch(fid)
{
case 2:
{
// ...
}
case 15:
{
// ...
}
case 22:
{
// ...
}
}
Но тут придётся следить за тем, чтоб значения в массиве и номера кейсов совпадали, что может быть проблематично (особенно в моменты когда кейсы наполнятся кодом и/или количество кейсов возрастёт).
Иными словами, главная задача switchrand - упростить работу со связкой "random + switch", избавив пользователя от рутинной задачи по слежению за номерами кейсов и числом в random().
Плюсы реализации:
Не требует наличия YSI, amx_assembly или каких-либо других сторонних инклудов.
Совместим с JIT.
Недостатки:
Из-за использования оператора __emit (необходимо для совместимости с JIT) инклуд совместим только с новыми версиями компилятора (3.10.6 и новее).
Использование
Просто подключите random_switch.inc и используйте макрос switchrand(), как если бы использовали оператор switch:
#include <a_samp>
#include <random_switch>
main()
{
switchrand()
{
case 0: print("case 0");
case 42: print("case 42");
case 84: print("case 84");
}
}
Скачать: https://www.dropbox.com/s/ew9px62sec6peu5/random_switch.zip?dl=1
Благодарности:
DeimoS - идея, примеры использования (http://pro-pawn.ru/showthread.php?16974&p=95520&viewfull=1#post95520).
VVWVV - изначальная реализация (http://pro-pawn.ru/showthread.php?16974&p=95511&viewfull=1#post95511).
История версий:
(03.12.2019) Первый релиз.
(05.12.2019) Добавлен обход проблемы с падением компилятора (баг специфичен для версий компилятора 3.10.7 - 3.10.9).
(31.12.2019) Оптимизирован код.
Этот инклуд позволяет использовать псевдооператор switchrand() - аналог switch со случайным выполнением одного из кейсов (case).
Где это может понадобиться?
В любых системах, где нужно случайно выбрать один из кейсов в switch, и при этом нумерация в кейсах прерывается (например, "1, 2, 3, 6, 7").
Допустим, решили вы сделать пикап, который выдаёт случайный приз:
switch(random(6))
{
case 0:
{
new money = random(4000) + 1000;
GivePlayerMoney(playerid, money);
new string[14 + 4 + 1];
format(string, sizeof(string), "Вы получили $%d!", money);
SendClientMessage(playerid, -1, string);
}
case 1:
{
new money = random(2000) + 1000;
GivePlayerMoney(playerid, -money);
new string[14 + 4 + 1];
format(string, sizeof(string), "Вы потеряли $%d!", money);
SendClientMessage(playerid, -1, string);
}
case 2:
{
#if !defined FLOAT_INFINITY
const Float:FLOAT_INFINITY = Float:0x7F800000;
#endif
SetPlayerHealth(playerid, FLOAT_INFINITY);
SendClientMessage(playerid, -1, "Вы получили бессмертие (до респавна)!");
}
case 3:
{
GivePlayerWeapon(playerid, WEAPON_DEAGLE, 300);
SendClientMessage(playerid, -1, "Вы получили пистолет!");
}
case 4, 5:
{
new Float:x, Float:y, Float:z, Float:a;
GetPlayerPos(playerid, x, y, z);
GetPlayerFacingAngle(playerid, a);
new vehicleid = CreateVehicle(562, x, y, z, a, -1, -1, 1 * 60);
SetVehicleParamsEx(vehicleid,
VEHICLE_PARAMS_ON, VEHICLE_PARAMS_OFF, VEHICLE_PARAMS_OFF,
VEHICLE_PARAMS_OFF, VEHICLE_PARAMS_OFF, VEHICLE_PARAMS_OFF,
VEHICLE_PARAMS_OFF);
PutPlayerInVehicle(playerid, vehicleid, 0);
SendClientMessage(playerid, -1, "Вы получили а-а-а-втомобиль!");
}
}
И всё, вроде бы, хорошо, система работает, а игроки довольны. Но тут в одном из обновлений вам нужно убрать case 1, ибо игроки расстраиваются, когда у них отбирают деньги. Если вы просто удалите его - система не будет работать в 1 случае из 6, ибо random() всё ещё будет иногда выдавать единицу. Чтобы это исправить, придётся сделать что-то одно:
Объединить 1-й кейс с каким-то другим (например, case 0, 1:), но это фактически увеличит шанс выпадения другого приза.
Добавить какой-то новый приз вместо удалённого (придётся думать и писать новый код, что, естественно, большущий минус :mamba:).
Сместить номера всех кейсов, которые шли после единицы, + исправить значение в random().
Придумать костыль по типу добавления goto, который бы отправлял обработчик в позицию перед switch, дабы random() сгенерировало новое число.
И если на подобном switch с малым количеством кейсов все перечисленные пункты могут показаться незначительными, то представьте, что switch у вас состоит из 50, 100 и т.д. кейсов. В этом случае switchrand довольно сильно упростит поддержку кода, сняв с вас и нужду думать насчёт того, чтоб все кейсы были по порядку, и нужду в изменении значения, указанного в random() при изменении количества кейсов.
Ещё один пример ситуации - RP-мод с системой фракций (банд/мафий/организаций), в котором при выполнении какого-то задания нужно отправить игрока в одну из трёх армий. При этом так получилось, что ID армий в списке фракций - 2, 15, 22.
В случае со switchrand решение будет выглядеть примерно так:
switchrand()
{
case 2:
{
// ...
}
case 15:
{
// ...
}
case 22:
{
// ...
}
}
Без switchrand есть 2 варианта решения:
Поместить все нужные данные в массивы, определять рандомно индекс и уже отображать игроку нужную информацию из массивов согласно получившемуся индексу (но если у нас для каждой отдельной фракции нужно выполнить уникальный код, могут возникнуть проблемы. Да и в целом код получится довольно сложным и менее гибким относительно варианта switchrand).
Сделать нечто подобное:
new army_frac[] = {2, 15, 22};
new fid = army_frac[random(sizeof(army_frac))];
switch(fid)
{
case 2:
{
// ...
}
case 15:
{
// ...
}
case 22:
{
// ...
}
}
Но тут придётся следить за тем, чтоб значения в массиве и номера кейсов совпадали, что может быть проблематично (особенно в моменты когда кейсы наполнятся кодом и/или количество кейсов возрастёт).
Иными словами, главная задача switchrand - упростить работу со связкой "random + switch", избавив пользователя от рутинной задачи по слежению за номерами кейсов и числом в random().
Плюсы реализации:
Не требует наличия YSI, amx_assembly или каких-либо других сторонних инклудов.
Совместим с JIT.
Недостатки:
Из-за использования оператора __emit (необходимо для совместимости с JIT) инклуд совместим только с новыми версиями компилятора (3.10.6 и новее).
Использование
Просто подключите random_switch.inc и используйте макрос switchrand(), как если бы использовали оператор switch:
#include <a_samp>
#include <random_switch>
main()
{
switchrand()
{
case 0: print("case 0");
case 42: print("case 42");
case 84: print("case 84");
}
}
Скачать: https://www.dropbox.com/s/ew9px62sec6peu5/random_switch.zip?dl=1
Благодарности:
DeimoS - идея, примеры использования (http://pro-pawn.ru/showthread.php?16974&p=95520&viewfull=1#post95520).
VVWVV - изначальная реализация (http://pro-pawn.ru/showthread.php?16974&p=95511&viewfull=1#post95511).
История версий:
(03.12.2019) Первый релиз.
(05.12.2019) Добавлен обход проблемы с падением компилятора (баг специфичен для версий компилятора 3.10.7 - 3.10.9).
(31.12.2019) Оптимизирован код.