PDA

Просмотр полной версии : [Мануал] Система достижений



L0ndl3m
12.06.2014, 14:27
Многие люди спрашивали как сделать систему достижения, сейчас я попробую показать как это делать.

Попробуем сделать систему достижений из 3 штук.

Достижения

Вынос мозга
Вершина мира
Маньяк


В начало мода, создадим глобально ( то есть ко всем new )



const
MAX_ACHIEVEMENT_NAME = 13,
DIALOG_ACHIEVEMENTS = 512,
DIALOG_ACHIEVEMENTS_EXP = 1024;

static const
achievement_names[][MAX_ACHIEVEMENT_NAME] =
{
"Вынос мозга", "Вершина мира", "Маньяк"
};

new
achievement[MAX_PLAYERS],
ach_progress[MAX_PLAYERS][2 char];

#if !defined BODY_PART_TORSO
enum
{
BODY_PART_TORSO = 3,
BODY_PART_GROIN,
BODY_PART_LEFT_ARM,
BODY_PART_RIGHT_ARM,
BODY_PART_LEFT_LEG,
BODY_PART_RIGHT_LEG,
BODY_PART_HEAD
};
#endif

enum(<<= 1)
{
ACHIEVEMENT_BRAINFUCK = 1,
ACHIEVEMENT_TOP_OF_THE_WORLD,
ACHIEVEMENT_MANIAC
};


Начнём с первого достижения: Вынос мозга.

Суть достижения заключается в том, чтобы за один сеанс игры убить 5 человек в голову.
Реализация будет выглядеть так: добавляем в public OnPlayerGiveDamage


if(damagedid != INVALID_PLAYER_ID && bodypart == BODY_PART_HEAD)
{
SetPlayerHealth(damagedid, 0.0);

if(((achievement[playerid] & ACHIEVEMENT_BRAINFUCK) == 0) && ++ach_progress[playerid]{0} == 5)
{
UnlockPlayerAchievement(playerid, 0);
GivePlayerMoney(playerid, 100000);
SendClientMessage(playerid, -1, "Вы получили вознаграждение: {FF0000}$100000");
}
}


Реализация первого достижения готова.

Теперь начнём со второго достижения: Вершина мира
Суть достижения заключается в том, чтобы залезть на вершину горы чиллиад (это самая высокая точка на карте).
Попытаемся реализовать достижение:

Добавляем в public OnGameModeInit:

SetTimer("@__achievement_update", 1000, 1);

В любое место в моде, можно ко всем public'ам:


@__achievement_update();
@__achievement_update()
{
new
i = GetMaxPlayers();

do
{
--i;
if(IsPlayerConnected(i) && (0 == (achievement[i] & ACHIEVEMENT_TOP_OF_THE_WORLD)) && IsPlayerInRangeOfPoint(i, 2.0, -2432.7881, -1620.0902, 526.8478))
{
UnlockPlayerAchievement(i, 1);
GivePlayerWeapon(i, 38, 150);
SendClientMessage(i, -1, "Вы получили: {FF0000}150 патронов к оружию Minigun");
}
}
while(i);
}


Реализация второго достижения готова.

Приступим к последнему, третьему достижению: Маньяк.
Суть достижения заключается в том, чтобы убить пятерых игроков лопастями вертолёта.

Реализуем достижение, добавив в public OnPlayerDeath:


if(reason == 50 && killerid != INVALID_PLAYER_ID && ((achievement[killerid] & ACHIEVEMENT_MANIAC) == 0) && ++ach_progress[killerid]{1} == 5)
{
UnlockPlayerAchievement(killerid, 2);
SetPlayerHealth(killerid, 500.0);
SendClientMessage(killerid, -1, "Вы получили: {FF0000}500 единиц здоровья.");
}


Реализация трёх достижений готова.

Создадим отдельный сток, который будет показывать какой игрок разблокировал достижение, в любое место скрипта (ко всем stock'ам):


stock UnlockPlayerAchievement(const playerid, const id)
{
achievement[playerid] |= 1 << id;

static const
fmt_str[] = "• {FF0000}%s (%i){AAAADD} разблокировал достижение: {FF0000}%s";

new
str[sizeof(fmt_str) - 2 + MAX_PLAYER_NAME - 2 + 3 - 2 + MAX_ACHIEVEMENT_NAME];

GetPlayerName(playerid, str, sizeof(str));

format(str, sizeof(str), fmt_str, str, playerid, achievement_names[id]);
SendClientMessageToAll(-1, str);
}


Добавим команду, в которой будет видно, разблокировал ли игрок какое-либо достижение:


CMD:achs(playerid, params[]) // if(strcmp(cmdtext, "/achs", true, 5) == 0)
{
return ShowPlayerAchievementsDialog(playerid);
}


В конец мода, функцию показа диалога:


ShowPlayerAchievementsDialog(const playerid)
{
static const
fmt_str[] = "\
1. Вынос мозга [%s{FFFFFF}]\n\
2. Вершина мира [%s{FFFFFF}]\n\
3. Маньяк [%s{FFFFFF}]",
lock_str[][] =
{
{"{FF0000}Заблокировано"},
{"{00CC00}Разблокировано"}
};

new
str[(sizeof(fmt_str) - 2 + 21) * sizeof(achievement_names)];

format
(
str, sizeof(str), fmt_str,
lock_str[(achievement[playerid] & ACHIEVEMENT_BRAINFUCK) != 0],
lock_str[(achievement[playerid] & ACHIEVEMENT_TOP_OF_THE_WORLD) != 0],
lock_str[(achievement[playerid] & ACHIEVEMENT_MANIAC) != 0]
);

return ShowPlayerDialog(playerid, DIALOG_ACHIEVEMENTS, DIALOG_STYLE_LIST, "Список достижений", str, "Выбрать", "Закрыть");
}


Добавим распознавание диалогов, в public OnDialogResponse:


if(dialogid == DIALOG_ACHIEVEMENTS) // case DIALOG_ACHIEVEMENTS:
{
if(response == 0)
return 1;

static const
achievement_explans[][] =
{
"Цель: Убить 5 игроков в голову за один сеанс игры\nНаграда: {FF0000}$100000",
"Цель: Залезть на вершину горы чиллиад (это самая высокая точка на карте)\nНаграда: {FF0000}150 патронов к оружию Minigun",
"Цель: Убить 5 игроков лопастями вертолёта за один сеанс игры\nНаграда: {FF0000}500 единиц здоровья"
};

return ShowPlayerDialog(playerid, DIALOG_ACHIEVEMENTS_EXP, DIALOG_STYLE_MSGBOX, "Описание достижения", achievement_explans[listitem], "Закрыть", "Назад");
}

if(dialogid == DIALOG_ACHIEVEMENTS_EXP) // case DIALOG_ACHIEVEMENTS_EXP:
{
return (response == 0) ? (ShowPlayerAchievementsDialog(playerid)) : (1);
}


С "игровой" частью мы справились. Осталось сделать сохранение достижении игрока, добавим в любое место в моде (ко всем stock'ам):


stock SavePlayerAchievements(const playerid)
{
if(PlayerInfo[playerid][pLogged] == 0)
return;
// Здесь вы выставляете свою проверку на логин игрока,
// если игрок не залогинен его достижения не сохранятся

static const
acc_str[] = "AchievementProgress/%s.ini";

new
str[sizeof(acc_str) - 2 + MAX_PLAYER_NAME];

GetPlayerName(playerid, str, sizeof(str));
format(str, sizeof(str), acc_str, str);

new
File: file = fopen(str, io_write);

if(file == File: 0)
return;

valstr(str, achievement[playerid]);

fwrite(file, str);

fclose(file);
}

stock LoadPlayerAchievements(const playerid)
{
static const
acc_str[] = "AchievementProgress/%s.ini";

new
str[sizeof(acc_str) - 2 + MAX_PLAYER_NAME];

GetPlayerName(playerid, str, sizeof(str));
format(str, sizeof(str), acc_str, str);

if(fexist(str) == 0)
return;

new
File: file = fopen(str, io_read);

if(file == File: 0)
return;

fread(file, str);

achievement[playerid] = strval(str);

fclose(file);
}


Добавляем сохранение достижений в public OnPlayerDisconnect:


SavePlayerAchievements(playerid);

ach_progress[playerid]{0} = 0;
ach_progress[playerid]{1} = 0;


Добавляем загрузку достижений туда, где у вас загружается аккаунт (например OnPlayerLogin):

LoadPlayerAchievements(playerid);

В общем-то и всё.


http://ihost.pro-pawn.ru/image.php?di=PEIX
http://ihost.pro-pawn.ru/image.php?di=CH1C
http://ihost.pro-pawn.ru/image.php?di=Y7CX



Автор: L0ndl3m (https://pro-pawn.ru/member.php?2057-L0ndl3m)

Специально для: Pro-Pawn.Ru (http://pro-pawn.ru)

Копирование данной статьи без разрешения автора запрещено!

somebodies
31.05.2017, 02:32
Приветствую! Проблема следующая:
Абсолютно никаким способом не открывается достижение под ID 0 , т.е "вынос мозга". UnlockPlayerAchievement(playerid, 0); не помогает в данном случае. (причем остальные достижения с ID > 0 открываются без проблем)

Также имеется маленькая проблема с сохранением, в .ini файл сохраняется лишь одна цифра, но достижений, как минимум, 3. где-то здесь кроется неполадка, как мне кажется.


какие могли возникнуть проблемы? код не изменял

заранее благодарю за помощь!

ziggi
31.05.2017, 07:30
Наверное, функция должна начинаться так:

stock UnlockPlayerAchievement(const playerid, const id)
{
achievement[playerid] |= 1 << id;

somebodies
31.05.2017, 15:51
Наверное, функция должна начинаться так:

stock UnlockPlayerAchievement(const playerid, const id)
{
achievement[playerid] |= 1 << id;

P.S. Почему ты не написал в той теме об этом?


Теперь все работает. Проблема с сохранением также решилась каким-то образом.