/* Player Model ================= by commonbullet based on scriptyboy's script & idea written in AMXX-Studio description: ------------ - custom models forum topic: ------------ http://www.amxmodx.org/forums/viewtopic.php? requirements: ------------- - requires "cstrike" module usage: ------ look at models.ini */ #include #include #include // ---- [debug settings] #define DEBUG_MODE 0 #define DEBUG_LOGFILE "playermodel.log" #define DEBUG_MSG_BEGIN "========= PLAYERMODEL DEBUG =========" #define DEBUG_MSG_END "=====================================" #define DEBUG_MSG_ERROR "[PLAYERMODEL ERROR] " #define DEBUG_MSG_LOG "[PLAYERMODEL LOG] " // ---- [end] // ---- [console messages] #define CONSOLE_MSG_HLIN "----------------------------------------" #define CONSOLE_MSG_HEAD "[PLAYERMODEL - Models.ini]" //#define CONSOLE_MSG_FOOT "[PLAYERMODEL - End of Models.ini]" #define CONSOLE_MSG_MODELS_LIST "[MODELS]" #define CONSOLE_MSG_DEL_INVALID "Invalid number. Type amx_playermodel_ini to get models index." #define CONSOLE_MSG_DEL_DELETED "Line %s has been deleted." #define CONSOLE_MSG_DEL_UPDATED "Current game model settings have been updated" #define CONSOLE_MSG_SET_RESTART "You need to restart map to apply changes." #define CONSOLE_MSG_SET_UPDATE "Models.ini has been updated." #define CONSOLE_MSG_SET_ADD "Line added to Models.ini." #define CONSOLE_MSG_SET_NORESTART "Model(s) have been set with precached files - no need to restart." #define CONSOLE_MSG_SET_MODEL_INVALID "Invalid Model: %s. ^nType 'amx_playermodel_models to get a list of valid models" #define CONSOLE_MSG_SET_ID_INVALID "Invalid ID" #define CONSOLE_MSG_MODELSLIST_FOOT "(*) - Models that have been precached in this session." #define CONSOLE_MSG_ACCESS_INVALID "You don't have admin access change/view models.." #define CONSOLE_MSG_INI_CREATE "** Models.ini has just been created." // ---- [end] // ---- [constants indexes] #define LN_TYPE_BLANK 0 #define LN_TYPE_VALID 1 #define AUTH_TYPE_BOTNAME 0 #define AUTH_TYPE_STEAMID 1 #define AUTH_TYPE_IP 2 // ---- [end] // ---- [general settings] #define MODELSINI_SCRATCH_LIMIT 9 //blank lines may be overwritten in models.ini after this line number //max models in models.ini.. #define MAX_MODELS 64 #define MAX_PLAYERS 33 // max cs and cz models, // shouldn't be changed unless there's a valve update... #define MAX_CZ_MODELS 5 #define MAX_CS_MODELS 4 #define TAG_BOTDEFAULT "*BOTDEFAULT" #define TAG_DEFAULT "*DEFAULT" #define TAG_FORCEPRECACHE_CHAR "*" #define TAG_COMMANDSET_BY_STEAMID "&" #define TAG_COMMANDSET_BY_IP "%" #define TAG_COMMANDSET_NULL "_" #define TAG_REPLACE "*REPLACE" #define STATUS_MODEL_NOTSET 0 #define STATUS_MODEL_SETBYID 1 #define STATUS_MODEL_BOTDEFAULT 2 #define STATUS_MODEL_DEFAULT 4 #define STATUS_MODEL_REPLACEMENT 8 #define STATUS_MODEL_NOMODEL 16 #define STATUS_MODEL_RESET 32 #define SETMODEL_RESET -4 #define SETMODEL_REPLACE -3 #define SETMODEL_DEFAULT -2 #define SETMODEL_BOTDEFAULT -1 #define NULLINDEX 8080 //-1 is being used... #define REPLACEMENT_SIGN "$" // ---- [end] // Globals new g_PlayerId[MAX_MODELS][25] // list of players ids new g_PrecachedList[MAX_MODELS][32] new g_PrecachedCount new g_ModelInfo[2][MAX_MODELS] // info about the models for each team new g_ModelsCount //models count new g_ModelStatus[MAX_PLAYERS] // array to check if a player model has been set, so it won't be set // unless it's necessary new g_BotsModel[2] = {-1,-1}// bots' unique model new g_DefaultModel[2] = {-1, -1} // human's default model #if DEBUG_MODE == 1 new logmsg[192] #endif public plugin_init() { register_plugin("Player Model", "2.13c", "commonbullet") register_event("ResetHUD", "set_players_models", "be") register_logevent ("auto_balance_triggered", 4, "3=auto") register_concmd ("amx_playermodel_ini","list_ini",ADMIN_KICK,"list models.ini") register_concmd ("amx_playermodel_del","del_line",ADMIN_KICK,"") register_concmd ("amx_playermodel_models","list_models",ADMIN_KICK,"list valid models") register_concmd ("amx_playermodel_set","set_line",ADMIN_KICK,"<*modelname> | ") register_cvar ("amx_playermodel_round_checkid", "0") } // ---- [Models.ini handlers] public list_ini (id,level,cid) { if (!cmd_access(id, level, cid, 0)) { console_print(id, CONSOLE_MSG_ACCESS_INVALID) return PLUGIN_HANDLED } new path[66] new validlines[MAX_MODELS] new vlinesnum new linestr[100] new len = 0 get_inipath(path,65) get_ini_lines(validlines,vlinesnum,LN_TYPE_VALID) console_print(id, "^n%s^n%s^n%s",CONSOLE_MSG_HLIN,CONSOLE_MSG_HEAD,CONSOLE_MSG_HLIN) for (new i = 0;i -1) && strlen(authid)>1) { new ind = find_registered_id(authid) if (ind > -1){ new players[32] new playersnum new authtype new checkid for (new i=ind;i<(g_ModelsCount-1);i++){ g_PlayerId[i] = g_PlayerId[i+1] g_ModelInfo[i] = g_ModelInfo[i+1] } g_ModelsCount-- get_players (players,playersnum) for (new i=0;i-1){ format(indexstr,7," (*)") strcat (msg,indexstr,255) } if (tabcount < 3) strcat(msg,"^t^t^t^t",255) else if ((q+1)0) && !is_valid_model(arg3)){ console_print(id, CONSOLE_MSG_SET_MODEL_INVALID,arg3) return PLUGIN_HANDLED } } new line new blanklines[MAX_MODELS] new blanknum new linestr[100] new path[66] new msg[128] new iniline new searchstr[21] get_inipath(path,65) line = -1 format (searchstr,20,"^"%s^"",arg1) iniline = find_line_by_id (searchstr) if (iniline>-1) line = iniline else { get_ini_lines (blanklines,blanknum,LN_TYPE_BLANK) if (blanknum && (blanklines[blanknum-1]>=MODELSINI_SCRATCH_LIMIT)) line = blanklines[blanknum-1] } if (strlen(arg3)>0 && !forceprecache) format(linestr,99,"^"%s^" ^"%s^" ^"%s^"",arg1,arg2,arg3) else if (forceprecache) format(linestr,99,"^"%s^"",arg1) else format(linestr,99,"^"%s^" ^"%s^"",arg1,arg2) new Tind new CTind new mayupdate // may update without restart if (strfind(arg2,"#")==0){ new error get_models_by_number(arg2,arg2,arg3,error) } Tind = (equal(arg2, "_")) ? NULLINDEX : find_precached_ind(arg2) CTind = (equal(arg2, "_")) ? NULLINDEX : (strlen(arg3)>0) ? find_precached_ind(arg3) : Tind mayupdate = (!forceprecache)? ((Tind>-1) && (CTind>-1)) : ((CTind>-1)) if (mayupdate) { if (equali(arg1,TAG_DEFAULT)) { new players[32] new playernum get_players (players,playernum,"c") g_DefaultModel[0] = Tind g_DefaultModel[1] = CTind for (new i=0; i < playernum; i++) { g_ModelStatus[players[i]] |= STATUS_MODEL_RESET set_players_models(players[i]) } } if (equali(arg1,TAG_BOTDEFAULT)){ new bots[32] new botnum get_players (bots,botnum,"d") g_BotsModel[0] = Tind g_BotsModel[1] = CTind for (new i=0;i -1) { format(g_PlayerId[slot], 24, REPLACEMENT_SIGN) g_ModelInfo[0][slot] = Tind g_ModelInfo[1][slot] = CTind for(new i = 0; i < playersnum; i++) { cs_get_user_model(players[i], modelname, 31) if(equali(modelname, arg2)) { g_ModelStatus[players[i]] |= STATUS_MODEL_RESET set_players_models(players[i]) } } } } else if (!forceprecache){ new ind = find_registered_id(arg1) new players[32] new playersnum new authtype new checkid if (ind > -1){ g_ModelInfo[0][ind] = Tind g_ModelInfo[1][ind] = CTind format(msg,47,CONSOLE_MSG_SET_UPDATE) } else { copy (g_PlayerId[g_ModelsCount],24,arg1) g_ModelInfo[0][g_ModelsCount] = Tind g_ModelInfo[1][g_ModelsCount] = CTind ind = g_ModelsCount g_ModelsCount ++ format(msg,47,CONSOLE_MSG_SET_ADD) } get_players (players,playersnum) for (new i=0;i=1) && (num<=lim)) isvalid = true } else if(equal(model, "_")) isvalid = true else { for (new j=0;j<3;j++){ new cdmodels[32][16] if (j<2) get_default_models (cdmodels,lim,j) else get_custom_models (cdmodels,lim,31) for (new i=0;i-1 || strfind (checkauthid,"VALVE")>-1) { get_user_authid(id,authid,49) checkid = equali(authid,checkauthid) #if DEBUG_MODE == 1 authtype = AUTH_TYPE_STEAMID #endif } else { get_user_ip (id,authid,49) checkid = (strfind(authid,checkauthid)>-1) #if DEBUG_MODE == 1 authtype = AUTH_TYPE_IP #endif } return authtype } stock substr(const str[],dest[],len,lpos){ new pos,ind for (pos=lpos;pos-1) { new error mayprecache_CT = 0 mayprecache_T = 0 get_models_by_number (arg2,arg2,arg3,error) if (error){ server_print ("[model error] Invalid Model Index: %s",arg2) continue } } else if ( (strfind(arg1,TAG_FORCEPRECACHE_CHAR)==0) && (strlen(arg1)>1) && (strlen(arg2)==0) && (strlen(arg3)==0)){ substr(arg1,arg3,31,1) mayprecache_T = 0 if (find_precached_ind(arg3)>-1) continue } else { // model replacement if (equali(arg1, TAG_REPLACE)) { if(equali(arg2, arg3)) continue isreplacement = 1 } // if there's only one model they'll be the same for CTs and Ts else if (!strlen(arg3)){ if(!strlen(arg2)) continue copy (arg3,31,arg2) mayprecache_T = 0 } else { if(equal(arg3, TAG_COMMANDSET_NULL)) { isnullmodel_CT = 1 mayprecache_CT = 0 } if(equal(arg2, TAG_COMMANDSET_NULL)) { isnullmodel_T = 1 mayprecache_T = 0 } } // This will prevent unecessary caching. // for default models for (new ind = 0; ind < g_PrecachedCount; ind ++) { if (mayprecache_CT && equali(arg3, g_PrecachedList[ind])) mayprecache_CT = 0 if (mayprecache_T && equali(arg2, g_PrecachedList[ind])) mayprecache_T = 0 if (!mayprecache_CT && !mayprecache_T) break } } // if it's a default model, it doesn't need to be cached if (mayprecache_CT){ new modelpath [65] format (modelpath,64,"models/player/%s/%s%s",arg3,arg3,".mdl") if (file_exists(modelpath)) { #if DEBUG_MODE == 1 format (logmsg,191,"%s%s%s",DEBUG_MSG_LOG," PRECACHING CT CUSTOM MODEL :",modelpath) debugMsg (logmsg) #endif precache_model(modelpath) copy (g_PrecachedList[g_PrecachedCount],31,arg3) g_PrecachedCount ++ } else { server_print ("[model error] File Not Found: %s",modelpath) #if DEBUG_MODE == 1 format (logmsg,191,"[model error] File Not Found: %s",modelpath) debugMsg (logmsg) #endif continue } } if (mayprecache_T && (!equali(arg2,arg3))){ new modelpath [65] format (modelpath,64,"models/player/%s/%s%s",arg2,arg2,".mdl") if (file_exists(modelpath)){ #if DEBUG_MODE == 1 format (logmsg,191,"%s%s%s",DEBUG_MSG_LOG," PRECACHING T CUSTOM MODEL :",modelpath) debugMsg (logmsg) #endif precache_model(modelpath) copy (g_PrecachedList[g_PrecachedCount],31,arg2) g_PrecachedCount ++ } else { server_print ("[model error] File Not Found: %s",modelpath) #if DEBUG_MODE == 1 format (logmsg,191,"[model error] File Not Found: %s",modelpath) debugMsg (logmsg) #endif continue } } // sets bots' unique models, if specified new CTmodelind new Tmodelind CTmodelind = (isnullmodel_CT) ? NULLINDEX : find_precached_ind(arg3) Tmodelind = (isnullmodel_T) ? NULLINDEX : find_precached_ind(arg2) if ((CTmodelind>-1) && (Tmodelind>-1) && !forceprecache){ if (equali(TAG_BOTDEFAULT,arg1)){ g_BotsModel[0] = Tmodelind g_BotsModel[1] = CTmodelind } if (equali(TAG_DEFAULT, arg1)){ g_DefaultModel[0] = Tmodelind g_DefaultModel[1] = CTmodelind } else { if(isreplacement) format(g_PlayerId[g_ModelsCount], 24, REPLACEMENT_SIGN) else copy(g_PlayerId[g_ModelsCount],24, arg1) g_ModelInfo[0][g_ModelsCount] = Tmodelind g_ModelInfo[1][g_ModelsCount] = CTmodelind g_ModelsCount++ } } } #if DEBUG_MODE == 1 server_print(DEBUG_MSG_END) if (line == 0){ format (logmsg,65,"%s models.ini EMPTY OR NOT FOUND",DEBUG_MSG_ERROR) debugMsg (logmsg) } #endif } // ---- [End of Precache] // ---- [reset models functions] public auto_balance_triggered(){ new id new name [32] new logdata0[128] read_logargv(0,logdata0,127) parse_loguser(logdata0, name, 31) id = get_user_index(name) if(g_ModelStatus[id] != STATUS_MODEL_NOTSET) g_ModelStatus[id] |= STATUS_MODEL_RESET else g_ModelStatus[id] = STATUS_MODEL_NOTSET } public client_infochanged (id){ if(g_ModelStatus[id] != STATUS_MODEL_NOTSET) g_ModelStatus[id] |= STATUS_MODEL_RESET else g_ModelStatus[id] = STATUS_MODEL_NOTSET } public client_command (id) { // check if a player selected another team new arg[13] if (read_argv(0, arg, 12) > 11) return PLUGIN_CONTINUE if (equal("chooseteam",arg) || equal ("jointeam",arg)){ #if DEBUG_MODE == 1 new playername[32] get_user_name (id,playername,31) format(logmsg,191,"%s%s%s(%d)",DEBUG_MSG_LOG,"RESET MODEL OF ",playername,id) debugMsg (logmsg) #endif g_ModelStatus[id] = STATUS_MODEL_NOTSET } return PLUGIN_CONTINUE } public client_disconnect(id) { g_ModelStatus[id] = STATUS_MODEL_NOTSET #if DEBUG_MODE == 1 format (logmsg,191,"%s%s%d",DEBUG_MSG_LOG,"DISCONNECTED slot ",id) debugMsg (logmsg) #endif } // ---- [end of reset models functions] // ---- [set models] public set_players_models(id) { if(!is_user_connected(id)) return PLUGIN_CONTINUE if (cs_get_user_vip(id)) g_ModelStatus[id] = STATUS_MODEL_NOTSET //#if DEBUG_MODE == 1 new playername[32] get_user_name (id,playername,31) //#endif if(g_ModelStatus[id] & STATUS_MODEL_RESET) { if(!(g_ModelStatus[id] & STATUS_MODEL_NOMODEL)) { cs_reset_user_model(id) } g_ModelStatus[id] = STATUS_MODEL_NOTSET } if (g_ModelStatus[id] != STATUS_MODEL_NOTSET && !get_cvar_num("amx_playermodel_round_checkid")) { #if DEBUG_MODE == 1 format (logmsg,191,"%s%s%s(%d)",DEBUG_MSG_LOG,"WON'T SET MODEL THIS TIME BECAUSE IT'S ALREADY BEEN SET ",playername,id) debugMsg (logmsg) #endif return PLUGIN_CONTINUE } //new id = read_data (1) new authid[50] #if DEBUG_MODE == 1 new ip[200] new steamid[32] get_user_ip (id,ip,199) get_user_authid (id,steamid,31) format (logmsg,191,"%s%s%s(%d) - ip:%s, steamid:%s",DEBUG_MSG_LOG," PLAYER CHECK MODEL UPDATE: ",playername,id,ip,steamid) debugMsg (logmsg) #endif // avoid extra processing - models are only set when needed new authtype new checkid new index new currentmodel[32] new params[3] new name[32] get_user_name(id, name, 31) cs_get_user_model(id, currentmodel, 31) for (index = 0; index < g_ModelsCount; index++) { if(equal(g_PlayerId[index], REPLACEMENT_SIGN)) { if(equali(g_PrecachedList[g_ModelInfo[0][index]], currentmodel)) { params[0] = id params[1] = SETMODEL_REPLACE params[2] = index server_print("$$%d", index) //if(task_exists(id)) set_task (0.8,"set_model",id,params,3) return PLUGIN_CONTINUE } } } for (index = 0; index < g_ModelsCount; index ++) { if(equal(g_PlayerId[index], REPLACEMENT_SIGN)) continue check_authtype(id,g_PlayerId[index],authtype,checkid,authid) if (checkid) break } params[0] = id //playerid if (checkid) params[1] = index else if (is_user_bot(id)) { if((g_BotsModel[0]>-1) && (g_BotsModel[1]>-1)) { params[1] = SETMODEL_BOTDEFAULT } else { g_ModelStatus[id] = STATUS_MODEL_NOMODEL return PLUGIN_CONTINUE } } else if(g_DefaultModel[0] > -1 && g_DefaultModel[1] > -1) { params[1] = SETMODEL_DEFAULT } else { g_ModelStatus[id] = STATUS_MODEL_NOMODEL return PLUGIN_CONTINUE } // this delay prevents some bugs. set_task (0.8,"set_model",id,params,3) #if DEBUG_MODE == 1 switch (authtype){ case AUTH_TYPE_BOTNAME: { format (logmsg,191,"%s%s%s(%d)",DEBUG_MSG_LOG,"AUTH TYPE = NAME FOR BOT: ",playername,id) debugMsg (logmsg) } case AUTH_TYPE_STEAMID: { format (logmsg,191,"%s%s%s(%d) - steamid: %s",DEBUG_MSG_LOG,"AUTH TYPE = STEAMID FOR USER: ",playername,id,authid) debugMsg (logmsg) } case AUTH_TYPE_IP: { format (logmsg,191,"%s%s%s(%d) - ip: %s",DEBUG_MSG_LOG,"AUTH TYPE = IP FOR USER: ",playername,id,authid) debugMsg (logmsg) } } #endif return PLUGIN_CONTINUE } public set_model (const params[]){ new id = params[0] // playerid. new ind = params[1] // model index. new team team = get_user_team(id) - 1 if (team>=0 && team<2){ if(ind == SETMODEL_REPLACE) { new ind2 = params[2] if(g_ModelInfo[1][ind2] != NULLINDEX) { cs_set_user_model(id, g_PrecachedList[g_ModelInfo[1][ind2]]) g_ModelStatus[id] = STATUS_MODEL_REPLACEMENT #if DEBUG_MODE == 1 new playername[32] get_user_name(id, playername, 31) format(logmsg, 191, "%s <%s> MODEL REPLACED %s->%s", DEBUG_MSG_LOG, playername, g_PrecachedList[g_ModelInfo[0][ind2]], g_PrecachedList[g_ModelInfo[1][ind2]]) #endif } } //else if(ind & SETMODEL_RESET) // cs_reset_user_model(id) else if(ind == SETMODEL_BOTDEFAULT) { if(g_BotsModel[team] != NULLINDEX) { cs_set_user_model (id, g_PrecachedList[g_BotsModel[team]]) g_ModelStatus[id] = STATUS_MODEL_BOTDEFAULT } } else if(ind == SETMODEL_DEFAULT) { if(g_DefaultModel[team] != NULLINDEX) { cs_set_user_model (id, g_PrecachedList[g_DefaultModel[team]]) g_ModelStatus[id] = STATUS_MODEL_DEFAULT } } else { if(g_ModelInfo[team][ind] != NULLINDEX) { cs_set_user_model (id, g_PrecachedList[g_ModelInfo[team][ind]]) #if DEBUG_MODE == 1 new playername[32] get_user_name (id,playername,31) format (logmsg,191,"%s%s<%s(%d)> HAS BEEN SET TO <%s>",DEBUG_MSG_LOG,"MODEL OF ",playername,id,g_PrecachedList[g_ModelInfo[team][ind]]) debugMsg (logmsg) #endif g_ModelStatus[id] = STATUS_MODEL_SETBYID } } } } // ---- [end of set models]