Skocz do zawartości
MiloV

[Rozwiązane] Dodanie skrotu klawiszowego do pluginu.

Rekomendowane odpowiedzi

Witajcie, prowadzę serwer prop hunt a raczej próbuje i zmagam się z pewnym problemem. Dodałem do map rożne propy aby trochę urozmaicić i utrudnić grę, ale podczas spawnowania się na mapie czasami gracz pojawia się w modelu i blokuje. Stwierdziłem ze trzeba coś z tym zrobić, poszperałem w internetach - nie znalazłem nic co by odpowiadało moim oczekiwaniom. Wpadł pomysł aby napisać sam jakiś plugin, dlatego postawiłem ze najłatwiejsze co jestem w stanie osiągnąć to teleportacja gracza o jakieś sto jednostek nad siebie w celu odblokowania. To mój pierwszy plugin wiec mam parę pytań jeżeli jest ktoś mi chętny na nie odpowiedzieć.
Płynąc do brzegu: Jeżeli się da i nie zabolą was oczy od mojego kodu to prosił bym o wskazówki / przerobienie pluginu tak aby można było wprowadzić skrót klawiszowy dla gracza. Tak aby wciskając np. F +lookatweapon gracz uruchamiał moją komendę sm_ub.

Nie będę kłamał bo kod podpatrzyłem chyba z pięciu pluginów plus moje poprawki wiec wygląda to jak wygląda. 😄 Kursy magneta na razie pozwoliły na jakieś drobne poprawki 😄

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>
#include <multicolors>

Float:g_Location[33][3];
bool:g_use[33];
bool:g_tuse[33];

public Plugin:myinfo = 
{
	name = "Unblock",
	description = "Unblock !ub",
	version = "1.0",
}

public OnPluginStart()
{
	HookEvent("round_start",EventRoundStart, EventHookMode_Post);
	RegConsoleCmd("sm_ub", Cmd_unblock, "Unblock player.");
	
	for (new ID=1; ID<=MaxClients; ID++)
		{
		if (!IsClientInGame(ID))
			{
			continue;
			}
    		
		g_Location[ID][0] = 0.0;
		g_Location[ID][1] = 0.0;
		g_Location[ID][2] = 0.0;
		g_use[ID] = false;
		g_tuse[ID] = true;
		}
} 

public OnClientPutInServer(client)
{
		g_Location[client][0] = 0.0;
		g_Location[client][1] = 0.0;
		g_Location[client][2] = 0.0;
		g_use[client] = false;
		g_tuse[client] = true;
}


public Action:Cmd_unblock(client,args)
{
		
	if(g_use[client] == false)
	{
		if(g_tuse[client] == true)
		{
		GetClientAbsOrigin(client, g_Location[client]);
		g_Location[client][2] = g_Location[client][2]+99.0;
		TeleportEntity(client, g_Location[client], NULL_VECTOR, NULL_VECTOR);
		CPrintToChat (client, "{lime}[UnBlock]{default} You have been teleported");
		PrintToServer( "Gracz uzyl ub");
		g_use[client] = true;
		}
		else
		{
		CPrintToChat (client, "{lime}[UnBlock]{default} Only 15sec after the round starts.");
		}
	} 
	else 
	{
		CPrintToChat (client, "{lime}[UnBlock]{default} Only once per round.");
	}	

}
public Action EventRoundStart(Event ev, const char[] evName, bool dontBroadcast)
{

	for (new ID=1; ID<=MaxClients; ID++)
		{
		if (!IsClientInGame(ID))
			{
			continue;
			}
		g_tuse[ID] = true;
		g_use[ID] = false;
		CreateTimer(50.0, switch_command);
		}
}
public Action switch_command(Handle timer)
{
	for (new ID=1; ID<=MaxClients; ID++)
		{
		if (!IsClientInGame(ID))
			{
			continue;
			}
		g_tuse[ID] = false;
		}
}  

Dla osób które maja dużo cierpliwości i chęci do pomocy:
 

Spoiler

1. Dlaczego zmienna deklarowana w funkcji OnPluginStart nie pozwala mi użyć zdeklarowanej zmiennej ID dalej w innych funkcjach? Czy mogę to rozwiązać deklarując zmienna globalna tak jak g_use a później w onplugin start nadać jej wartość? Następnie używać jej do identyfikacji graczy już w całym pluginie.

2. Dlaczego niektóre zmienne maja przedrostek g_? to nazwa własna czy jakaś właściwość.

3. Jak sprawdzać jak używać funkcji?  Na przykład chciałem sprawdzić jak używać printtochat i dostałem to:

void PrintToChat(int client, const char[] format, any... ...)
Dlaczego zawsze w nawiasie podaja INT przed zmienna? Musze tam znowu deklarować jakaś nowa zmienna czy chodzi o to ze mogę tylko użyć zmiennej typu całkowitego? 

nawiazując do poprzedniego pytania, czy nie istnieje już jakiś prosty sposob na identyfikacje klienta? Bo czesto widzę jakieś iClient i wydaje mi sie ze nikt tego nie deklarował a używa. Czy to jest wlasnie jakas zmienna wbudowana w SM?

 

 

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
  • Lubię to! 3
  • Dziękuje 1
  • Dobry pomysł! 1
Napisano (edytowane)

Witaj @MiloV

Zaczynając od podstaw, teleportacja gracza o stałą wartość wektora nie jest najlepszym rozwiązaniem problemu. W przypadku pojawienia się blokowania w innym propie, powinieneś automatycznie sprawdzać moment kolizji tych dwóch obiektów (gracz oraz prop) oraz jej zapobiegać. Nie jest to łatwy temat, ponieważ aby zapobiec kolizji trzeba określić trasę i wiele czynników, które mogą się wydarzyć podczas teleportowania enta, trzeba wykazać się dobrą wyobraźnią i umiejętnościami, których niestety z poradników MAGNET'a się nie nauczysz (bo to już nie podstawa). Jeśli chcesz bardziej zagłębić się w temat, polecam (https://forums.alliedmods.net/showthread.php?t=315808
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!).

Wracając jednak do Twojego pluginu, oraz samej komendy !ub, zacznę może od odpowiedzenia Ci na pytania w spoilerze.

 

W dniu 7.04.2020 o 23:29, MiloV napisał:

1. Dlaczego zmienna deklarowana w funkcji OnPluginStart nie pozwala mi użyć zdeklarowanej zmiennej ID dalej w innych funkcjach? Czy mogę to rozwiązać deklarując zmienna globalna tak jak g_use a później w onplugin start nadać jej wartość? Następnie używać jej do identyfikacji graczy już w całym pluginie.

 

W sourcepawnie klienta identyfikuje się poprzez parametry przekazywane przez forwardy, jak możesz się domyślać funkcja OnPluginStart() również jest forwardem, tak więc zmienne utworzone w jej kontenerze (kod w bracketach {})  są zmiennymi lokalnymi a więc mogą być użyte jedynie w tym kontenerze przy zachowaniu hierarchii. Przechodząc do drugiego członu pytania, zwróć uwagę na to, że zmienną "ID", która definiujesz w OnPluginStart() jest zmienną która działa tylko i wyłącznie w obszarze pętli for, w której ją zdefiniowałeś. Jest to pętla iteracyjna a więc zmienna poza kontenerem pętli nie jest dłużej przechowywana.

Przejdę od razu do drugiego pytania, na koniec zrobię delikatne podsumowanie, aby łatwiej Ci było wszystko ogarnąć.

 

W dniu 7.04.2020 o 23:29, MiloV napisał:

2. Dlaczego niektóre zmienne maja przedrostek g_? to nazwa własna czy jakaś właściwość.

 

Dodawanie przedrostka "g_" przed nazwą zmiennej określa, że zmienna jest globalna. Jest to raczej uznane jako zasada, aby poprawić czytelność kodu. Oznaczając w ten sposób zmienne, będziesz mógł je potem łatwo zidentyfikować w kodzie. Dla przykładu, Twoja funkcja ma około 300 linijek, kod jest dosyć skomplikowany, a Ty nazywasz zmienne "player_name, player_id, player_id2, buffer, buffer2", gdzie "player_id" oraz "buffer" będą zmiennymi globalnymi, spróbuj się w tym połapać 😄 Stosując się do wyżej wspomnianej zasady zmienne będą nazywać się "g_iPlayerId" oraz "g_sBuffer", gdzie "i" oraz "s" oznaczają typy zmiennych.

 

W dniu 7.04.2020 o 23:29, MiloV napisał:

3. Jak sprawdzać jak używać funkcji?  Na przykład chciałem sprawdzić jak używać printtochat i dostałem to:

void PrintToChat(int client, const char[] format, any... ...)
Dlaczego zawsze w nawiasie podaja INT przed zmienna? Musze tam znowu deklarować jakaś nowa zmienna czy chodzi o to ze mogę tylko użyć zmiennej typu całkowitego?

 

To są z kolei natywy Panie kolego, dostałeś natyw z określonymi typami danych, a więc:

  • void - Oznacza, że funkcja ta nie zwraca żadnej wartości, jest zmienną typu pustego, jeżeli z kolei przed nazwą funkcji miał byś "int, char.." funkcja ta już zwraca wartość w tym właśnie typie danych.
  • int client - oczekiwany parametr typu int - jak dobrze zauważyłeś jest to zmienna typu całkowitego, a więc tylko taką zmienną możesz przekazać.
  • const char[] format - stała tablica znaków 

Podsumowując, powtórz sobie lekcje o typach zmiennych, zmiennych lokalnych jak i globalnych oraz funkcjach. Masz również problem z identyfikacją gracza, lecz tutaj nie ma też się czego bać, gracz jest zawsze określany poprzez parametr przekazywany przez forward (parametry możesz nazywać sam, lecz najlepiej jest nazywać je "client". 

 

Niżej łap kodzik, miłego wchodzenia w pisanie skryptów :). 

 

#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>
#include <multicolors>

int g_iRoundStart; // zmiennna globalna przechowująca timestamp startu rundy
bool g_bUsed[MAXPLAYERS+1]; // tablica zmiennych typu boolean, przechowująca wartość prawda/fałsz - tworzymy dla każdego klienta z osobn, stąd index MAXPLAYERS

public void OnPluginStart()
{
	// "Łapiemy" start rundy
	HookEvent("round_start", Event_RoundStart);
	
	// rejestrujemy naszą komendę
	RegConsoleCmd("sm_ub", CMD_UnBlock, "Unblock player");
	
	// "Łapiemy" użycie +lookatweapon
	AddCommandListener(Listener_LookAtWeapon, "+lookatweapon");
} 

public void OnClientPutInServer(int client)
{
	// ustawiamy wartość domyślną dla naszej zmiennej sprawdzającej czy klient wpisał komende
	g_bUsed[client] = false;
}

public void Event_RoundStart(Handle event, const char[] name, bool dontBroadcast)
{
	// resetujemy użycie komendy iterując każdego klienta, zauważ, że przy wydarzeniu "round_start" nie dostajemy indexu klienta, ponieważ event dotyczy rundy, nie samego klienta. Dlatego też pobieramy ich manualnie
	for(int i = 1; i < MaxClients; i++)
		if(IsClientInGame(i) && !IsFakeClient(i))
			g_bUsed[i] = false;
	
	// pobieramy timestamp gdy zaczyna się runda
	g_iRoundStart = GetTime(); 
}

public Action CMD_UnBlock(int client, int args)
{
	// sprawdzamy czy gracz jest zywy, jeżeli nie ~ pomijamy kod poniżej
	if(!IsPlayerAlive(client)) {
		CPrintToChat(client, "{lime}[UnBlock]{default} You need to be alive.");
		return Plugin_Continue;
	}
		
	// sprawdzamy czy gracz użył komendy, jeżeli tak ~ pomijamy kod poniżej
	if(g_bUsed[client]){
		CPrintToChat(client, "{lime}[UnBlock]{default} Only once per round.");
		return Plugin_Continue;
	}
	
	// pobieramy aktualny timestamp, usuwamy od niego czas, w którym wystartowała runda, zostają nam więc sekundy, które minęły od tamtego wydarzenia
	if (GetTime() - g_iRoundStart > 15) {
		CPrintToChat(client, "{lime}[UnBlock]{default} Only 15sec after the round starts.");
		return Plugin_Continue;
	}
	
	// wszystko poszło pomyślnie, więc definiujemy zmienną przechowującą origin klienta
	float fOrigin[3];
	GetClientAbsOrigin(client, fOrigin);
	
	// dorzucamy 99.0 do wysokości używając operatora przypisania dodatku
	fOrigin[2] += 99.0;
	
	// teleportujemy klienta na podane origin
	TeleportEntity(client, fOrigin, NULL_VECTOR, NULL_VECTOR); // tutaj wyobraź sobię, że nad klientem jest inny obiekt, jeżeli go tam podrzucisz, możesz zbierać to co z niego zostanie
	
	// trzeba pamietac, że klient użył komendy
	g_bUsed[client] = true;
	
	// Twoje info
	CPrintToChat(client, "{lime}[UnBlock]{default} You have been teleported");
	PrintToServer( "Gracz uzyl ub");
	
	// zatrzymujemy w tym miejscu wykonywanie funkcji dalej, aby gra nie zwróciła "Unknown command" w konsoli
	return Plugin_Handled;
}

public Action Listener_LookAtWeapon(int client, const char[] command, int argc)
{
	// jeżeli gracz jest martwy lub czas minął a gracze lubią się bawić +lookatweapon, po co spamować 
	if(GetTime() - g_iRoundStart > 15 || !IsPlayerAlive(client))
		return Plugin_Continue;	

	// Wywołujemy nasz handler komendy
	CMD_UnBlock(client, 0);

	// jak gdyby nigdy nic
	return Plugin_Continue;
}

 

Pozderki, noxik! 🙂

 

 

Edytowane przez n.o.x

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

@n.o.x

Jeju ale Ci dziękuję że mi odpisałeś i poprawiłeś kod. Ustawiłeś mi uśmiech na ryjku na cały dzień!

Dobra zabieram się do analizy i dalszej nauki! Dzięki wielkie !😁😁

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

@n.o.x

\\Chciałem edytować poprzedni post ale brakło mi czasu. Jeżeli jest możliwość to prosiłbym o scalenie postów.

 

Mam pytanie, bo chce zmienić tylko klawisz z F na cokolwiek innego bo prophunt używa domyślnie +lookatweapon jako zamrażania gracza.
Odpowiada za to ta komenda:

	AddCommandListener(Listener_LookAtWeapon, "+lookatweapon");

I po podmiance z +lookatweapon na np. +reload +duck czy cokolwiek innego plugin już nie działa. i głowię się tutaj od godziny bo w kodzie nie ma innej wspominki o tym klawiszu, wiec teoretycznie taka podmianka powinna działać. Szukałem jakieś listy klawiszy która współpracuje z AddCommandListener ale nie znalazłem nic. Taka zmiana wymaga jakiś większych modyfikacji kodu?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Akcje typu +reload, +duck, +attack możesz wykryć poprzez pobranie przycisków gracza, tj. OnPlayerRunCmd


// These defines are for client button presses.
#define IN_ATTACK                (1 << 0)
#define IN_JUMP                  (1 << 1)
#define IN_DUCK                  (1 << 2)
#define IN_FORWARD               (1 << 3)
#define IN_BACK                  (1 << 4)
#define IN_USE                   (1 << 5)
#define IN_CANCEL                (1 << 6)
#define IN_LEFT                  (1 << 7)
#define IN_RIGHT                 (1 << 8)
#define IN_MOVELEFT              (1 << 9)
#define IN_MOVERIGHT             (1 << 10)
#define IN_ATTACK2               (1 << 11)
#define IN_RUN                   (1 << 12)
#define IN_RELOAD                (1 << 13)
#define IN_ALT1                  (1 << 14)
#define IN_ALT2                  (1 << 15)
#define IN_SCORE                 (1 << 16)   /**< Used by client.dll for when scoreboard is held down */
#define IN_SPEED                 (1 << 17)   /**< Player is holding the speed key */
#define IN_WALK                  (1 << 18)   /**< Player holding walk key */
#define IN_ZOOM                  (1 << 19)   /**< Zoom key for HUD zoom */
#define IN_WEAPON1               (1 << 20)   /**< weapon defines these bits */
#define IN_WEAPON2               (1 << 21)   /**< weapon defines these bits */
#define IN_BULLRUSH              (1 << 22)
#define IN_GRENADE1              (1 << 23)   /**< grenade 1 */
#define IN_GRENADE2              (1 << 24)   /**< grenade 2 */
#define IN_ATTACK3               (1 << 25)

 

Powodzonka!

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
Napisano (edytowane)

Jest dalej jedna rzecz która mi nie daje odejść od komputera 😄 Jak tego nie rozgryzę to nie pójdę dziś spać 😄 
Dlaczego AddCommandListener działa tylko z +lookatweapon? Próbowałem już przypisać to do paru klawiszy i dalej nie działa. Napisałem plugin aby to sprawdzić i faktycznie tylko lookatweapon daje odpowiedz na czacie.
Plugin:

Spoiler
#pragma semicolon 1
#pragma newdecls required
 
#include <sourcemod>
#include <sdktools>
#include <multicolors>
 
public void OnPluginStart()
{
    AddCommandListener(law, "+lookatweapon");
    AddCommandListener(rl, "+reload");
    AddCommandListener(us, "+use");
    AddCommandListener(frw, "+forward");
    AddCommandListener(sp, "+speed");
    AddCommandListener(dc, "+duck");
    AddCommandListener(jp, "+jump");
}
 
public Action law(int client, const char[] command, int argc) 
{
    CPrintToChat(client, "lookatweapon");   
    return Plugin_Continue; 
}
public Action rl(int client, const char[] command, int argc) 
{
    CPrintToChat(client, "reload"); 
    return Plugin_Continue; 
}
public Action us(int client, const char[] command, int argc) 
{
    CPrintToChat(client, "use");    
    return Plugin_Continue; 
}
public Action frw(int client, const char[] command, int argc) 
{
    CPrintToChat(client, "forward");    
    return Plugin_Continue; 
}
public Action sp(int client, const char[] command, int argc) 
{
    CPrintToChat(client, "speed");  
    return Plugin_Continue; 
}
public Action dc(int client, const char[] command, int argc) 
{
    CPrintToChat(client, "duck");   
    return Plugin_Continue; 
}
public Action jp(int client, const char[] command, int argc) 
{
    CPrintToChat(client, "jump");   
    return Plugin_Continue; 
}

 

Co prawda nawiązując do poprzedniego postu z moim pluginem rozwiązałem problem innego klawisza poprzez RegConsoleCmd i używam DROP ale dalej mnie to nie zadowala bo CT wyrzuca sobie broń 😄 A jedyne wolne klawisze które mi pasują to +use albo +reload. Będę musiał rozgryżć OnPlayerRunCmd.
 

 

 

Edytowane przez MiloV

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Wiadomość wygenerowana automatycznie

 

Problem został rozwiązany

Jeżeli się z tym nie zgadzasz, raportuj ten post

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
Gość
Ten temat został zamknięty. Brak możliwości dodania odpowiedzi.

×
×
  • Dodaj nową pozycję...