(HL2DM) zombies

A place for requesting new Source.Python plugins to be made for your server.

Please request only one plugin per thread.
User avatar
daren adler
Senior Member
Posts: 328
Joined: Sat May 18, 2019 7:42 pm

(HL2DM) zombies

Postby daren adler » Wed Jun 10, 2020 5:58 am

Hello :smile: Found this old sourcemod plugin that was used years ago, To set up your spawn spots for npc to auto spawn and kill or be killed. then they auto spawn after death, Was wondering if someone would like to take a look at it and make it a SP :wink: :wink: here the site https://forums.alliedmods.net/showthread.php?p=1255826 and heres plugin.

Code: Select all

#include <sourcemod>
#include <sdktools>

static String:ZombieSpawn[1001][128];
new Handle:CanSpawn;
new Handle:Population;
new Handle:Frequency;

public Plugin:myinfo =
{
    name = "Dynamic NPC Spawner",
    author = "Alm",
    description = "Spawns NPCs randomly around the map.",
    version = "1.1",
    url = "http://www.roflservers.com/"
};

stock PrepFile(const String:FileName[])
{
   if(!FileExists(FileName))
   {
      decl Handle:File;
      File = OpenFile(FileName, "w+");
      CloseHandle(File);
   }
}

public OnPluginStart()
{
   PrepFile("cfg/zombiepopulations.cfg");
   PrepFile("cfg/zombiefrequencies.cfg");

   RegAdminCmd("z_addspawn", AddSpawn, ADMFLAG_CHEATS, "Creates a new zombie spawn where you stand.");
   
   CanSpawn = CreateConVar("z_enabled", "1", "Determines if zombies will be spawned.");
   Population = CreateConVar("z_population", "default", "Determines which zombie population to spawn.");
   Frequency = CreateConVar("z_frequency", "default", "Determines how often zombies will spawn.");

   new Refire = GetRefire();
   CreateTimer(float(Refire), PluginLifeTimer);

   HookEntityOutput("npc_zombie", "OnDeath", ZombieDeath);
}

public ZombieDeath(const String:output[], NPC, Killer, Float:Delay)
{
   CreateTimer(0.1, HeadcrabAI);
}

public Action:HeadcrabAI(Handle:Timer)
{
   decl String:Class[128];

   for(new NPC = 1; NPC < 3000; NPC++)
   {
      if(IsValidEdict(NPC) && IsValidEntity(NPC))
      {
         GetEdictClassname(NPC, Class, 128);
         
         if(StrEqual(Class, "npc_headcrab", false))
         {
            SetVariantString("player D_HT");
            AcceptEntityInput(NPC, "setrelationship");
         }
      }
   }
}

enum dirMode
{
    o=777,
    g=777,
    u=777
}

public OnMapStart()
{
   for(new Reset = 1; Reset <= 1000; Reset++)
   {
      ZombieSpawn[Reset] = "null";
   }

   decl String:DirMap[128];
   GetCurrentMap(DirMap, 128);

   decl String:TryDir[255];
   Format(TryDir, 255, "cfg/%s", DirMap);

   if(!DirExists(TryDir))
   {
      CreateDirectory(TryDir, dirMode);
   }
      
   new GotCount = 0;
   decl String:EntClass[128];
   decl Float:EntOrg[3];

   for(new Ents = 1; Ents < 3000; Ents++)
   {
      if(IsValidEdict(Ents) && IsValidEntity(Ents) && GotCount < 1000)
      {
         GetEdictClassname(Ents, EntClass, 128);

         if(StrEqual(EntClass, "info_npc_spawn_destination", false))
         {
            GotCount++;
            GetEntPropVector(Ents, Prop_Data, "m_vecOrigin", EntOrg);
            Format(ZombieSpawn[GotCount], 128, "%f %f %f", EntOrg[0], EntOrg[1], EntOrg[2]);
            RemoveEdict(Ents);
         }
      }
   }

   if(GotCount < 1000)
   {
      decl String:MapName[128];
      GetCurrentMap(MapName, 128);

      decl String:WatFile[128];
      Format(WatFile, 128, "cfg/%s/zombiespawns.cfg", MapName);
      PrepFile(WatFile);

      AddSpawnsFromFile(MapName);
   }
}

stock GetSpawnCount()
{
   new ValidSpawns = 0;

   for(new Count = 1; Count <= 1000; Count++)
   {
      if(!StrEqual(ZombieSpawn[Count], "null", false))
      {
         ValidSpawns++;
      }
   }

   return ValidSpawns;
}

public GetRefire()
{
   decl Handle:File;
   File = OpenFile("cfg/zombiefrequencies.cfg", "r");

   decl String:SectionName[128];
   GetConVarString(Frequency, SectionName, 128);

   new bool:RightSection = false;
   new bool:FoundLine = false;

   decl String:FileLine[128];
   FileSeek(File, 0, SEEK_SET);

   while(!IsEndOfFile(File) && ReadFileLine(File, FileLine, 128))
   {
      TrimString(FileLine);

      if(StrEqual(FileLine, "}", false))
      {
         RightSection = false;
         continue;
      }

      if(StrEqual(FileLine, "{", false) || StrEqual(FileLine, "", false) || StrEqual(FileLine, " ", false))
      {
         continue;
      }

      if(!RightSection && StrEqual(FileLine, SectionName, false))
      {
         RightSection = true;
         continue;
      }

      if(RightSection && StrContains(FileLine, "refire", false) == 0)
      {
         FoundLine = true;
         break;
      }
   }

   CloseHandle(File);

   if(!FoundLine)
   {
      return 60;
   }

   decl String:Exploded[2][128];
   ExplodeString(FileLine, "=", Exploded, 2, 128);

   if(StrContains(Exploded[1], "-", false) == -1)
   {
      return StringToInt(Exploded[1]);
   }

   decl String:RandomPicks[2][128];
   ExplodeString(Exploded[1], "-", RandomPicks, 2, 128);

   return GetRandomInt(StringToInt(RandomPicks[0]), StringToInt(RandomPicks[1]));
}

public AddSpawnsFromFile(const String:MapName[])
{
   new SpawnCount = GetSpawnCount();

   decl String:WatFile[128];
   Format(WatFile, 128, "cfg/%s/zombiespawns.cfg", MapName);

   decl Handle:File;
   File = OpenFile(WatFile, "r");

   decl String:FileLine[128];
   FileSeek(File, 0, SEEK_SET);

   while(!IsEndOfFile(File) && ReadFileLine(File, FileLine, 128))
   {
      TrimString(FileLine);

      SpawnCount++;
      strcopy(ZombieSpawn[SpawnCount], 128, FileLine);

      if(SpawnCount >= 1000)
      {
         CloseHandle(File);
         return;
      }
   }

   CloseHandle(File);
   return;
}

public Action:AddSpawn(Client, Args)
{
   if(Client == 0)
   {
      ReplyToCommand(Client, "[SM] Can't create new spawns from RCON.");
      return Plugin_Handled;
   }

   if(GetSpawnCount() >= 1000)
   {
      ReplyToCommand(Client, "[SM] Spawn limit has been reached. (1000)");
      return Plugin_Handled;
   }

   decl Float:ClientPos[3];
   GetClientAbsOrigin(Client, ClientPos);

   decl String:MapName[128];
   GetCurrentMap(MapName, 128);

   decl String:WatFile[128];
   Format(WatFile, 128, "cfg/%s/zombiespawns.cfg", MapName);

   new SpawnCount = GetSpawnCount();
   SpawnCount++;

   Format(ZombieSpawn[SpawnCount], 128, "%f %f %f", ClientPos[0], ClientPos[1], ClientPos[2]);

   decl Handle:File;
   File = OpenFile(WatFile, "a");

   FileSeek(File, 0, SEEK_END);
   WriteFileLine(File, "%f %f %f", ClientPos[0], ClientPos[1], ClientPos[2]);
   CloseHandle(File);
         
   ReplyToCommand(Client, "[SM] Added new zombie spawn. (%s)", ZombieSpawn[SpawnCount]);

   return Plugin_Handled;
}

public GetSpawnAmount()
{
   decl Handle:File;
   File = OpenFile("cfg/zombiefrequencies.cfg", "r");

   decl String:SectionName[128];
   GetConVarString(Frequency, SectionName, 128);

   new bool:RightSection = false;
   new bool:FoundLine = false;

   decl String:FileLine[128];
   FileSeek(File, 0, SEEK_SET);

   while(!IsEndOfFile(File) && ReadFileLine(File, FileLine, 128))
   {
      TrimString(FileLine);

      if(StrEqual(FileLine, "}", false))
      {
         RightSection = false;
         continue;
      }

      if(StrEqual(FileLine, "{", false) || StrEqual(FileLine, "", false) || StrEqual(FileLine, " ", false))
      {
         continue;
      }

      if(!RightSection && StrEqual(FileLine, SectionName, false))
      {
         RightSection = true;
         continue;
      }

      if(RightSection && StrContains(FileLine, "spawns", false) == 0)
      {
         FoundLine = true;
         break;
      }
   }

   CloseHandle(File);

   if(!FoundLine)
   {
      return 1;
   }

   decl String:Exploded[2][128];
   ExplodeString(FileLine, "=", Exploded, 2, 128);

   if(StrContains(Exploded[1], "-", false) == -1)
   {
      return StringToInt(Exploded[1]);
   }

   decl String:RandomPicks[2][128];
   ExplodeString(Exploded[1], "-", RandomPicks, 2, 128);

   return GetRandomInt(StringToInt(RandomPicks[0]), StringToInt(RandomPicks[1]));
}

public GetMaxNPCS()
{
   decl Handle:File;
   File = OpenFile("cfg/zombiefrequencies.cfg", "r");

   decl String:SectionName[128];
   GetConVarString(Frequency, SectionName, 128);

   new bool:RightSection = false;
   new bool:FoundLine = false;

   decl String:FileLine[128];
   FileSeek(File, 0, SEEK_SET);

   while(!IsEndOfFile(File) && ReadFileLine(File, FileLine, 128))
   {
      TrimString(FileLine);

      if(StrEqual(FileLine, "}", false))
      {
         RightSection = false;
         continue;
      }

      if(StrEqual(FileLine, "{", false) || StrEqual(FileLine, "", false) || StrEqual(FileLine, " ", false))
      {
         continue;
      }

      if(!RightSection && StrEqual(FileLine, SectionName, false))
      {
         RightSection = true;
         continue;
      }

      if(RightSection && StrContains(FileLine, "max", false) == 0)
      {
         FoundLine = true;
         break;
      }
   }

   CloseHandle(File);

   if(!FoundLine)
   {
      return 1000;
   }

   decl String:Exploded[2][128];
   ExplodeString(FileLine, "=", Exploded, 2, 128);

   return StringToInt(Exploded[1]);
}

public GetNPCCount()
{
   decl String:CurPop[128];
   GetConVarString(Population, CurPop, 128);

   decl Handle:File;
   File = OpenFile("cfg/zombiepopulations.cfg", "r");

   new bool:RightSection = false;

   new TypeCount = 0;

   decl String:Exploded[2][128];

   decl String:FileLine[128];
   FileSeek(File, 0, SEEK_SET);

   while(!IsEndOfFile(File) && ReadFileLine(File, FileLine, 128))
   {
      TrimString(FileLine);

      if(StrEqual(FileLine, "}", false))
      {
         RightSection = false;
         continue;
      }

      if(StrEqual(FileLine, "{", false) || StrEqual(FileLine, "", false) || StrEqual(FileLine, " ", false))
      {
         continue;
      }

      if(!RightSection && StrEqual(FileLine, CurPop, false))
      {
         RightSection = true;
         continue;
      }

      if(RightSection)
      {
         TypeCount++;
      }
   }

   if(TypeCount == 0)
   {
      return 0;
   }

   decl String:NPCType[TypeCount+1][128];

   new TypeCount2 = 0;
   FileSeek(File, 0, SEEK_SET);

   while(!IsEndOfFile(File) && ReadFileLine(File, FileLine, 128))
   {
      TrimString(FileLine);

      if(StrEqual(FileLine, "}", false))
      {
         RightSection = false;
         continue;
      }

      if(StrEqual(FileLine, "{", false) || StrEqual(FileLine, "", false) || StrEqual(FileLine, " ", false))
      {
         continue;
      }

      if(!RightSection && StrEqual(FileLine, CurPop, false))
      {
         RightSection = true;
         continue;
      }

      if(RightSection)
      {
         TypeCount2++;
         ExplodeString(FileLine, "=", Exploded, 2, 128);
         strcopy(NPCType[TypeCount2], 128, Exploded[0]);
      }
   }

   CloseHandle(File);

   new FinalCount = 0;
   new TestClass = 0;
   decl String:EntClass[128];

   for(new Ents = 1; Ents < 3000; Ents++)
   {
      if(IsValidEdict(Ents) && IsValidEntity(Ents))
      {
         GetEdictClassname(Ents, EntClass, 128);

         if(StrContains(EntClass, "npc_", false) == 0)
         {
            ReplaceString(EntClass, 128, "npc_", " ", false);

            TrimString(EntClass);
            
            for(TestClass = 1; TestClass <= TypeCount; TestClass++)
            {
               if(StrEqual(EntClass, NPCType[TestClass], false))
               {
                  FinalCount++;
               }
            }
         }
      }
   }

   return FinalCount;
}

public GetRandomZombieType(String:ZombieType[], stringlength)
{
   decl String:CurPop[128];
   GetConVarString(Population, CurPop, 128);

   decl Handle:File;
   File = OpenFile("cfg/zombiepopulations.cfg", "r");

   new bool:RightSection = false;

   new TypeCount = 0;

   decl String:FileLine[128];
   FileSeek(File, 0, SEEK_SET);

   while(!IsEndOfFile(File) && ReadFileLine(File, FileLine, 128))
   {
      TrimString(FileLine);

      if(StrEqual(FileLine, "}", false))
      {
         RightSection = false;
         continue;
      }

      if(StrEqual(FileLine, "{", false) || StrEqual(FileLine, "", false) || StrEqual(FileLine, " ", false))
      {
         continue;
      }

      if(!RightSection && StrEqual(FileLine, CurPop, false))
      {
         RightSection = true;
         continue;
      }

      if(RightSection)
      {
         TypeCount++;
      }
   }

   if(TypeCount == 0)
   {
      return;
   }

   decl String:NPCType[TypeCount+1][128];

   new TypeCount2 = 0;
   FileSeek(File, 0, SEEK_SET);

   while(!IsEndOfFile(File) && ReadFileLine(File, FileLine, 128))
   {
      TrimString(FileLine);

      if(StrEqual(FileLine, "}", false))
      {
         RightSection = false;
         continue;
      }

      if(StrEqual(FileLine, "{", false) || StrEqual(FileLine, "", false) || StrEqual(FileLine, " ", false))
      {
         continue;
      }

      if(!RightSection && StrEqual(FileLine, CurPop, false))
      {
         RightSection = true;
         continue;
      }

      if(RightSection)
      {
         TypeCount2++;
         strcopy(NPCType[TypeCount2], 128, FileLine);
      }
   }

   CloseHandle(File);

   new GotType = GetRandomInt(1, TypeCount);

   strcopy(ZombieType, stringlength, NPCType[GotType]);
   return;
}

public Occupied(Node)
{
   decl String:NodePoints[3][128];
   ExplodeString(ZombieSpawn[Node], " ", NodePoints, 3, 128);

   decl Float:NodeOrg[3];
   NodeOrg[0] = StringToFloat(NodePoints[0]);
   NodeOrg[1] = StringToFloat(NodePoints[1]);
   NodeOrg[2] = StringToFloat(NodePoints[2]);

   decl Float:EntOrg[3];
   decl String:EntClass[128];
   
   for(new Ents = 1; Ents < 3000; Ents++)
   {
      if(IsValidEdict(Ents) && IsValidEntity(Ents))
      {
         GetEdictClassname(Ents, EntClass, 128);

         if(StrContains(EntClass, "npc_", false) == 0)
         {
            GetEntPropVector(Ents, Prop_Send, "m_vecOrigin", EntOrg);
         }
         else
         {
            GetEntPropVector(Ents, Prop_Data, "m_vecOrigin", EntOrg);
         }

         if(Ents <= GetMaxClients())
         {
            if(GetVectorDistance(EntOrg, NodeOrg) <= 200)
            {
               return true;
            }
         }
         else
         {
            if(GetVectorDistance(EntOrg, NodeOrg) <= 100)
            {
               return true;
            }
         }
      }
   }

   return false;
}

public SpawnZombie()
{
   decl String:ZombieType[128];
   GetRandomZombieType(ZombieType, 128);
   decl String:SpawnZombieType[128];
   Format(SpawnZombieType, 128, "npc_%s", ZombieType);

   new NodeCount = 0;
   new CurrentNode = 1;

   while(CurrentNode <= GetSpawnCount())
   {
      if(!Occupied(CurrentNode))
      {
         NodeCount++;
      }
      CurrentNode++;
   }

   if(NodeCount == 0)
   {
      return;
   }

   decl ChooseNode[NodeCount+1];
   
   NodeCount = 0;
   CurrentNode = 1;

   while(CurrentNode <= GetSpawnCount())
   {
      if(!Occupied(CurrentNode))
      {
         NodeCount++;
         ChooseNode[NodeCount] = CurrentNode;
      }
      CurrentNode++;
   }

   new RandomNode = ChooseNode[GetRandomInt(1,NodeCount)];

   new Zombie = CreateEntityByName(SpawnZombieType);

   decl String:NodePoints[3][128];
   ExplodeString(ZombieSpawn[RandomNode], " ", NodePoints, 3, 128);

   decl Float:NodeOrg[3];
   NodeOrg[0] = StringToFloat(NodePoints[0]);
   NodeOrg[1] = StringToFloat(NodePoints[1]);
   NodeOrg[2] = StringToFloat(NodePoints[2]);

   NodeOrg[2] += 15.0;

   decl String:OrgString[128];
   Format(OrgString, 128, "%f %f %f", NodeOrg[0], NodeOrg[1], NodeOrg[2]);
   
   DispatchKeyValue(Zombie, "origin", OrgString);

   new Float:Angle = GetRandomFloat(0.0, 359.9);
   
   decl String:AngleString[128];
   Format(AngleString, 128, "0 %f 0", Angle);

   DispatchKeyValue(Zombie, "angles", AngleString);

   DispatchSpawn(Zombie);

   SetVariantString("player D_HT");
   AcceptEntityInput(Zombie, "setrelationship");

   return;
}

public Action:PluginLifeTimer(Handle:Timer)
{
   if(GetConVarBool(CanSpawn))
   {
      new NewSpawns = GetSpawnAmount();

      while((NewSpawns+GetNPCCount()) > GetMaxNPCS())
      {
         NewSpawns--;
         
         if(NewSpawns == 0)
         {
            break;
         }
      }

      if(NewSpawns > 0)
      {
         for(new DoSpawn = 1; DoSpawn <= NewSpawns; DoSpawn++)
         {
            SpawnZombie();
         }
      }
   }

   new Refire = GetRefire();
   CreateTimer(float(Refire), PluginLifeTimer);
}


Heres the setup
ZOMBIES
The Dynamic NPC Spawner

Cvars
z_enabled : 0/1 Enabled or disable the plugin.
z_population: Chooses the population from which NPCs are spawned.
z_frequency: Chooses the frequency of which NPCs are spawned.

Admin Commands
z_addspawn: Adds a spawnpoint for an NPC to be spawned at. There can be a maximum of 1000 spawnpoints.

Info
Do you love spawning NPC's for your players to fight against, but hate the time it takes to spawn them, and turn on their AI? Don't you wish there was an easier way? Wish no more! With this plugin, you have the power to choose where NPCs spawn, when NPCs spawn, and which NPCs spawn, all without lifting a finger! (After the initial setup.) This plugin let's you create specific profiles for NPC populations and NPC spawning frequencies, then choose which profiles should be active. After that, the NPCs spawn at random spawnpoints, and turn on their AI automatically, creating surprise attacks for the players where they least expect them.

Setup
1. Add this plugin to your server, then make sure it activates, either by a server restart or a map change.

2. There should now be 2 cfg files in your server's FTP: cfg/zombiefrequencies.cfg, and cfg/zombiepopulations.cfg

3. Let's work on the populations first, so open zombiepopulations.cfg

4. To create a new profile, simply write the name of it on a new line. Let's begin with "default", as this is the profile the plugin looks for by default.

5. Once you have the profile name on it's own line, go down a line, and add a "{"

6. Go down one line further. Now you're ready to start adding NPCs that you want to spawn. Simply type an npc name (without the npc_) on it's own line to add that NPC to the population! Let's make our default profile spawn headcrabs and manhacks, so we make one line say "headcrab" and the next line say "manhack".

7. Let's close our profile with a "}" on the next line. Now we have our default profile done! Let's add another though. So go to the next line.

8. Let's name our next profile "headcrabs", because with this one, we'll spawn all 3 types of headcrabs!

9. So now that the profile name is "headcrabs", go to the next line, and put a "{", same as before. Now go down another line, and let's start adding in the NPC names.

10. We should add "headcrab", "headcrab_black", and "headcrab_fast", all with new lines in between.

11. Now close the profile with another "}". Great, we've made 2 population profiles! We can switch between the 2 with the cvar z_population, followed by either "default", or "headcrabs", without the quotes! Let's see if we've made the profiles correctly. Do they look like this?

Code:
default
{
headcrab
manhack
}
headcrabs
{
headcrab
headcrab_black
headcrab_fast
}
If yours looks like that, then you've got the hang of it!

12. Now let's work on setting up the frequency file, so open zombiefrequencies.cfg now.

13. Let's make another default profile, so make a line that says "default", then on the next line, put a "{".

14. Now each frequency profile has 3 values that need to be set. Refire, which is how often the timer fires that spawns the NPCs. Spawns, which is how many NPCs should be spawned every time the timer fires. Max, which is the maximum amount of NPCs that can be spawned with this plugin.

15. First, let's take care of refire. For our default profile, let's make the timer refire once every minute. So we would write this on a new line: "refire=60". Easy huh?

16. Next, let's take care of the spawns. Let's only make 1 NPC spawn every time the timer fires (every minute), so we would write this on a new line: "spawns=1".

17. Last, let's put the max. Servers have a way of crashing when there are thousands of NPCs spawned, so for the sake of the server, let's make the maximum amount of NPCs that are able to be spawned relatively low. Write this on a new line: "max=100". When the plugin realizes that 100 NPCs exist on the map, it won't spawn any new ones until some of the existing ones are removed or killed.

18. Finally close the profile with a "}". Now we have a frequency profile! But let's add another, so we can switch between them. Let's make this one a crazy one!

19. Go down a line, and name your new profile "apocolypse"! Add a "{" after like before.

20. This time, for refire, put it as: "refire=10-20". Notice how we have a hyphen now. This means that the timer will refire anywhere in between 10 seconds and 20 seconds. It could refire at 18 seconds, who knows? This is good for adding extra randomness to your NPC spawns, so the players don't know when the next NPC will be spawned.

21. Now go down a line, and this time for spawns, put it as: "spawns=2-5". Again with the hyphen! This means that any amount in between 2 and 5 can be spawned. At one timer fire, 3 could be spawned. At the next, 5. It's all random!

22. Now finally, let's do the max. Put it as: "max=300". Max can't use a hyphen, for obvious reasons. But this new maximum will let way more NPCs spawn!

23. Finally, close the profile with a "}". Let's recap, does it look like this?

Code:
default
{
refire=60
spawns=1
max=100
}
apocolypse
{
refire=10-20
spawns=2-5
max=300
}
If it does, then great work! You've finished setting up your config files! If you ever want to add more profiles, you know exactly how to now! You can also switch your frequency with the cvar z_frequency, followed by either "default", or "apocolypse", without the quotes!

24. Now that we have profiles ready, it doesn't mean NPCs can be spawned. Why you ask? They have nowhere to spawn! So what this means, is any admin with the cheats flag, has to go around the map setting spawnpoints. (NOTE: The entity: info_npc_spawn_destination acts as a spawnpoint.)

25. Simply type the command: z_addspawn into your console, and a spawnpoint is automatically created right where you are standing! (NOTE: If you want to use flying or hovering NPCs, it's smart to create the spawnpoints a little off the ground, so the NPCs don't spawn in the ground.)

26. So run or noclip around the map, using z_addspawn to create spawns where you want them!

27. Finally, if the cvar z_enabled is off, turn it on, and your NPCs will begin to spawn!

28. To change the NPC attack damage or health, use the built in sk_ commands.


Hope someone will try. Thank you,you guys do great jobs :cool: :cool:
User avatar
Painkiller
Senior Member
Posts: 725
Joined: Sun Mar 01, 2015 8:09 am
Location: Germany
Contact:

Re: (HL2DM) zombies

Postby Painkiller » Wed Jun 10, 2020 8:35 am

User avatar
daren adler
Senior Member
Posts: 328
Joined: Sat May 18, 2019 7:42 pm

Re: (HL2DM) zombies

Postby daren adler » Wed Jun 10, 2020 4:13 pm

Painkiller wrote:https://github.com/KirillMysnik/SP-HL2DM-ZombieWaves


OK i will give it a try,,thank you Painkiller :smile:
User avatar
daren adler
Senior Member
Posts: 328
Joined: Sat May 18, 2019 7:42 pm

Re: (HL2DM) zombies

Postby daren adler » Wed Jun 10, 2020 4:40 pm

daren adler wrote:
Painkiller wrote:https://github.com/KirillMysnik/SP-HL2DM-ZombieWaves


OK i will give it a try,,thank you Painkiller :smile:


i got these errors

Code: Select all

2020-06-10 11:36:05 - sp   -   MESSAGE   [SP] Loading plugin 'zombie_waves'...
2020-06-10 11:36:05 - sp   -   EXCEPTION   
[SP] Caught an Exception:
Traceback (most recent call last):
  File "..\addons\source-python\packages\source-python\plugins\command.py", line 164, in load_plugin
    plugin = self.manager.load(plugin_name)
  File "..\addons\source-python\packages\source-python\plugins\manager.py", line 194, in load
    plugin._load()
  File "..\addons\source-python\packages\source-python\plugins\instance.py", line 74, in _load
    self.module = import_module(self.import_name)
  File "..\addons\source-python\plugins\zombie_waves\zombie_waves.py", line 14, in <module>
    from .info import info
  File "..\addons\source-python\plugins\zombie_waves\info.py", line 5, in <module>
    info = PluginInfo()

TypeError: __init__() missing 1 required positional argument: 'name'


2020-06-10 11:36:05 - sp   -   MESSAGE   [SP] Plugin 'zombie_waves' was unable to be loaded.


also got this error

Code: Select all

2020-06-10 11:43:39 - sp   -   MESSAGE   [SP] Plugin 'zombie_waves' was unable to be loaded.
2020-06-10 11:43:39 - sp   -   MESSAGE   [SP] Loading plugin 'zombie_waves_editor'...
2020-06-10 11:43:39 - sp   -   EXCEPTION   
[SP] Caught an Exception:
Traceback (most recent call last):
  File "..\addons\source-python\packages\source-python\plugins\command.py", line 164, in load_plugin
    plugin = self.manager.load(plugin_name)
  File "..\addons\source-python\packages\source-python\plugins\manager.py", line 194, in load
    plugin._load()
  File "..\addons\source-python\packages\source-python\plugins\instance.py", line 74, in _load
    self.module = import_module(self.import_name)
  File "..\addons\source-python\plugins\zombie_waves_editor\zombie_waves_editor.py", line 11, in <module>
    from listeners.tick import TickRepeat

ImportError: cannot import name 'TickRepeat'


2020-06-10 11:43:39 - sp   -   MESSAGE   [SP] Plugin 'zombie_waves_editor' was unable to be loaded.
User avatar
Painkiller
Senior Member
Posts: 725
Joined: Sun Mar 01, 2015 8:09 am
Location: Germany
Contact:

Re: (HL2DM) zombies

Postby Painkiller » Thu Jun 11, 2020 3:17 pm

I think you have to be patient here, iPlayer has not been active in the forum for a while.

Maybe it helps to open an "Issues" directly on the github page.

Image
cssbestrpg
Senior Member
Posts: 287
Joined: Sun May 17, 2020 7:56 am
Location: Finland
Contact:

Re: (HL2DM) zombies

Postby cssbestrpg » Thu Jun 11, 2020 6:19 pm

Code: Select all

2020-06-10 11:43:39 - sp   -   MESSAGE   [SP] Plugin 'zombie_waves' was unable to be loaded.
2020-06-10 11:43:39 - sp   -   MESSAGE   [SP] Loading plugin 'zombie_waves_editor'...
2020-06-10 11:43:39 - sp   -   EXCEPTION   
[SP] Caught an Exception:
Traceback (most recent call last):
  File "..\addons\source-python\packages\source-python\plugins\command.py", line 164, in load_plugin
    plugin = self.manager.load(plugin_name)
  File "..\addons\source-python\packages\source-python\plugins\manager.py", line 194, in load
    plugin._load()
  File "..\addons\source-python\packages\source-python\plugins\instance.py", line 74, in _load
    self.module = import_module(self.import_name)
  File "..\addons\source-python\plugins\zombie_waves_editor\zombie_waves_editor.py", line 11, in <module>
    from listeners.tick import TickRepeat

ImportError: cannot import name 'TickRepeat'


2020-06-10 11:43:39 - sp   -   MESSAGE   [SP] Plugin 'zombie_waves_editor' was unable to be loaded.


Change TickRepeat to Repeat

It should fix that ImportError
cssbestrpg
Senior Member
Posts: 287
Joined: Sun May 17, 2020 7:56 am
Location: Finland
Contact:

Re: (HL2DM) zombies

Postby cssbestrpg » Thu Jun 11, 2020 6:27 pm

Code: Select all

2020-06-10 11:36:05 - sp   -   MESSAGE   [SP] Loading plugin 'zombie_waves'...
2020-06-10 11:36:05 - sp   -   EXCEPTION   
[SP] Caught an Exception:
Traceback (most recent call last):
  File "..\addons\source-python\packages\source-python\plugins\command.py", line 164, in load_plugin
    plugin = self.manager.load(plugin_name)
  File "..\addons\source-python\packages\source-python\plugins\manager.py", line 194, in load
    plugin._load()
  File "..\addons\source-python\packages\source-python\plugins\instance.py", line 74, in _load
    self.module = import_module(self.import_name)
  File "..\addons\source-python\plugins\zombie_waves\zombie_waves.py", line 14, in <module>
    from .info import info
  File "..\addons\source-python\plugins\zombie_waves\info.py", line 5, in <module>
    info = PluginInfo()

TypeError: __init__() missing 1 required positional argument: 'name'


2020-06-10 11:36:05 - sp   -   MESSAGE   [SP] Plugin 'zombie_waves' was unable to be loaded.


To fix that error put this

info = PluginInfo('zombie_waves')
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: (HL2DM) zombies

Postby Ayuto » Fri Jun 12, 2020 11:44 am

Actually, PluginInfo isn't supposed to be instantiated by plugins. It was in the past, but today it's generated in the background by SP:
http://wiki.sourcepython.com/developing ... plugininfo

This allows other plugins to retrieve the plugin information (even for plugins that aren't loaded):
http://wiki.sourcepython.com/developing ... o-instance

In the past, SP was searching for an instance of the class in loaded plugins, but today it doesn't do that anymore. So, if you still instantiate a PluginInfo instance in your plugin, it's a useless container. So, the correct fix would be to delete that part and create an info.ini.
User avatar
daren adler
Senior Member
Posts: 328
Joined: Sat May 18, 2019 7:42 pm

Re: (HL2DM) zombies

Postby daren adler » Fri Jun 12, 2020 10:34 pm

Ayuto wrote:Actually, PluginInfo isn't supposed to be instantiated by plugins. It was in the past, but today it's generated in the background by SP:
http://wiki.sourcepython.com/developing ... plugininfo

This allows other plugins to retrieve the plugin information (even for plugins that aren't loaded):
http://wiki.sourcepython.com/developing ... o-instance

In the past, SP was searching for an instance of the class in loaded plugins, but today it doesn't do that anymore. So, if you still instantiate a PluginInfo instance in your plugin, it's a useless container. So, the correct fix would be to delete that part and create an info.ini.


Ok, can you explain to me what i would have to do to the zombie SP i have? and how to get the zombie waves started please?
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: (HL2DM) zombies

Postby Ayuto » Mon Jun 15, 2020 12:59 pm

Oh, sorry. That reply was actually directed to cssbestrpg. If you simply want to get the plugin (possibility - there might be more issues) just delete this line:
https://github.com/KirillMysnik/SP-HL2D ... ves.py#L14
User avatar
daren adler
Senior Member
Posts: 328
Joined: Sat May 18, 2019 7:42 pm

Re: (HL2DM) zombies

Postby daren adler » Mon Jun 15, 2020 2:52 pm

Ayuto wrote:Oh, sorry. That reply was actually directed to cssbestrpg. If you simply want to get the plugin (possibility - there might be more issues) just delete this line:
https://github.com/KirillMysnik/SP-HL2D ... ves.py#L14


OK. I did that and removed all of what you said to remove, no errors, but also no zombies,,i would put !zw and nothing happins,i even put cheats on and still nothing, it does show it on my HLSW and nothing spawns. Thank for your help Avuto. :smile:
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: (HL2DM) zombies

Postby Ayuto » Thu Jun 18, 2020 6:58 pm

Unfortunately, my time is currently too limited to take a deeper look into this. Sorry! I just wanted to help with the exception.
User avatar
daren adler
Senior Member
Posts: 328
Joined: Sat May 18, 2019 7:42 pm

Re: (HL2DM) zombies

Postby daren adler » Sat Jun 20, 2020 9:21 pm

Ayuto wrote:Unfortunately, my time is currently too limited to take a deeper look into this. Sorry! I just wanted to help with the exception.

OK NP.
User avatar
Kami
Global Moderator
Posts: 263
Joined: Wed Aug 15, 2012 1:24 am
Location: Germany

Re: (HL2DM) zombies

Postby Kami » Sun Jun 21, 2020 7:31 am

You need to load zombie_waves and zombie_waves_editor. zombie_waves_editor had some outdated Translation code which I replaced with the new one.

zombie_waves.py

Syntax: Select all

import json

from core import PLATFORM
from engines.server import global_vars
from entities.entity import Entity
from entities.hooks import EntityCondition, EntityPreHook
from listeners import (
OnEntityDeleted, OnEntitySpawned, OnLevelEnd, OnLevelInit,
OnServerActivate)
from mathlib import Vector
from memory import Convention, DataType, make_object
from paths import GAME_PATH, PLUGIN_DATA_PATH



MAPDATA_PATH = GAME_PATH / "mapdata" / "zombie_waves"

if PLATFORM == "windows":
EVENT_KILLED_INDEX = 66
else:
EVENT_KILLED_INDEX = 67

unloading = False
working = True
valid_npc_classnames = []
with open(PLUGIN_DATA_PATH / "zombie_waves" / "valid_npcs.res") as f:
for line in f:
line = line.strip()
if not line:
continue

valid_npc_classnames.append(line)


def dict_to_vector(dict_):
return Vector(dict_['x'], dict_['y'], dict_['z'])


class ZombieSpawn:
def __init__(self, dict_):
self.origin = dict_to_vector(dict_['origin'])
self.angles = dict_to_vector(dict_['angles'])
self.classname = dict_['classname']


class ZombieSpawnStorage(list):
def load_from_file(self):
self.clear()

if not self.filepath.isfile():
return

with open(self.filepath, 'r') as f:
json_dict = json.load(f)

for zombie_spawn_json in json_dict['zombie_spawns']:
self.append(ZombieSpawn(zombie_spawn_json))

@property
def filepath(self):
return MAPDATA_PATH / "{basename}.json".format(
basename=global_vars.map_name)

zombie_spawn_storage = ZombieSpawnStorage()
zombie_entities = {}


def create_zombie_entities():
for zombie_spawn in zombie_spawn_storage:
entity = Entity.create(zombie_spawn.classname)
entity.spawn()
entity.teleport(zombie_spawn.origin, zombie_spawn.angles)

zombie_entities[entity.index] = entity


def load():
if global_vars.map_name:
zombie_spawn_storage.load_from_file()
create_zombie_entities()


def unload():
global unloading
unloading = True
for entity in list(zombie_entities.values()):
entity.remove()


@OnLevelInit
def listener_on_level_init(level_name):
zombie_spawn_storage.load_from_file()


@OnServerActivate
def on_server_activate(edicts, edict_count, max_clients):
global working
working = True

create_zombie_entities()


@OnLevelEnd
def listener_on_level_end():
global working
working = False


@OnEntityDeleted
def listener_on_entity_deleted(base_entity):
if not base_entity.is_networked():
return

zombie_entities.pop(base_entity.index, None)

if unloading:
return

if not working:
return

if not zombie_entities:
create_zombie_entities()


@OnEntitySpawned
def listener_on_entity_spawned(base_entity):
if base_entity.classname not in valid_npc_classnames:
return

entity = Entity(base_entity.index)
entity.spawn_flags |= 512
entity.set_key_value_int('sleepstate', 0)
entity.call_input('SetRelationship', 'player D_HT 99')


def make_event_killed(entity):
return entity.pointer.make_virtual_function(
EVENT_KILLED_INDEX,
Convention.THISCALL,
[DataType.POINTER, DataType.POINTER],
DataType.VOID
)


@EntityPreHook(EntityCondition.equals_entity_classname(*valid_npc_classnames),
make_event_killed)
def pre_event_killed(args):
entity = make_object(Entity, args[0])
if entity.classname not in valid_npc_classnames:
return

entity.remove()
return True


zombie_waves_editor.py

Syntax: Select all

from enum import IntEnum
import json

from colors import BLUE, ORANGE
from commands.typed import TypedClientCommand, TypedSayCommand
from effects import box
from engines.precache import Model
from engines.server import global_vars
from filters.recipients import RecipientFilter
from listeners import OnClientDisconnect, OnLevelInit
from listeners.tick import Repeat
from mathlib import Vector
from menus import SimpleMenu, SimpleOption, Text
from messages import SayText2
from paths import GAME_PATH, PLUGIN_DATA_PATH
from players.dictionary import PlayerDictionary

from translations.strings import LangStrings



TICK_REPEAT_INTERVAL = 0.1

EDITOR_STEP_UNITS = 1

INSPECT_LINE_COLOR = BLUE
INSPECT_LINE_MODEL = Model('sprites/laserbeam.vmt')
INSPECT_LINE_WIDTH = 2

HIGHLIGHT_LINE_COLOR = ORANGE
HIGHLIGHT_LINE_MODEL = Model('sprites/laserbeam.vmt')
HIGHLIGHT_LINE_WIDTH = 4

MAPDATA_PATH = GAME_PATH / "mapdata" / "zombie_waves"

BOX_HEIGHT = 80
BOX_WIDTH = 16

valid_npc_classnames = []
with open(PLUGIN_DATA_PATH / "zombie_waves" / "valid_npcs.res") as f:
for line in f:
line = line.strip()
if not line:
continue

valid_npc_classnames.append(line)

strings = LangStrings("zombie_waves_editor")

MSG_ZW_INSPECT_START = SayText2(strings['zw_inspect start'])
MSG_ZW_INSPECT_STOP = SayText2(strings['zw_inspect stop'])
MSG_ERR_INVALID_NPC = SayText2(strings['error invalid_npc'])


class HighlightChoice(IntEnum):
HL_NEXT = 0
HL_PREV = 1
DELETE = 2


players = PlayerDictionary()
popups = {}


def round_vector(vector, step):
vector.x = step * round(vector.x / step)
vector.y = step * round(vector.y / step)
vector.z = step * round(vector.z / step)


def vector_to_dict(vector):
return {
'x': vector.x,
'y': vector.y,
'z': vector.z
}


def dict_to_vector(dict_):
return Vector(dict_['x'], dict_['y'], dict_['z'])


def vector_to_str(vector):
return "{x:.2f} {y:.2f} {z:.2f}".format(x=vector.x, y=vector.y, z=vector.z)


class ZombieSpawn:
def __init__(self, *args):
# From JSON-dict
if isinstance(args[0], dict):
dict_ = args[0]
origin = dict_to_vector(dict_['origin'])
angles = dict_to_vector(dict_['angles'])
classname = dict_['classname']

# From mins and maxs vectors
else:
origin, angles, classname = args

self.origin = origin
self.angles = angles
self.classname = classname

self._mins = self.origin + Vector(-BOX_WIDTH, -BOX_WIDTH, 0)
self._maxs = self.origin + Vector(BOX_WIDTH, BOX_WIDTH, BOX_HEIGHT)

def draw_inspect(self, recipients):
box(
recipients,
self._mins,
self._maxs,
color=INSPECT_LINE_COLOR,
life_time=TICK_REPEAT_INTERVAL,
halo=INSPECT_LINE_MODEL,
model=INSPECT_LINE_MODEL,
start_width=INSPECT_LINE_WIDTH,
end_width=INSPECT_LINE_WIDTH
)

def draw_highlight(self, recipients):
box(
recipients,
self._mins,
self._maxs,
color=HIGHLIGHT_LINE_COLOR,
life_time=TICK_REPEAT_INTERVAL,
halo=HIGHLIGHT_LINE_MODEL,
model=HIGHLIGHT_LINE_MODEL,
start_width=HIGHLIGHT_LINE_WIDTH,
end_width=HIGHLIGHT_LINE_WIDTH
)

def to_dict(self):
dict_ = {
'origin': vector_to_dict(self.origin),
'angles': vector_to_dict(self.angles),
'classname': self.classname
}

return dict_


class ZombieSpawnStorage(list):
def save_to_file(self):
json_dict = {
'zombie_spawns': [],
}
for zombie_spawn in self:
json_dict['zombie_spawns'].append(zombie_spawn.to_dict())

with open(self.filepath, 'w') as f:
json.dump(json_dict, f, indent=4)

def load_from_file(self):
self.clear()

if not self.filepath.isfile():
return

with open(self.filepath, 'r') as f:
json_dict = json.load(f)

for zombie_spawn_json in json_dict['zombie_spawns']:
self.append(ZombieSpawn(zombie_spawn_json))
highlights.append_zombie_spawn()

@property
def filepath(self):
return MAPDATA_PATH / "{basename}.json".format(
basename=global_vars.map_name)

zombie_spawn_storage = ZombieSpawnStorage()


class Inspects(RecipientFilter):
def __init__(self):
super().__init__()
self.remove_all_players()

def tick(self):
for zombie_spawn in zombie_spawn_storage:
zombie_spawn.draw_inspect(self)

def client_disconnect(self, index):
self.remove_recipient(index)

inspects = Inspects()


class Highlights(list):
def highlight_next(self, index):
zombie_spawn_id = self.get_zombie_spawn_id_by_index(index)
if zombie_spawn_id is None:
if self:
self[0].add_recipient(index)
return zombie_spawn_storage[0]

return None

else:
self[zombie_spawn_id].remove_recipient(index)

zombie_spawn_id += 1
if len(self) > zombie_spawn_id:
self[zombie_spawn_id].add_recipient(index)
return zombie_spawn_storage[zombie_spawn_id]

else:
return None

def highlight_prev(self, index):
zombie_spawn_id = self.get_zombie_spawn_id_by_index(index)
if zombie_spawn_id is None:
if self:
self[-1].add_recipient(index)
return zombie_spawn_storage[-1]

return None

else:
self[zombie_spawn_id].remove_recipient(index)

zombie_spawn_id -= 1
if 0 <= zombie_spawn_id:
self[zombie_spawn_id].add_recipient(index)
return zombie_spawn_storage[zombie_spawn_id]

else:
return None

def get_zombie_spawn_id_by_index(self, index):
for zombie_spawn_id, recipients in enumerate(self):
if index in recipients:
return zombie_spawn_id

return None

def append_zombie_spawn(self):
recipients = RecipientFilter()
recipients.remove_all_players()
self.append(recipients)

def pop_zombie_spawn(self, zombie_spawn_id):
self.pop(zombie_spawn_id)

def tick(self):
for zombie_spawn_id, recipients in enumerate(self):
zombie_spawn_storage[zombie_spawn_id].draw_highlight(recipients)

def client_disconnect(self, index):
for recipients in self:
recipients.remove_recipient(index)

highlights = Highlights()


def send_highlight_popup(index, zombie_spawn):
if index in popups:
popups[index].close(index)

popup = popups[index] = SimpleMenu(
select_callback=select_callback_highlight)

popup.append(SimpleOption(
choice_index=1,
text=strings['popup highlight next_zombie_spawn'],
value=HighlightChoice.HL_NEXT
))

popup.append(SimpleOption(
choice_index=2,
text=strings['popup highlight prev_zombie_spawn'],
value=HighlightChoice.HL_PREV
))

if zombie_spawn is None:
popup.append(
Text(strings['popup highlight current_zombie_spawn none']))
else:
popup.append(
Text(strings['popup highlight current_zombie_spawn'].tokenized(
origin=vector_to_str(zombie_spawn.origin),
angles=vector_to_str(zombie_spawn.angles),
classname=zombie_spawn.classname
))
)

popup.append(SimpleOption(
choice_index=3,
text=strings['popup highlight delete'],
value=HighlightChoice.DELETE
))

popup.send(index)


def send_delete_popup(index):
if index in popups:
popups[index].close(index)

popup = popups[index] = SimpleMenu(select_callback=select_callback_delete)
popup.append(Text(strings['popup delete title']))
popup.append(SimpleOption(
choice_index=1,
text=strings['popup delete no'],
value=False
))
popup.append(SimpleOption(
choice_index=2,
text=strings['popup delete yes'],
value=True
))
popup.send(index)


def select_callback_highlight(popup, index, option):
if option.value == HighlightChoice.HL_NEXT:
zombie_spawn = highlights.highlight_next(index)
send_highlight_popup(index, zombie_spawn)
elif option.value == HighlightChoice.HL_PREV:
zombie_spawn = highlights.highlight_prev(index)
send_highlight_popup(index, zombie_spawn)
elif option.value == HighlightChoice.DELETE:
send_delete_popup(index)


def select_callback_delete(popup, index, option):
old_zombie_spawn_id = highlights.get_zombie_spawn_id_by_index(index)
if old_zombie_spawn_id is None:
return

if option.value:
zombie_spawn = highlights.highlight_prev(index)

highlights.pop_zombie_spawn(old_zombie_spawn_id)
zombie_spawn_storage.pop(old_zombie_spawn_id)

else:
zombie_spawn = zombie_spawn_storage[old_zombie_spawn_id]

send_highlight_popup(index, zombie_spawn)


@OnClientDisconnect
def listener_on_client_disconnect(index):
inspects.client_disconnect(index)
highlights.client_disconnect(index)

popups.pop(index, None)


@Repeat
def tick_repeat():
inspects.tick()
highlights.tick()

tick_repeat.start(TICK_REPEAT_INTERVAL, limit=0)


@OnLevelInit
def listener_on_level_init(level_name):
popups.clear()
players.clear()


@TypedClientCommand('zw_save_to_file', "zombie_waves_editor.create")
@TypedSayCommand('!zw_save_to_file', "zombie_waves_editor.create")
def typed_zw_save_to_file(command_info):
zombie_spawn_storage.save_to_file()


@TypedClientCommand('zw_load_from_file', "zombie_waves_editor.create")
@TypedSayCommand('!zw_load_from_file', "zombie_waves_editor.create")
def typed_zw_load_from_file(command_info):
zombie_spawn_storage.load_from_file()


@TypedClientCommand('zw_inspect', "zombie_waves_editor.inspect")
@TypedSayCommand('!zw_inspect', "zombie_waves_editor.inspect")
def typed_zw_inspect(command_info):
if command_info.index in inspects:
inspects.remove_recipient(command_info.index)
MSG_ZW_INSPECT_STOP.send(command_info.index)
else:
inspects.add_recipient(command_info.index)
MSG_ZW_INSPECT_START.send(command_info.index)


@TypedClientCommand('zw_highlight', "zombie_waves_editor.create")
@TypedSayCommand('!zw_highlight', "zombie_waves_editor.create")
def typed_zw_highlight(command_info):
zombie_spawn_id = highlights.get_zombie_spawn_id_by_index(
command_info.index)

if zombie_spawn_id is None:
send_highlight_popup(command_info.index, None)
else:
zombie_spawn = zombie_spawn_storage[zombie_spawn_id]
send_highlight_popup(command_info.index, zombie_spawn)


@TypedClientCommand('zw_create', "zombie_waves_editor.create")
@TypedSayCommand('!zw_create', "zombie_waves_editor.create")
def typed_zw_create(command_info, classname:str):
classname = classname.lower()

if classname not in valid_npc_classnames:
MSG_ERR_INVALID_NPC.send(command_info.index, classname=classname)
return

player = players[command_info.index]
origin = player.origin
angles = player.angles
round_vector(origin, EDITOR_STEP_UNITS)

zombie_spawn = ZombieSpawn(origin, angles, classname)
zombie_spawn_storage.append(zombie_spawn)
highlights.append_zombie_spawn()


For commands you have:

!zw_create <npc_name> //you can find the complete list under addons\source-python\data\plugins\zombie_waves\valid_npcs.res

!zw_save_to_file //saves the spawn points you created with !zw_create to a json file

!zw_load_from_file //load spawn points from json file.

!zw_inspect //does not seem to work, should show a box where you put a spawn point

!zw_highlight //not sure what it is supposed to do but it does not seem to work.



If you saved spawnpoints and try to edit them later, you need to use !zw_load_from_file first, otherwise the new spawnpoints will override the old ones.

Also you need to give yourself permissions in SourcePythons auth system so you can use those commands.

Code: Select all

{
    "YOURSTEAMID": {
        "parents": [
            "guest"
        ],
        "permissions": [
            "zombie_waves_editor.create",
            "zombie_waves_editor.inspect"
        ]
    }
}



Even though you can technically make the spawn points work this way, the npcs do not seem to do damage, they don't have a death animation and if you are too far away they will not go towards you which kinda defeats the purpose of wave based gameplay.


Edit: So I found out that you need to define the damage of the NPCs with console variables in hl2dm, so that problem is easily solved.
User avatar
daren adler
Senior Member
Posts: 328
Joined: Sat May 18, 2019 7:42 pm

Re: (HL2DM) zombies

Postby daren adler » Wed Jun 24, 2020 5:59 pm

OK i will give it another try,thank you.

Return to “Plugin Requests”

Who is online

Users browsing this forum: No registered users and 24 guests