extensions/topmenus/smn_topmenus.cpp
author David Anderson <dvander@alliedmods.net>
Wed Feb 25 20:07:12 2009 -0500 (2009-02-25)
changeset 2607 f3b8bbe17f85
parent 2289 44045ead61cd
child 4350 9f00539117ce
permissions -rw-r--r--
Backed out changeset fa286305bd3f
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod TopMenus Extension
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "extension.h"
    33 #include "TopMenuManager.h"
    34 #include "TopMenu.h"
    35 
    36 HandleType_t hTopMenuType;
    37 
    38 class TopMenuHandle : public IHandleTypeDispatch
    39 {
    40 public: 
    41 	void OnHandleDestroy(HandleType_t type, void *object)
    42 	{
    43 		ITopMenu *pTopMenu = (ITopMenu *)object;
    44 		g_TopMenus.DestroyTopMenu(pTopMenu);
    45 	}
    46 	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
    47 	{
    48 		*pSize = ((TopMenu *)object)->CalcMemUsage();
    49 		return true;
    50 	}
    51 } s_TopMenuHandle;
    52 
    53 void Initialize_Natives()
    54 {
    55 	hTopMenuType = handlesys->CreateType("ITopMenu",
    56 		&s_TopMenuHandle,
    57 		0,
    58 		NULL,
    59 		NULL,
    60 		myself->GetIdentity(),
    61 		NULL);
    62 }
    63 
    64 void Shutdown_Natives()
    65 {
    66 	handlesys->RemoveType(hTopMenuType, myself->GetIdentity());
    67 }
    68 
    69 enum TopMenuAction
    70 {
    71 	TopMenuAction_DisplayOption = 0,
    72 	TopMenuAction_DisplayTitle = 1,
    73 	TopMenuAction_SelectOption = 2,
    74 	TopMenuAction_DrawOption = 3,
    75 	TopMenuAction_RemoveObject = 4,
    76 };
    77 
    78 class TopMenuCallbacks : public ITopMenuObjectCallbacks
    79 {
    80 public:
    81 	TopMenuCallbacks(IPluginFunction *pFunction) : m_pFunction(pFunction)
    82 	{		
    83 	}
    84 
    85 	unsigned int OnTopMenuDrawOption(ITopMenu *menu,
    86 		int client,
    87 		unsigned int object_id)
    88 	{
    89 		char buffer[2] = {ITEMDRAW_DEFAULT, 0x0};
    90 		m_pFunction->PushCell(m_hMenuHandle);
    91 		m_pFunction->PushCell(TopMenuAction_DrawOption);
    92 		m_pFunction->PushCell(object_id);
    93 		m_pFunction->PushCell(client);
    94 		m_pFunction->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
    95 		m_pFunction->PushCell(sizeof(buffer));
    96 		m_pFunction->Execute(NULL);
    97 		return (unsigned int)buffer[0];
    98 	}
    99 
   100 	void OnTopMenuDisplayOption(ITopMenu *menu,
   101 		int client, 
   102 		unsigned int object_id,
   103 		char buffer[], 
   104 		size_t maxlength)
   105 	{
   106 		m_pFunction->PushCell(m_hMenuHandle);
   107 		m_pFunction->PushCell(TopMenuAction_DisplayOption);
   108 		m_pFunction->PushCell(object_id);
   109 		m_pFunction->PushCell(client);
   110 		m_pFunction->PushStringEx(buffer, maxlength, 0, SM_PARAM_COPYBACK);
   111 		m_pFunction->PushCell(maxlength);
   112 		m_pFunction->Execute(NULL);
   113 	}
   114 
   115 	void OnTopMenuDisplayTitle(ITopMenu *menu,
   116 		int client,
   117 		unsigned int object_id,
   118 		char buffer[],
   119 		size_t maxlength)
   120 	{
   121 		m_pFunction->PushCell(m_hMenuHandle);
   122 		m_pFunction->PushCell(TopMenuAction_DisplayTitle);
   123 		m_pFunction->PushCell(object_id);
   124 		m_pFunction->PushCell(client);
   125 		m_pFunction->PushStringEx(buffer, maxlength, 0, SM_PARAM_COPYBACK);
   126 		m_pFunction->PushCell(maxlength);
   127 		m_pFunction->Execute(NULL);
   128 	}
   129 
   130 	void OnTopMenuSelectOption(ITopMenu *menu, 
   131 		int client, 
   132 		unsigned int object_id)
   133 	{
   134 		unsigned int old_reply = playerhelpers->SetReplyTo(SM_REPLY_CHAT);
   135 		m_pFunction->PushCell(m_hMenuHandle);
   136 		m_pFunction->PushCell(TopMenuAction_SelectOption);
   137 		m_pFunction->PushCell(object_id);
   138 		m_pFunction->PushCell(client);
   139 		m_pFunction->PushString("");
   140 		m_pFunction->PushCell(0);
   141 		m_pFunction->Execute(NULL);
   142 		playerhelpers->SetReplyTo(old_reply);
   143 	}
   144 
   145 	void OnTopMenuObjectRemoved(ITopMenu *menu, unsigned int object_id)
   146 	{
   147 		m_pFunction->PushCell(m_hMenuHandle);
   148 		m_pFunction->PushCell(TopMenuAction_RemoveObject);
   149 		m_pFunction->PushCell(object_id);
   150 		m_pFunction->PushCell(0);
   151 		m_pFunction->PushString("");
   152 		m_pFunction->PushCell(0);
   153 		m_pFunction->Execute(NULL);
   154 
   155 		delete this;
   156 	}
   157 
   158 	Handle_t m_hMenuHandle;
   159 	IPluginFunction *m_pFunction;
   160 };
   161 
   162 static cell_t CreateTopMenu(IPluginContext *pContext, const cell_t *params)
   163 {
   164 	IPluginFunction *func = pContext->GetFunctionById(params[1]);
   165 	if (func == NULL)
   166 	{
   167 		return pContext	->ThrowNativeError("Invalid function specified");
   168 	}
   169 
   170 	TopMenuCallbacks *cb = new TopMenuCallbacks(func);
   171 
   172 	ITopMenu *pMenu = g_TopMenus.CreateTopMenu(cb);
   173 
   174 	if (!pMenu)
   175 	{
   176 		delete cb;
   177 		return BAD_HANDLE;
   178 	}
   179 
   180 	Handle_t hndl = handlesys->CreateHandle(hTopMenuType, 
   181 		pMenu,
   182 		pContext->GetIdentity(),
   183 		myself->GetIdentity(),
   184 		NULL);
   185 	if (hndl == 0)
   186 	{
   187 		g_TopMenus.DestroyTopMenu(pMenu);
   188 		return BAD_HANDLE;
   189 	}
   190 
   191 	cb->m_hMenuHandle = hndl;
   192 
   193 	return hndl;
   194 }
   195 
   196 static cell_t LoadTopMenuConfig(IPluginContext *pContext, const cell_t *params)
   197 {
   198 	HandleError err;
   199 	ITopMenu *pMenu;
   200 	HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
   201 
   202 	if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
   203 		!= HandleError_None)
   204 	{
   205 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   206 	}
   207 
   208 	char *file, *err_buf;
   209 	pContext->LocalToString(params[2], &file);
   210 	pContext->LocalToString(params[3], &err_buf);
   211 
   212 	char path[PLATFORM_MAX_PATH];
   213 	g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
   214 
   215 	return pMenu->LoadConfiguration(path, err_buf, params[4]) ? 1 : 0;
   216 }
   217 
   218 static cell_t AddToTopMenu(IPluginContext *pContext, const cell_t *params)
   219 {
   220 	HandleError err;
   221 	ITopMenu *pMenu;
   222 	HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
   223 
   224 	if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
   225 		!= HandleError_None)
   226 	{
   227 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   228 	}
   229 
   230 	IPluginFunction *func = pContext->GetFunctionById(params[4]);
   231 	if (func == NULL)
   232 	{
   233 		return pContext	->ThrowNativeError("Invalid function specified");
   234 	}
   235 
   236 	TopMenuCallbacks *cb = new TopMenuCallbacks(func);
   237 
   238 	char *name, *cmdname, *info_string = NULL;
   239 	pContext->LocalToString(params[2], &name);
   240 	pContext->LocalToString(params[6], &cmdname);
   241 
   242 	if (params[0] >= 8)
   243 	{
   244 		pContext->LocalToString(params[8], &info_string);
   245 	}
   246 
   247 	TopMenuObjectType obj_type = (TopMenuObjectType)params[3];
   248 	
   249 	unsigned int object_id;
   250 	if ((object_id = pMenu->AddToMenu2(name,
   251 		obj_type,
   252 		cb,
   253 		pContext->GetIdentity(),
   254 		cmdname,
   255 		params[7], 
   256 		params[5],
   257 		info_string)) == 0)
   258 	{
   259 		delete cb;
   260 		return 0;
   261 	}
   262 
   263 	cb->m_hMenuHandle = params[1];
   264 
   265 	return object_id;
   266 }
   267 
   268 static cell_t RemoveFromTopMenu(IPluginContext *pContext, const cell_t *params)
   269 {
   270 	HandleError err;
   271 	ITopMenu *pMenu;
   272 	HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
   273 
   274 	if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
   275 		!= HandleError_None)
   276 	{
   277 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   278 	}
   279 
   280 	pMenu->RemoveFromMenu(params[2]);
   281 
   282 	return 1;
   283 }
   284 
   285 static cell_t FindTopMenuCategory(IPluginContext *pContext, const cell_t *params)
   286 {
   287 	HandleError err;
   288 	ITopMenu *pMenu;
   289 	HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
   290 
   291 	if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
   292 		!= HandleError_None)
   293 	{
   294 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   295 	}
   296 
   297 	char *name;
   298 	pContext->LocalToString(params[2], &name);
   299 
   300 	return pMenu->FindCategory(name);
   301 }
   302 
   303 static cell_t DisplayTopMenu(IPluginContext *pContext, const cell_t *params)
   304 {
   305 	HandleError err;
   306 	ITopMenu *pMenu;
   307 	HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
   308 
   309 	if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
   310 		!= HandleError_None)
   311 	{
   312 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   313 	}
   314 
   315 	int client = params[2];
   316 	IGamePlayer *player = playerhelpers->GetGamePlayer(client);
   317 	if (!player)
   318 	{
   319 		return pContext->ThrowNativeError("Invalid client index %d", client);
   320 	}
   321 	else if (!player->IsInGame())
   322 	{
   323 		return pContext->ThrowNativeError("Client %d is not in game", client);
   324 	}
   325 
   326 	return pMenu->DisplayMenu(client, 0, (TopMenuPosition)params[3]);
   327 }
   328 
   329 static cell_t GetTopMenuInfoString(IPluginContext *pContext, const cell_t *params)
   330 {
   331 	HandleError err;
   332 	ITopMenu *pMenu;
   333 	HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
   334 
   335 	if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
   336 		!= HandleError_None)
   337 	{
   338 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   339 	}
   340 
   341 	const char *str;
   342 	if ((str = pMenu->GetObjectInfoString(params[2])) == NULL)
   343 	{
   344 		return pContext->ThrowNativeError("Invalid menu object %d", params[2]);
   345 	}
   346 
   347 	char *buffer;
   348 	pContext->LocalToString(params[3], &buffer);
   349 
   350 	return strncopy(buffer, str, params[4]);
   351 }
   352 
   353 static cell_t GetTopMenuName(IPluginContext *pContext, const cell_t *params)
   354 {
   355 	HandleError err;
   356 	ITopMenu *pMenu;
   357 	HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
   358 
   359 	if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
   360 		!= HandleError_None)
   361 	{
   362 		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
   363 	}
   364 
   365 	const char *str;
   366 	if ((str = pMenu->GetObjectName(params[2])) == NULL)
   367 	{
   368 		return pContext->ThrowNativeError("Invalid menu object %d", params[2]);
   369 	}
   370 
   371 	char *buffer;
   372 	pContext->LocalToString(params[3], &buffer);
   373 
   374 	return strncopy(buffer, str, params[4]);
   375 }
   376 
   377 sp_nativeinfo_t g_TopMenuNatives[] = 
   378 {
   379 	{"AddToTopMenu",			AddToTopMenu},
   380 	{"CreateTopMenu",			CreateTopMenu},
   381 	{"DisplayTopMenu",			DisplayTopMenu},
   382 	{"LoadTopMenuConfig",		LoadTopMenuConfig},
   383 	{"RemoveFromTopMenu",		RemoveFromTopMenu},
   384 	{"FindTopMenuCategory",		FindTopMenuCategory},
   385 	{"GetTopMenuInfoString",	GetTopMenuInfoString},
   386 	{"GetTopMenuObjName",		GetTopMenuName},
   387 	{NULL,					NULL},
   388 };