1 | /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ |
2 | /* If you are missing that file, acquire a complete release at teeworlds.com. */ |
3 | #include <base/math.h> |
4 | #include <base/system.h> |
5 | |
6 | #include <engine/config.h> |
7 | #include <engine/console.h> |
8 | #include <engine/shared/config.h> |
9 | |
10 | #include "friends.h" |
11 | |
12 | CFriends::CFriends() |
13 | { |
14 | mem_zero(block: m_aFriends, size: sizeof(m_aFriends)); |
15 | m_NumFriends = 0; |
16 | m_Foes = false; |
17 | } |
18 | |
19 | void CFriends::ConAddFriend(IConsole::IResult *pResult, void *pUserData) |
20 | { |
21 | CFriends *pSelf = (CFriends *)pUserData; |
22 | pSelf->AddFriend(pName: pResult->GetString(Index: 0), pClan: pResult->GetString(Index: 1)); |
23 | } |
24 | |
25 | void CFriends::ConRemoveFriend(IConsole::IResult *pResult, void *pUserData) |
26 | { |
27 | CFriends *pSelf = (CFriends *)pUserData; |
28 | pSelf->RemoveFriend(pName: pResult->GetString(Index: 0), pClan: pResult->GetString(Index: 1)); |
29 | } |
30 | |
31 | void CFriends::ConFriends(IConsole::IResult *pResult, void *pUserData) |
32 | { |
33 | CFriends *pSelf = (CFriends *)pUserData; |
34 | pSelf->Friends(); |
35 | } |
36 | |
37 | void CFriends::Init(bool Foes) |
38 | { |
39 | m_Foes = Foes; |
40 | |
41 | IConfigManager *pConfigManager = Kernel()->RequestInterface<IConfigManager>(); |
42 | if(pConfigManager) |
43 | pConfigManager->RegisterCallback(pfnFunc: ConfigSaveCallback, pUserData: this); |
44 | |
45 | IConsole *pConsole = Kernel()->RequestInterface<IConsole>(); |
46 | if(pConsole) |
47 | { |
48 | if(Foes) |
49 | { |
50 | pConsole->Register(pName: "add_foe" , pParams: "s[name] ?s[clan]" , Flags: CFGFLAG_CLIENT, pfnFunc: ConAddFriend, pUser: this, pHelp: "Add a foe" ); |
51 | pConsole->Register(pName: "remove_foe" , pParams: "s[name] ?s[clan]" , Flags: CFGFLAG_CLIENT, pfnFunc: ConRemoveFriend, pUser: this, pHelp: "Remove a foe" ); |
52 | pConsole->Register(pName: "foes" , pParams: "" , Flags: CFGFLAG_CLIENT, pfnFunc: ConFriends, pUser: this, pHelp: "List foes" ); |
53 | } |
54 | else |
55 | { |
56 | pConsole->Register(pName: "add_friend" , pParams: "s[name] ?s[clan]" , Flags: CFGFLAG_CLIENT, pfnFunc: ConAddFriend, pUser: this, pHelp: "Add a friend" ); |
57 | pConsole->Register(pName: "remove_friend" , pParams: "s[name] ?s[clan]" , Flags: CFGFLAG_CLIENT, pfnFunc: ConRemoveFriend, pUser: this, pHelp: "Remove a friend" ); |
58 | pConsole->Register(pName: "friends" , pParams: "" , Flags: CFGFLAG_CLIENT, pfnFunc: ConFriends, pUser: this, pHelp: "List friends" ); |
59 | } |
60 | } |
61 | } |
62 | |
63 | const CFriendInfo *CFriends::GetFriend(int Index) const |
64 | { |
65 | return &m_aFriends[maximum(a: 0, b: Index % m_NumFriends)]; |
66 | } |
67 | |
68 | int CFriends::GetFriendState(const char *pName, const char *pClan) const |
69 | { |
70 | int Result = FRIEND_NO; |
71 | unsigned NameHash = str_quickhash(str: pName); |
72 | unsigned ClanHash = str_quickhash(str: pClan); |
73 | for(int i = 0; i < m_NumFriends; ++i) |
74 | { |
75 | if((g_Config.m_ClFriendsIgnoreClan && m_aFriends[i].m_aName[0]) || (m_aFriends[i].m_ClanHash == ClanHash && !str_comp(a: m_aFriends[i].m_aClan, b: pClan))) |
76 | { |
77 | if(m_aFriends[i].m_aName[0] == 0) |
78 | Result = FRIEND_CLAN; |
79 | else if(m_aFriends[i].m_NameHash == NameHash && !str_comp(a: m_aFriends[i].m_aName, b: pName)) |
80 | { |
81 | Result = FRIEND_PLAYER; |
82 | break; |
83 | } |
84 | } |
85 | } |
86 | return Result; |
87 | } |
88 | |
89 | bool CFriends::IsFriend(const char *pName, const char *pClan, bool PlayersOnly) const |
90 | { |
91 | unsigned NameHash = str_quickhash(str: pName); |
92 | unsigned ClanHash = str_quickhash(str: pClan); |
93 | for(int i = 0; i < m_NumFriends; ++i) |
94 | { |
95 | if(((g_Config.m_ClFriendsIgnoreClan && m_aFriends[i].m_aName[0]) || (m_aFriends[i].m_ClanHash == ClanHash && !str_comp(a: m_aFriends[i].m_aClan, b: pClan))) && |
96 | ((!PlayersOnly && m_aFriends[i].m_aName[0] == 0) || (m_aFriends[i].m_NameHash == NameHash && !str_comp(a: m_aFriends[i].m_aName, b: pName)))) |
97 | return true; |
98 | } |
99 | return false; |
100 | } |
101 | |
102 | void CFriends::AddFriend(const char *pName, const char *pClan) |
103 | { |
104 | if(m_NumFriends == MAX_FRIENDS || (pName[0] == 0 && pClan[0] == 0)) |
105 | return; |
106 | |
107 | // make sure we don't have the friend already |
108 | unsigned NameHash = str_quickhash(str: pName); |
109 | unsigned ClanHash = str_quickhash(str: pClan); |
110 | for(int i = 0; i < m_NumFriends; ++i) |
111 | { |
112 | if((m_aFriends[i].m_NameHash == NameHash && !str_comp(a: m_aFriends[i].m_aName, b: pName)) && ((g_Config.m_ClFriendsIgnoreClan && m_aFriends[i].m_aName[0]) || (m_aFriends[i].m_ClanHash == ClanHash && !str_comp(a: m_aFriends[i].m_aClan, b: pClan)))) |
113 | return; |
114 | } |
115 | |
116 | str_copy(dst&: m_aFriends[m_NumFriends].m_aName, src: pName); |
117 | str_copy(dst&: m_aFriends[m_NumFriends].m_aClan, src: pClan); |
118 | m_aFriends[m_NumFriends].m_NameHash = NameHash; |
119 | m_aFriends[m_NumFriends].m_ClanHash = ClanHash; |
120 | ++m_NumFriends; |
121 | } |
122 | |
123 | void CFriends::RemoveFriend(const char *pName, const char *pClan) |
124 | { |
125 | unsigned NameHash = str_quickhash(str: pName); |
126 | unsigned ClanHash = str_quickhash(str: pClan); |
127 | for(int i = 0; i < m_NumFriends; ++i) |
128 | { |
129 | if((m_aFriends[i].m_NameHash == NameHash && !str_comp(a: m_aFriends[i].m_aName, b: pName)) && |
130 | ((g_Config.m_ClFriendsIgnoreClan && m_aFriends[i].m_aName[0]) || (m_aFriends[i].m_ClanHash == ClanHash && !str_comp(a: m_aFriends[i].m_aClan, b: pClan)))) |
131 | { |
132 | RemoveFriend(Index: i); |
133 | return; |
134 | } |
135 | } |
136 | } |
137 | |
138 | void CFriends::RemoveFriend(int Index) |
139 | { |
140 | if(Index >= 0 && Index < m_NumFriends) |
141 | { |
142 | mem_move(dest: &m_aFriends[Index], source: &m_aFriends[Index + 1], size: sizeof(CFriendInfo) * (m_NumFriends - (Index + 1))); |
143 | --m_NumFriends; |
144 | } |
145 | } |
146 | |
147 | void CFriends::Friends() |
148 | { |
149 | char aBuf[128]; |
150 | IConsole *pConsole = Kernel()->RequestInterface<IConsole>(); |
151 | if(pConsole) |
152 | { |
153 | for(int i = 0; i < m_NumFriends; ++i) |
154 | { |
155 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "Name: %s, Clan: %s" , m_aFriends[i].m_aName, m_aFriends[i].m_aClan); |
156 | |
157 | pConsole->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: m_Foes ? "foes" : "friends" , pStr: aBuf, PrintColor: color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClMessageHighlightColor))); |
158 | } |
159 | } |
160 | } |
161 | |
162 | void CFriends::ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData) |
163 | { |
164 | CFriends *pSelf = (CFriends *)pUserData; |
165 | char aBuf[128]; |
166 | const char *pEnd = aBuf + sizeof(aBuf) - 4; |
167 | for(int i = 0; i < pSelf->m_NumFriends; ++i) |
168 | { |
169 | str_copy(dst&: aBuf, src: pSelf->m_Foes ? "add_foe " : "add_friend " ); |
170 | |
171 | str_append(dst&: aBuf, src: "\"" ); |
172 | char *pDst = aBuf + str_length(str: aBuf); |
173 | str_escape(dst: &pDst, src: pSelf->m_aFriends[i].m_aName, end: pEnd); |
174 | str_append(dst&: aBuf, src: "\" \"" ); |
175 | pDst = aBuf + str_length(str: aBuf); |
176 | str_escape(dst: &pDst, src: pSelf->m_aFriends[i].m_aClan, end: pEnd); |
177 | str_append(dst&: aBuf, src: "\"" ); |
178 | |
179 | pConfigManager->WriteLine(pLine: aBuf); |
180 | } |
181 | } |
182 | |