/** * File: War3Source_Engine_ESCompatLayer.sp * Description: Support for the ES race format. * Since WCS restricts the sale of content, this is a great option for transition! You may sell War3 content forever and always ;] * Author(s): Anthony Iacono and Derek Ownz */ #pragma semicolon 1 #pragma dynamic 40000 #include #include "W3SIncs/War3Source_Interface" #include new String:g_EventList[][32] = { "intro_finish", "intro_nextcamera", "player_changeclass", "player_death", "object_removed", "object_destroyed", "tf_map_time_remaining", "tf_game_over", "ctf_flag_captured", "controlpoint_initialized", "controlpoint_updateimages", "controlpoint_updatelayout", "controlpoint_updatecapping", "controlpoint_updateowner", "controlpoint_starttouch", "controlpoint_endtouch", "controlpoint_pulse_element", "controlpoint_fake_capture", "controlpoint_fake_capture_mult", "teamplay_round_selected", "teamplay_round_start", "teamplay_round_active", "teamplay_waiting_begins", "teamplay_waiting_ends", "teamplay_waiting_abouttoend", "teamplay_restart_round", "teamplay_ready_restart", "teamplay_round_restart_seconds", "teamplay_team_ready", "teamplay_round_win", "teamplay_update_timer", "teamplay_round_stalemate", "teamplay_overtime_begin", "teamplay_overtime_end", "teamplay_suddendeath_begin", "teamplay_suddendeath_end", "teamplay_game_over", "teamplay_map_time_remaining", "teamplay_broadcast_audio", "teamplay_timer_flash", "teamplay_timer_time_added", "teamplay_point_startcapture", "teamplay_point_captured", "teamplay_point_locked", "teamplay_point_unlocked", "teamplay_capture_broken", "teamplay_capture_blocked", "teamplay_flag_event", "teamplay_win_panel", "teamplay_teambalanced_player", "teamplay_setup_finished", "show_freezepanel", "hide_freezepanel", "freezecam_started", "localplayer_changeteam", "localplayer_score_changed", "localplayer_changeclass", "localplayer_respawn", "building_info_changed", "localplayer_changedisguise", "player_account_changed", "spy_pda_reset", "flagstatus_update", "player_stats_updated", "playing_commentary", "player_chargedeployed", "player_builtobject", "player_upgradedobject", "achievement_earned", "spec_target_updated", "tournament_stateupdate", "player_calledformedic", "localplayer_becameobserver", "player_ignited_inv", "player_ignited", "player_extinguished", "player_teleported", "player_healedmediccall", "localplayer_chargeready", "localplayer_winddown", "player_invulned", "escort_speed", "escort_progress", "escort_recede", "client_loadout_changed", "gameui_activated", "gameui_hidden", "player_escort_score", "player_healonhit", "player_stealsandvich", "show_class_layout", "show_vs_panel", "player_damaged", "player_hurt", "arena_player_notification", "arena_match_maxstreak", "arena_round_start", "arena_win_panel", "inventory_updated", "air_dash", "landed", "player_damage_dodged", "player_stunned", "scout_grand_slam", "scout_slamdoll_landed", "arrow_impact", "player_jarated", "player_jarated_fade", "player_shield_blocked", "player_pinned", "player_healedbymedic", "player_spawn", "player_sapped_object", "item_found", "show_annotations", "hide_annotations", "post_inventory_application", "controlpoint_unlock_updated", "deploy_buff_banner", "player_buff", "medic_death", "overtime_nag", "teams_changed", "halloween_pumpkin_grab", "rocket_jump", "rocket_jump_landed", "sticky_jump", "sticky_jump_landed", "medic_defended", "localplayer_healed", "player_destroyed_pipebomb", "object_deflected", "player_mvp", "raid_spawn_mob", "raid_spawn_squad", "nav_blocked", "path_track_passed", "num_cappers_changed", "player_regenerate", "update_status_item", "cart_updated", "store_pricesheet_updated", "stats_resetround", "gc_connected", "item_schema_initialized", "achievement_earned_local", "player_healed", "item_pickup", "duel_status", "fish_notice", "pumpkin_lord_summoned", "pumpkin_lord_killed", "bomb_abortdefuse", "bomb_abortplant", "bomb_beep", "bomb_begindefuse", "bomb_beginplant", "bomb_defused", "bomb_dropped", "bomb_exploded", "bomb_pickup", "bomb_planted", "break_breakable", "break_prop", "bullet_impact", "door_moving", "flashbang_detonate", "game_end", "game_message", "game_start", "grenade_bounce", "hegrenade_detonate", "hostage_call_for_help", "hostage_follows", "hostage_hurt", "hostage_killed", "hostage_rescued", "hostage_rescued_all", "hostage_stops_following", "player_activate", "player_blind", "player_changename", "player_chat", "player_class", "player_connect", "player_disconnect", "player_falldamage", "player_footstep", "player_info", "player_jump", "player_radio", "player_say", "player_score", "player_shoot", "player_team", "player_use", "round_end", "round_freeze_end", "round_start", "server_addban", "server_cvar", "server_message", "server_removeban", "server_shutdown", "smokegrenade_detonate", "vip_escaped", "vip_killed", "weapon_fire", "weapon_fire_on_empty", "weapon_reload", "weapon_zoom", "nav_generate" }; new String:g_EventKeyList[][32] = { "userid", "attacker", "weapon", "headshot", "health", "armor", "dmg_health", "dmg_armor", "hitgroup", "site", "posx", "posy", "haskit", "hostage", "slot", "entindex", "item", "x", "y", "z", "damage", "area", "blocked", "teamid", "teamname", "score", "oldteam", "disconnect", "autoteam", "silent", "name", "class", "teamonly", "text", "kills", "deaths", "mode", "entity", "oldname", "newname", "mapname", "roundslimit", "timelimit", "fraglimit", "objective", "winner", "reason", "message", "target", "material", "entindex_killed", "entindex_attacker", "entindex_inflictor", "damagebits", "numadvanced", "numbronze", "numsilver", "numgold", "achievement_name", "cur_val", "max_val", "achievement_id", "hostname", "address", "port", "game", "maxplayers", "os", "dedicated", "password", "cvarname", "cvarvalue", "networkid", "ip", "duration", "by", "kicked", "bot", "player", "victim_entindex", "inflictor_entindex", "weaponid", "customkill", "assister", "weapon_logclassname", "stun_flags", "death_flags", "silent_kill", "dominated", "assister_dominated", "revenge", "assister_revenge", "first_blood", "feign_death", "objecttype", "index", "was_building", "seconds", "capping_team", "capping_team_score", "int_data", "full_reset", "winreason", "team", "flagcaplimit", "full_round", "round_time", "losing_team_num_caps", "was_sudden_death", "sound", "time_remaining", "timer", "seconds_added", "cp", "cpname", "capteam", "cappers", "captime", "blocker", "carrier", "eventtype", "panel_style", "winning_team", "blue_score", "red_score", "blue_score_prev", "red_score_prev", "round_complete", "rounds_remaining", "player_1", "player_1_points", "player_2", "player_2_points", "player_3", "player_3_points", "killer", "object_mode", "building_type", "remove", "disguised", "old_value", "new_value", "forceupload", "isbuilder", "achievement", "namechange", "readystate", "pyro_entindex", "medic_entindex", "dist", "medic_userid", "speed", "players", "progress", "reset", "recedetime", "points", "owner", "amount", "show", "damageamount", "crit", "minicrit", "allseecrit", "streak", "player_1_healing", "player_1_damage", "player_1_lifetime", "player_1_kills", "player_2_healing", "player_2_damage", "player_2_lifetime", "player_2_kills", "player_3_healing", "player_3_damage", "player_3_lifetime", "player_3_kills", "player_4_healing", "player_4_damage", "player_4_lifetime", "player_4_kills", "player_5_healing", "player_5_damage", "player_5_lifetime", "player_5_kills", "player5", "player_6_healing", "player_6_damage", "player_6_lifetime", "player_6_kills", "player6", "victim_capping", "stunner", "big_stun", "scout_id", "target_id", "attachedEntity", "shooter", "boneIndexAttached", "bonePositionX", "bonePositionY", "bonePositionZ", "boneAnglesX", "boneAnglesY", "boneAnglesZ", "thrower_entindex", "pinned", "sapperid", "quality", "method", "propername", "worldPosX", "worldPosY", "worldPosZ", "buff_type", "buff_owner", "healing", "charged", "count", "patient", "healer", "score_type", "initiator", "initiator_score", "target_score" }; new Handle:hCurrentEventData = INVALID_HANDLE; new Handle:hWCSRaces = INVALID_HANDLE; public Plugin:myinfo = { name = "War3 Engine ESCompatLayer", author = "Anthony & Ownz", description = "Support for the ES race format.", version = "1.0.0.0", url = "http://war3source.com" }; bool:ESCheck() { new Handle:hVar = FindConVar("eventscripts_ver"); if(hVar) { return true; } return false; } bool:ESTCheck() { new Handle:hVar = FindConVar("est_version"); if(hVar) { return true; } return false; } String:firstchar(const String:buffer[]) { return buffer[0]; } String:lastchar(const String:buffer[]) { return buffer[strlen(buffer)-1]; } new Handle:g_ToDelete = INVALID_HANDLE; // Last resort to help with the handles. ClearDeletionQueue() { ClearArray(g_ToDelete); } AddToDeletionQueue(Handle:h) { new c = GetArraySize(g_ToDelete); new bool:found=false; for(new x=0;x0) // Else, empty line. { new String:first=firstchar(line); new String:last=lastchar(line); if(first=='#') { continue; // This line is a comment. } else if(first=='[') { if(len<2) { error_type = 2; // parsing error (no section defined) lnum = lnum_track; return false; } if(last==']') { if(line[1]=='[') { if(line[len-2]==']') { // Take from 2 - len-3 if(len<5) { error_type = 2; // parsing error lnum = lnum_track; return false; } else { if(!sectionKV) { error_type = 2; // parsing error lnum = lnum_track; return false; } strcopy(currentSubsection, len-3, line[2]); } } else { error_type = 2; // parsing error lnum = lnum_track; return false; } } else { if(len<3) { error_type = 2; // parsing error lnum = lnum_track; return false; } strcopy(currentSection, len-1, line[1]); if(!WCSValidSection(currentSection)) { error_type = 2; // parsing error lnum = lnum_track; return false; } Format(currentSubsection, sizeof(currentSubsection), ""); sectionKV = CreateKeyValues(currentSection); keysArray = CreateArray(64); AddToDeletionQueue(sectionKV); AddToDeletionQueue(keysArray); KvSetNum(sectionKV, "keys", _:keysArray); PushArrayCell(arrayHandle, sectionKV); } } else { error_type = 2; // parsing error (no section defined) lnum = lnum_track; return false; } } else { // This must be a: // something = value // or // something="value" if(!sectionKV) { error_type = 2; // parsing error (no section defined) lnum = lnum_track; return false; } new String:keyName[64]; new String:keyValue[1024]; new cur_state = 0; // scanning name // 1 = scanning value for(new x=0;x='A' && kName[x]<='Z') || (kName[x]>='a' && kName[x]<='z') || (kName[x]>='0' && kName[x]<='9') || kName[x]==' ' || kName[x]=='_' || kName[x]=='=' || kName[x]=='-' || kName[x]=='.' || kName[x]=='!' || kName[x]==',' || kName[x]=='<' || kName[x]=='>')) { return false; } } return true; } bool:WCSValidKeyName(const String:kName[]) { new len=strlen(kName); if(len<1) { return false; } for(new x=0;x='A' && kName[x]<='Z') || (kName[x]>='a' && kName[x]<='z') || (kName[x]>='0' && kName[x]<='9') || kName[x]==' ' || kName[x]=='_')) { return false; } } return true; } public TestRecurse(Handle:kv) { new index = 1; new String:keyName[256]; while(KvFindKeyById(kv, index, keyName, 256)) { PrintToServer("%d: %s", index, keyName); index++; } } KeyToAlias(const String:keyName[], numberOfSkills, String:aliasName[], maxAliasLength) { for(new x=1;x<=numberOfSkills;x++) { new String:keyNameCheck[128]; Format(keyNameCheck, sizeof(keyNameCheck), "skill%d_racealias_", x); new String:keyNameCheck2[128]; Format(keyNameCheck2, strlen(keyNameCheck)+1, "%s", keyName); if(StrEqual(keyNameCheck, keyNameCheck2)) { if(strlen(keyName)>strlen(keyNameCheck)) { Format(aliasName, maxAliasLength, "racealias_%s", keyName[strlen(keyNameCheck)]); return x; } } } return 0; } War3_LoadWCSRaces() { new ecode; new lnum; new String:racesPath[1024]; BuildPath(Path_SM, racesPath, sizeof(racesPath), "configs/races.ini"); new Handle:fileArray = CreateArray(); new Handle:fHandle = INVALID_HANDLE; new bool:result = wcsfile_parse(racesPath, fileArray, ecode, lnum, fHandle); if(fHandle) { CloseHandle(fHandle); } if(!result) { ExecDeletionQueue(); // Auto clean up. if(ecode==1) { if(FileExists(racesPath)) { PrintToServer("[War3Source] Error opening configs/races.ini even though it exists."); } } else if(ecode==2) { PrintToServer("[War3Source] Error parsing WCS race file at line %d.", lnum); } } else { // Things will be deleted properly without the delete queue, just clear it. ClearDeletionQueue(); new size = GetArraySize(fileArray); for(new x=0;x0) { WCS_AddSkillAlias(raceID, skillNum, aliasName, keyValue); } } WCS_EndCreateRace(raceID); CloseHandle(curRace); // Close key value. CloseHandle(keysArray); // Close list of all key names. } PrintToServer("Total of %d races", size); } CloseHandle(fileArray); // Close the array of key values. } public OnMapStart() { ClearDeletionQueue(); WCSRacesClean(); War3_LoadWCSRaces(); } WCSRacesClean() { new wcsCount = GetArraySize(hWCSRaces); for(new x=0;x0) { Format(tString, sizeof(tString), "%s_minlevel", shortName); new var = W3FindCvar(tString); new String:tString2[1024]; Format(tString2, sizeof(tString2), "%d", required); if(var>=0) { W3SetCvar(var, tString2); } } if(!StrEqual(restrictitem,"") && !StrEqual(restrictitem,"0")) { Format(tString, sizeof(tString), "%s_restrict_items", shortName); new var = W3FindCvar(tString); if(var>=0) { W3SetCvar(var, restrictitem); } } if(restrictteam>1) { if(restrictteam==2) { Format(tString, sizeof(tString), "%s_team1_limit", shortName); } else if(restrictteam==3) { Format(tString, sizeof(tString), "%s_team2_limit", shortName); } new var = W3FindCvar(tString); if(var>=0) { W3SetCvar(var, "0"); } } return raceID; // Well I guess as a sanity check, make sure number of skills is greater than 0. } Handle:WCS_RaceOfRaceID(raceID) { new wcsCount = GetArraySize(hWCSRaces); for(new x=0;x='A' && buffer[x]<='Z') || (buffer[x]>='a' && buffer[x]<='z') || (buffer[x]>='0' && buffer[x]<='9') ) { Format(out, maxlen, "%s%c", out, CharToLower(buffer[x])); } } } // War3Source Functions public OnPluginStart() { g_ToDelete = CreateArray(); hWCSRaces = CreateArray(); ClearDeletionQueue(); RegServerCmd("war3_if", War3EngIf, "Logical statement."); RegServerCmd("war3_xif", War3EngXIf, "Non-expanded logical statement."); RegServerCmd("war3_setinfo", War3EngSetinfo, "Set a server variable."); RegServerCmd("war3_xsetinfo", War3EngXSetinfo, "Non expanded, set a server variable."); RegServerCmd("war3_set", War3EngSetinfo, "Set a server variable."); RegServerCmd("war3_xset", War3EngXSetinfo, "Non expanded, set a server variable."); RegServerCmd("war3_cmd", War3EngCmd, "Expanded command."); RegServerCmd("war3_getplayerlocation", War3EngGetPlayerLocation, "Expanded get player location."); RegServerCmd("war3_xgetplayerlocation", War3EngXGetPlayerLocation, "Non-expanded get player location."); RegServerCmd("war3_effect", War3EngEffect, "Expanded effect."); RegServerCmd("war3_xeffect", War3EngXEffect, "Non-expanded effect."); if(!ESCheck()) { RegServerCmd("es_if", War3EngIf, "Logical statement."); RegServerCmd("es_xif", War3EngXIf, "Non-expanded logical statement."); RegServerCmd("if", War3EngIf, "Logical statement."); RegServerCmd("es_set", War3EngSetinfo, "Set a server variable."); RegServerCmd("es_xset", War3EngXSetinfo, "Non expanded, set a server variable."); RegServerCmd("es", War3EngCmd, "Expanded command."); RegServerCmd("es_getplayerlocation", War3EngGetPlayerLocation, "Expanded get player location."); RegServerCmd("es_xgetplayerlocation", War3EngXGetPlayerLocation, "Non-expanded get player location."); } if(!ESTCheck()) { RegServerCmd("est_effect", War3EngEffect, "Expanded effect."); RegServerCmd("est_xeffect", War3EngXEffect, "Non-expanded effect."); } for(new x=0;x0) { new race = War3_GetRace(client); new Handle:wcsRace = WCS_RaceOfRaceID(race); if(wcsRace!=INVALID_HANDLE) { new String:spawnCmd[4096]; GetArrayString(wcsRace, 10, spawnCmd, sizeof(spawnCmd)); if(!StrEqual(spawnCmd, "")) { // PrintToServer(spawnCmd); ServerCommand("%s\n", spawnCmd); } } } } } bool:EventExists(const String:eventName[]) { new Handle:hTest = CreateEvent(eventName, true); if(hTest) { CancelCreatedEvent(hTest); return true; } return false; } bool:validExpressionChar(String:chr) { if(chr=='-' || chr=='.' || (chr>='0' && chr<='9') || (chr>='a' && chr<='z') || (chr>='A' && chr<='Z') || chr=='_' || chr=='(' || chr==')') { return true; } return false; } bool:validExpressionChar2(String:chr) { if(validExpressionChar(chr) || chr=='>' || chr=='<' || chr=='=' || chr=='!') { return true; } return false; } bool:IsNumber(const String:buffer[]) { new bool:decimal=false; new len = strlen(buffer); for(new x=0;x'9') { return false; } } return true; } bool:nextchar(const String:buffer[], index, &String:nextchar) { if(strlen(buffer)>index+1) { nextchar = buffer[index+1]; return true; } return false; } bool:nextcharnonwhite(const String:buffer[], index, &String:nextchar, &fIndex) { new len = strlen(buffer); for(new x=index+1;x5)) { PrintToServer("TODO: Error with syntax"); return Plugin_Handled; } Format(afterStart, sizeof(afterStart), "%s", afterStart[5]); TrimString(afterStart); if(expand) { ExpandVars(value1, sizeof(value1)); ExpandVars(operatorstr, sizeof(operatorstr)); ExpandVars(value2, sizeof(value2)); ExpandVars(afterStart, sizeof(afterStart)); } TrimString(operatorstr); if(StrEqual(operatorstr,"==") || StrEqual(operatorstr,"=") || StrEqual(operatorstr,"equalto", false)) { if(IsNumber(value1) && IsNumber(value2)) { if(StringToFloat(value1)==StringToFloat(value2)) { ServerCommand("%s\n", afterStart); } } else { if(StrEqual(value1,value2)) { ServerCommand("%s\n", afterStart); } } } else if(StrEqual(operatorstr,"!=") || StrEqual(operatorstr,"notequalto", false)) { if(IsNumber(value1) && IsNumber(value2)) { if(StringToFloat(value1)!=StringToFloat(value2)) { ServerCommand("%s\n", afterStart); } } else { if(!StrEqual(value1,value2)) { ServerCommand("%s\n", afterStart); } } } else if(StrEqual(operatorstr,">") || StrEqual(operatorstr,"greaterthan", false)) { if(IsNumber(value1) && IsNumber(value2)) { if(StringToFloat(value1)>StringToFloat(value2)) { ServerCommand("%s\n", afterStart); } } } else if(StrEqual(operatorstr,"<") || StrEqual(operatorstr,"lessthan", false)) { if(IsNumber(value1) && IsNumber(value2)) { if(StringToFloat(value1)=") || StrEqual(operatorstr,"notlessthan", false)) { if(IsNumber(value1) && IsNumber(value2)) { if(StringToFloat(value1)>=StringToFloat(value2)) { ServerCommand("%s\n", afterStart); } } } else if(StrEqual(operatorstr,"<=") || StrEqual(operatorstr,"notgreaterthan", false)) { if(IsNumber(value1) && IsNumber(value2)) { if(StringToFloat(value1)>=StringToFloat(value2)) { ServerCommand("%s\n", afterStart); } } } return Plugin_Handled; } W3VarByStr(const String:lookup[]) { for(new x=0;x=0;x--) { if(StrContains(buffer[x], "server_var(", false)==0) { pos2 = x; break; } else if(StrContains(buffer[x], "event_var(", false)==0) { pos2 = x; vType = 1; break; } else if(StrContains(buffer[x], "war3_int(", false)==0) { pos2 = x; vType = 2; break; } else if(StrContains(buffer[x], "war3_float(", false)==0) { pos2 = x; vType = 3; break; } } if(pos2==-1) { return false; } new String:collectSymbol[64]; new bool:endFound = false; new bool:hasStarted = false; new endAt; new offset = 0; if(vType==0) { offset = 11; } else if(vType==1) // event_var( { offset = 10; } else if(vType==2) // war3_int( { offset = 9; } else // war3_float( { offset = 11; } for(new x=(pos2+offset);x Creates a armour ricochet effect. est_Effect 02 Creates a beam ent point effect. est_Effect 03 Creates a beam ents effect. est_Effect 04 Creates a beam ent follow effect est_Effect 05 Creates a beam laser effect. est_Effect 06 Creates a Beam Points Effect. est_Effect 07 Creates a beam Beam Ring Ent Effect. est_Effect 08 Creates a Beam Ring Ent Effect. est_Effect 09 Creates a Beam Spline Effect. est_Effect 10 Creates a Blood Sprite Effect. est_Effect 11 Creates a Blood Stream Effect. est_Effect 12