Welcome to Open Carnage

A resource for Halo Custom Edition and MCC modding, with unique means of rewarding content creation and support. Have a wander to see why we're worth the time! - EST. 2012


  • Content count

  • Joined

  • Last visited

  • Raffle Tickets


About mouseboyx

Extra Information

  • Gender
  • Location
    Kansas, USA
  • Occupation
  • Interests
    Guitar, Halo, Programming

Contact Methods

Computer Details

  • Central Processor
    i5 6600k
  • Graphics
    RX 590
  • Memory
  • Storage
    2x500gb sata ssd
  • Display
    144hz 1080p 16:9
  • Operating System
    Ubuntu 20.04 + Windows 7
  1. I want to preface this by saying that I had not written any C++ before I started working on this, and also that I don't know how to manage memory within C++. I would not recommend using this on your halo server because it could potentially crash it if not used correctly. This is more like an overview of how an async C function call can work within lua. The .dll seems to work under the circumstances, but I don't know how everything works within the C++ code, so it definitely shouldn't be used in any production environment. I would not have been able to figure out how to make the dll if it were not for these posts, I used the structure from Discord Webhooks Script dllmain.cpp, and the lua timer structure from the sapp http client, also special thanks to a halo player named dummkopf. Using Visual Studio 2019 on Windows 10, I followed this guide to setup the environment with libcurl to compile the dll https://medium.com/@farhabihelal/how-to-set-up-libcurl-on-visual-studio-2019-a9fdacce6945 The dll can only make one request at a time, lua can pass in a url and post data through the request, and the request is completed asynchronously. I'm fairly confident halo will not lag no matter how long the webserver takes to respond. The text response is stored in an lua variable so that you can do whatever needs to be done with it. It sort of performs an http get and post request at the same time where get variables are passed through the query string, and the post data is passed to the 2nd parameter of curl_request(). If any of the C functions are called out of order then it could crash the server, and I haven't figured out how to create curl request instances, thus only one request at a time, then wait, then make the next one. The dllmain.cpp could be modified from documentation https://curl.se/libcurl/c/libcurl-easy.html to perform any http method, however the compiled dll in the zip only supports http get/post. There are lots of comments in the sources to help. The curl_test.7z includes: dllmain.cpp - C++ code that can compile with visual studio 2019 curl_test.dll - dll that I compiled with visual studio 2019 (put this in the same directory as haloded.exe) I didn't test this on wine or anything other than windows 10 curl_test.lua - example lua script that allows curl_test.dll to be loaded and called sleep.php - put this at the root directory of a web server with PHP installed (you can install xampp and put it in C:\xampp\htdocs) This was mainly for testing whether curl was performed using async and to echo back post variables Honestly though if someone has experience writing C/C++ out there this is a decent enough base to create C functions that won't lag the halo server, but the C++ that I cobbled together is not very good due to my lack of understanding of C++. I guess I'm looking for someone to come and improve this idea, but I might try to figure out a better way of doing it after I learn more. Problems running with wine: I was testing the dll included in the zip, and it looks like I compiled it in debug mode rather than release mode, also I attempted to ffi load the dll while running haloded.exe through wine and it asks for VCRUNTIME140D.dll and ucrtbased.dll which could not be found it led me to this https://stackoverflow.com/questions/6261034/building-dll-for-lower-version-of-visual-studio which it looks like it will be necessary to learn about the solutions described in this question in order to compile a working dll for wine. The VC++ 2010 runtime has a platinum rating on winehq.org, https://appdb.winehq.org/objectManager.php?sClass=application&iId=5766, my assumption is to somehow obtain a legitimate copy of visual studio 2010 or the VC++ 2010 compiler and compile the dll using that. Then use: winetricks vcrun2010 within the 32bit wine prefix that the halo server is run in. In addition visual studio 2010 would somehow have to work with libcurl, which hopefully it would. Ignore the grayed out text, if you open the solution properties in visual studio 2019 before writing any code, then specify the platform toolset as the 2015 version, not the 2015 xp version, then the compiled dll will work under wine after running: winetricks vcrun2015 within the 32 bit wine prefix, and make sure to compile in release mode and not debug mode, or wine will throw an error trying to load the dll, I also uploaded the VC++ 2015 version of the dll as culr_test_wine.dll.7z, it has an identical source to the dllmain.cpp, only that it works with wine, and should work on windows as well after installing the VC++ 2015 runtime. Using winetricks vcrun2015 over ssh may require the ssh -X option to forward x11 applications because there is a graphical popup to accept the Microsoft terms of the redistributable. I would really like to find a way to compile the dll without the need for any runtime redist, but I haven't figured that out. Other Notes: If some protection were added with extra bool values within the dllmain.cpp and wrapping some of the code within an if statement so that certain functions could only be called after others had been completed then improper usage of the C functions causing the server to crash could most likely be avoided. There should probably be an if statement within do_curl() in dllmain.cpp so that if you pass an empty string as the 2nd parameter in lua like: curl_client.curl_request("http://localhost/sleep.php?wait_time=4","") Then curl should not perform with any post data or so that post would not be a part of the request, because sending post data to a dynamic web page whether it be PHP or anything, if the page is setup in such a way that you send post data when it doesn't expect any or doesn't need any it could possibly fail on the server side. I don't have an example of this happening, but it would be a good idea to have it operate like a switch rather than sending blank post data. In other words, wrap curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); in an if statement so that if post_data is an empty string don't include it in the request. There is no current error reporting or checking, get_curl_status()==true only means that the curl portion of the C++ has completed, if curl was unable to contact the web server there's no real way to tell. I believe if it failed you'll get back an empty string "" from get_curl_text_response() yet if you were already expecting an empty response from the web server it would be difficult to discern whether there was an error. Queue of requests: curl_test_queue.7z contains: curl_test_queue.lua This is one example of how lua can create a queue for curl_test_wine.dll, an lua table of outgoing requests can be done one after another, where the timer loop is constantly running checking for more data in the table, sending all of it out until there's no more entries in the table. There's probably also a way to trigger the timer loop rather than to have it constantly running if there's no data to be sent, but I didn't include that in the code. log_player.php This appends the data sent from lua to the http server to a file in the same directory where the php script is located called halo_players.txt that contains the name of the player who joined and the current unix timestamp. It has to be run within a web server compatible with php. Setting custom headers: Sorry for this messy edited timeline of work, but curl_test_headers.7z works the same as curl_test_wine, however lua is given the opportunity to pass custom headers using the curl rules outlined in this doc https://curl.se/libcurl/c/httpcustomheader.html I believe I also fixed a memory leak in the program, but I don't have any way to know for sure, or don't know how. I also added some protection for the functions just in case they get called out of order. So this should be considered the "stable version" although relatively "stable" compared to previous attempts. I've played a little with this code https://gist.github.com/ianklatzco/c033b33757915feaf48fd0caf14b42cb for running curl from bash to communicate with a discord bot, but I vaguely remember there needing to be an initial authorization that has to be done before the bot will accept requests, which may or may not hinder trying to create one in within lua using this dll. Setting custom method: It's on my todo list to add an lua counterpart to add an option and parameter to change this libcurl function: curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, <string from lua here>); so that something like "DELETE", "PATCH", or "PUT" etc... can be used. sapp_curl_1.7z: I'm happy with the way this turned out and I did some testing with it and included 2 examples of how sapp_curl_1.dll can be used within lua to query the discord API, and in turn instruct a discord bot to do things. Due to the massive number of options here: https://curl.se/libcurl/c/curl_easy_setopt.html I think it would be wise to stop development. The dllmain.cpp could easily be restructured to include any of those options, but sapp_curl_1.dll is simple enough to get started with http api requests or sending any http method along with data. There is a quirk where if you are sending JSON data with sapp_curl_1.dll it may have been a good idea to format that as UTF-8 within the .dll, but it may be possible to do that within lua. I might try to figure out either method whether lua or cpp to send special characters, but the fix that I've put in the discord lua examples is a hack method that is reliable at changing the data to be acceptable but won't send special characters. I believe that the post data must be ASCII encoded. The included examples go into a lot more detail of usage, so I'm not going to put that information here, but you can set custom headers, and set custom request methods, and custom post data, and turn standard output messages on and off. It looks like attempting to detect the charset given to sapp_curl_1.dll and then convert to utf-8 is a problem that would require quite a bit of work. I'm unsure how lua is deriving the charset from any data that is passed to it, so it could possibly be any charset. Making a list of all the ascii characters and making sure that the data you send is one of those characters seems like an easy fix, but no special characters are able to get sent. If there was a way to force lua to encode a particular string with a certain charset all the time once it's sent to sapp_curl_1.dll it would make life a lot easier, but there are also ways of detecting charsets within a C/C++ program, however there are quite a few that would need to be set up to be detected. I even went so far as to think that possibly url encoding then url decoding the string, or somewhere in the process of doing that might make this easier to figure out https://help.interfaceware.com/code/details/urlcode-lua send all post data as a url encoded string, then you could decode it once it was passed to the dll, however that seems like a wild goose chase. I've hit a point where I need to learn more before being able to make improvements: https://stackoverflow.com/questions/16208079/how-to-work-with-utf-8-in-c-conversion-from-other-encodings-to-utf-8 Nevermind the issue above is solved in with this stackoverflow question: https://stackoverflow.com/questions/16624036/how-to-convert-windows-1256-to-utf-8-in-lua it probably works for both halo chat and names chosen in halo. There is also probably some usage of lua's string.byte() that can be done beforehand to make sure you aren't trying to convert a string with a character represented by a byte valuer greater than 255. It makes me think about the halo name hack program and I'm wondering if it would inject characters into a player's name that have a byte value greater than 255, I don't know enough about how the halo client/server handles names and chat strings in order to give a solution that will always work even if someone was being naughty with the strings that you can get from get_var(PlayerIndex,"$name") and also the Message parameter from register_callback(cb["EVENT_CHAT"], "OnPlayerChat") in sapp. sapp_curl_2.7z is the current version: I fixed a dumb mistake by making sure: curl_slist_free_all(chunk); gets called, this probably would have been bad over long periods of use. I did some unorthodox stress testing attempting to see how reliable the dll was. I did ~500,000 requests at ~250 requests per second with everything being done over localhost, and 99 header rules, and 1000 characters of data per request. So far as I can tell the memory usage of the machine I was running it on while running with wine did not increase as if there was a leak. Connecting to the halo server through localhost while this was going on with 1 player it seemed as everything was normal, which seemed kind of comical because haloded.exe was hovering around 20% cpu usage (i5 6600k). Errors: As of the time of writing this there is no error reporting for curl within the dll, you are at the mercy of the api endpoint to give relevant errors, but an empty string "" will be returned if curl fails for whatever reason. An example would be the webserver not being able to be contacted because there is no webserver running at the hostname of the url does not exist, curl will return "" after a pre-defined amount time because the webserver did not exist. This could happen for any number of reasons, like a dns lookup failed, or you aren't connected to the internet, trying to request from exampel.com instead of example.com, etc... The name of the sapp_curl_x.dll is arbitrary, and in order to load whichever version you downloaded: curl_client = ffi.load("sapp_curl_x") replace the name within the quotes with the file name of the dll, you can also rename it to anything and use that name instead, and I don't think you have to put .dll on the end in order for lua to load it. The dll should be put in the same directory that contains the halo server i.e. the same location of sapp.dll and haloded Todo list: File posting https://curl.se/libcurl/c/postit2.html curl_slist_free_all(chunk); needs to be added when custom headers are specified (Done) Reason for making this and future thoughts: I wanted a portable solution that could contact http api's that was also not going to lag the halo server. The sapp_http_client is a better option if you only need to make GET requests. I'm still wondering whether this sapp curl dll would be compatible with a service like elite game servers, I'm hoping / praying that they have a way to use the VC++ 2015 runtime and will accept the .dll if they are asked to upload it to a service. If services like elite game servers will accept the dll then that opens up some lua programming freedom on EGS for script writers to create interactions with http api's that require more than the GET method. EGS doesn't care too much if you upload any lua script by yourself and write your own lua scripts for sapp. But they disallow uploading of .dll files unless you open a ticket with them. The sapp_http_client has already been added to their list of mods that can be "one click" installed, so I'm hoping this can get on that list too, but I would like someone to review the dllmain.cpp before that happens. Of course improper use of the dll within lua will crash the server, and it could be warped and twisted into a cpu sucking program if used improperly in lua. I'm hoping it's treated with respect and not abused, waiting 250ms between initiating and processing a request is just an arbitrary number that I put in the examples, but changing that number is up to the lua programmer to decide. curl_test.7z curl_test_wine.dll.7z curl_test_queue.7z curl_test_headers.7z sapp_curl_1.7z sapp_curl_2.7z
  2. I sent EGS a ticket, and they say the shell exec from sapp lua is no-go. I was using shared linux vps hosting, but ran into the noisy neighbors effect and got some bad lag so I went back to EGS. For 1 to 2 servers EGS is fine I think although the complete lack of control over anything is one of the compromises of price and reliability. EGS added a plugin script to auto-install the sapp http client that Kavawavi made. I was doing some testing with the client and it can request urls up to around ~8100 characters long, probably 8000 or less to keep things safe. Would you consider writing in a compatibility layer to use the sapp http request to bring your script to locked down hosting like EGS?
  3. I really wish I knew enough to be able to create ffi libraries for lua/sapp. Sorry for my rambling post earlier, I think having no available source for the webserver side of things started to make me go crazy with questions in my mind of things to look out for. If I can get elitegameservers.net to upload wget.exe along with its .dll files I would be willing to help send you some info, I've got this server on retail SuicideBomber3, that gets a good amount of traffic, it's ffa. I don't know if elitegameservers.net runs windows for hosting but I really don't know if they allow a shell to pulled up from lua. If your website has ssh access you can get a free signed ssl certificate and enable https, it would help a bit with securing data, it's the only reason I felt comfortable with sending information through a url rather than post. This is what I used: https://github.com/srvrco/getssl
  4. Thanks, I think an ffi module that was capable of doing any http method that would not cause lag would be an indispensable asset to any web related integration. The project that I was working on completely lacked an api portion, but I was thinking about how it would be useful. I'm thinking what if a nefarious group of players decide they want to make up a UUID? Then concatenate that value through the chimera script, rather than the real UUID from their C: drive, and then they all use that same UUID among them? There would probably be some logic somewhere on the server side to account for a problem like that. Also if they all logged in through a vpn while using that shared UUID their ip addresses would more or less look like a single player, except their names would be different if they were all playing on the same server at the same time. And they could make the UUID follow the same format as one that would be obtained from a drive. Sorry this is just where my mind goes with this stuff. execute_script('rcon uuid cl_uuid '..'some_uuid_here') Edit: I guess when the end report is known by the webserver and it encounters any duplicate uuid from different players, it could flag that uuid for abuse, and/or toss that information out. I guess the most they could do at that point would be to work in shifts, especially if 2 games going on 2 different servers had the same uuid at the same time and that could also be detected.
  5. Ash vs Evil Dead (Lots of gore), Futurama (Cartoon comedy), It's Always Sunny in Philadelphia (Comedy), Breaking Bad (Crime Drama), Doctor Who (Science Fiction) There's also lots of anime out there too, Death Note, Full Metal Alchemist Brotherhood, Hunter x Hunter, Mob Psycho 100, One Punch Man, Assassination Classroom, Initial D, but I'm bad about watching anime unless it's english dubbed. A movie based on the first person shooter video game genre is Hardcore Henry, lots of gore and some nudity though.
  6. Great work, this release solves many problems I've run into while trying to make something similar. I spent my time dillydallying instead of working on the web stats thing that I was working on. I guess the ideology is different in releasing source for the server code, so I may still have a chance at continuing work, but most likely I'll continue my procrastination. The method I fell back on for uniquely identifying players only depends on IP+Name if either of those things change it's considered a different player, but the UUID seems like an interesting workaround to the problem of halo being pretty much anonymous. I was considering consolidating, or having an option to treat "unique" players as the same if they had the same name and if their different IP addresses were relatively on the same network. It wouldn't be possible for players to see other's UUID, but could they edit the chimera portion to send a pre-fabricated UUID? The http request for sapp can do requests, although I think limited to the get method, without lagging or doing them on the main thread. Even if the web server takes 10 seconds or longer to even send back a response there's no lag using the async method and putting part of the code in a timer. I'm unsure if you already found a way around the lag with the system shell call to powershell or wget. Edit: Sorry, I feel like I'm putting up too much criticism of your release, but I'm very curious about the methods you used because of my attempt in creating something similar.
  7. Power went out a few hours before I went to sleep, luckily it was back on when I woke up. This has happened before where it lasted a few days before they got it back on during an ice storm that knocked out power for a good portion of the city area. Usually when the power goes out, it's kind of a nuisance, but this time I was thinking "I'm Free!" like the electronic devices rule my life, it's nice to have an uncontrollable interruption in that flow to re-organize thoughts. But in the past having no heat and no hot water during those few days in the winter was not fun.
  8. Sorry I don't know of any way to log comprehensive error reports of sapp. If the server crashes as soon as it is launched, this post fixes the issue: Or it could be crashing due to a script, but you can run haloded+sapp on your local machine like a copy from the vps and start disabling scripts one by one to find the cause. You would be able to read from the console while running the local copy to see if there are any messages. If it's a single script causing the issue, you can add function OnError(Message) --Code here to log errors cprint(Message) end to the script to figure out more about what's causing it. Possibly another cause of the crash could be that you are running wine in a 64bit prefix while running haloded+sapp, if you create a 32bit prefix to run in it may solve the issue.
  9. All of what you said is true. For some reason I was thinking there were already servers out there that had a version of this type of thing implemented, although I wasn't sure whether someone already had a program that would do it. I was more interested in whether it already exists, rather than the implementation. I usually ignore any server where all of the players are ones with default names, the popularity of servers to me seems more up to individuals who decide to play and enjoy a particular game. It does seem pointless to add bots to a server, because if it's already a good server, then players will join, or sometimes join an empty server to get more of that experience. I was trying to search for whether this existed but couldn't find any resources. My guess is that someone is already either doing these things manually or has already found out a way to script it, but is not sharing the methods.
  10. A server that has afk multi client bots, usually if someone is running the bots they would all be from the same IP address, and they would also all have a default name "Sleepy", "The Bear" etc... so a lua script could be written to kick out those bots IF They were from a specific IP address And they had a default name And the server had something like 16 players so that more real players could join But what if you wanted those afk multi client bots to re-join after the server reached something like 0 players? I figure there is a very round about method of doing that, which makes me think that someone has already made a program that isn't so round about but does the same thing, but this is my idea from my background in web-dev: Using a sapp script and the http client, the halo server will send the player count to a web server through a GET variable in a query string to update the player count every second or so, then that player count could be viewed publicly at a url. Then the computer running the multi clients could read that url if the player count dropped to a specific number it could then launch more multi client afk bots, I was thinking something like cURL wrapped through a .bat script on windows, or windows subsystem for linux running cURL in a bash script loop that could in turn launch the bots. There would need to be some cleanup, so that all the multi client instances were ended at some point or else there would be a lot of clients open on the computer running the script. Maybe some sort of communication back and forth to id the instances with which one got kicked and end that one may work, but I don't know. Does this type of program already exist out there? Because this method seems really too complicated to achieve what I'm looking for.
  11. I started out learning this stuff from a lot of Chalwk's scripts I checked out that admin chat you were talking about. It looks like the program flow could be changed by removing or changing if statements to send the chat messages to all players through the console regardless of the need for a command to activate it. However it would need some re-working to handle team chat properly.
  12. Edit: Sorry I misunderstood the original question, but if you wanted to call a function within an .lua script that is already loaded by halo, you can use this command from halo lua_call <script name> <function name> [arguments] If you wanted to run that command from within a lua script you would wrap that command within execute_command(). However if you tried to call a function that was used as an event callback within a script the parameters that are given to it through the callback system will no longer work afaik. Like imagine you had a script called test1.lua api_version = "" function OnScriptLoad() end function OnScriptUnload() end function test_function1(aString) say_all(aString) end And then you had a script called test2.lua api_version = "" function OnScriptLoad() register_callback(cb['EVENT_JOIN'], "OnPlayerConnect") end function OnScriptUnload() end function OnPlayerConnect(PlayerIndex) execute_command("lua_call test1 test_function1 'say something'") end test2.lua would run the function test_function1() from the test1.lua, and it would pass the string 'say something' to it when it called it. If you tried to do this same thing with a function that is done from a callback like register_callback(cb['EVENT_JOIN'], "OnPlayerConnect") then called OnPlayerConnect in place of test_function1 it wouldn't be able to execute with the parameters that are passed through the callback system, it would still execute, but most likely wouldn't do what you wanted it to. This is what I think would work: If you want one script to perform one action like running a bit of code or using execute_command() exactly when a player joins the server, you can register a callback function like this: (the double dash -- in front of a line means it's a comment and won't affect the code when it's being run) api_version = "" function OnScriptLoad() register_callback(cb['EVENT_JOIN'], "OnPlayerJoin") end function OnScriptUnload() end function OnPlayerJoin(PlayerIndex) --put code here to execute when a player joins --this is an example that says to everyone in the server the player index of who just joined say_all(PlayerIndex) --this is an example that executes the command nades on the PlayerIndex who just joined execute_command("nades "..PlayerIndex.." 7") --the use of .. is the concatenation operator that tells lua to stick two strings together --strings are enclosed in "" but there are special characters that have to be escaped inside strings like --if you use "something\somethingelse" it needs to be changed to "something\\somethingelse" for lua to recognize it properly --this link goes over the special characters https://www.tutorialspoint.com/lua/lua_strings.htm end For a list of all the callback functions you can reference the sapp documentation http://halo.isimaginary.com/SAPP Documentation Revision 2.5.pdf (The section labeled "Event Callbacks") , but they all work the same way, but some take a different number of parameters, like this example OnPlayerDeath() in addition to PlayerIndex, there is a Causer parameter to determine what killed a player. Some of them also use a return statement, which I could give an example of if need be. api_version = "" function OnScriptLoad() register_callback(cb['EVENT_DIE'], "OnPlayerDeath") end function OnScriptUnload() end function OnPlayerDeath(PlayerIndex,Causer) --^There are 2 parameters for EVENT_DIE^ --PlayerIndex refers to who died, while the Causer refers to what caused their death, it can be a number from -1 to 16 I think, --where a number between 1 to 16 is another player and -1 to 0 is a different mode of death, like switching teams, falling damage or killed with a vehicle. --put code here to execute when a player dies end For every event callback that is registered within OnScriptLoad() each one needs to be on it's own line and you'll need to create a new function somewhere else in the code to match each individual callback. You can have all of the callbacks in a single lua script, as long as they aren't repeated I think it should be fine. Like if the two code bits above were in the same script: api_version = "" function OnScriptLoad() register_callback(cb['EVENT_DIE'], "OnPlayerDeath") register_callback(cb['EVENT_JOIN'], "OnPlayerJoin") end function OnScriptUnload() end function OnPlayerDeath(PlayerIndex,Causer) --^There are 2 parameters for EVENT_DIE^ --PlayerIndex refers to who died, while the Causer refers to what caused their death, it can be a number from -1 to 16 I think, where a number between 1 to 16 is another player and -1 to 0 is a different mode of death, like switching teams, falling damage or killed with a vehicle. --put code here to execute when a player dies end function OnPlayerJoin(PlayerIndex) --put code here to execute when a player joins --this is an example that says to everyone in the server the player index of who just joined say_all(PlayerIndex) --this is an example that executes the command nades on the PlayerIndex execute_command("nades "..PlayerIndex.." 7") --the use of .. is the concatenation operator that tells lua to stick two strings together --strings are enclosed in "" but there are special characters that have to be escaped inside strings like --if you use "something\somethingelse" it needs to be changed to "something\\somethingelse" for lua to recognize it properly --this link goes over the special characters https://www.tutorialspoint.com/lua/lua_strings.htm end Something else to keep in mind is that when register callback is called in a script, like this: register_callback(cb['EVENT_JOIN'], "OnPlayerJoin") The text that says "OnPlayerJoin" is arbitrary and can be changed to whatever you want as long as there is a matching function in the code to go along with it: api_version = "" function OnScriptLoad() register_callback(cb['EVENT_JOIN'], "OnPlayerConnectToServer") --the part that says 'EVENT_JOIN' does not change, but the 2nd part has been changed to "OnPlayerConnectToServer" end function OnScriptUnload() end --the below function was changed to OnPlayerConnectToServer to match the register_callback function OnPlayerConnectToServer(PlayerIndex) --put code here to execute when a player joins --this is an example that says to everyone in the server the player index of who just joined say_all(PlayerIndex) end
  13. Awesome, it was fun to figure out how to make it work, glad you like it.
  14. Sorry that I don't have a script to contribute, but from looking at other scripts I have sort of idea like how pieces of other scripts could be used to accomplish this. I can't take any credit for the code here, but I like finding bits of code others have written to make things. Thanks to Chalwk's github and Enclusion's thread for these bits of code: Zombies are always on the blue team? If so, do a callback on player death, find the killer index and the victim index. If the victim index is a zombie using get_var(victim,"$team")=="blue" and the killer is a human get_var(killer,"$team")=="red" then This script by Chalwk https://github.com/Chalwk77/HALO-SCRIPT-PROJECTS/blob/master/SAPP SCRIPTS/ATTRACTIVE MODS/Tea Bagging.lua specifically this bit here: function OnPlayerDeath(P) return TBag:OnDeath(P) end function TBag:OnDeath(Ply) local pos = self:GetXYZ(Ply) if (pos and self.players[Ply]) then table.insert(self.players[Ply].coordinates, { timer = 0, x = pos.x, y = pos.y, z = pos.z }) end end function TBag:GetXYZ(Ply) local pos = { } local DyN = get_dynamic_player(Ply) if (player_alive(Ply) and DyN ~= 0) then pos.dyn = DyN local VehicleID = read_dword(DyN + 0x11C) local VObject = get_object_memory(VehicleID) if (VehicleID == 0xFFFFFFFF) then pos.in_vehicle = false pos.x, pos.y, pos.z = read_vector3d(DyN + 0x5c) elseif (VObject ~= 0) then pos.in_vehicle = true pos.x, pos.y, pos.z = read_vector3d(VObject + 0x5c) end end return (pos.x and pos) or nil end Is a way to find the x,y,z coordinates of a player when they die. So find the x,y,z of the zombie that died then This thread covers how to find the current weapon someone is holding, although upon testing I was given an exception error, I'm thinking it's an issue with running sapp+haloded on linux. Anyway it should work for finding what weapon (tag path) someone is holding when they kill someone. You could alternatively get the tag path of every weapon a player is holding, to spawn all ammo for their weapons. Edit: I attached a compilation of the scripts in the "Checking if plasma weapon is in hand & what is in the backpack" thread, to make the info easier to use. I also found a solution to the exception error that I was getting. I edited this line: local WeaponID = get_object_memory(read_dword(DyN + 0x118)) so that it was wrapped in get_object_memory() Now we have the tag path and x,y,z of the player that died, and who killed them and what weapon they were holding. There's a way to spawn that specific weapon on the ground where they died using execute_command("spawn <type> <tag_path> [<x> <y> <z>] [rotation]") or find a different way to spawn the weapon. The z coordinate would probably need to bumped up a tiny bit like z+0.1 or +0.01, something like that, although I'm not certain. This script https://github.com/Chalwk77/HALO-SCRIPT-PROJECTS/blob/50c09db2cfbe6fe45b62e7587a24680733d8f515/SAPP SCRIPTS/UTILITY MODS/Item Spawner.lua gives an even better method for spawning a weapon, rather than relying on execute_command()... Spawning the weapon is the safe way, but you could also do a relation table to not spawn the weapon, but spawn the ammo object like you see in single player. This is a rough estimation of how it could be done, with lots more fine tuning to make it pretty and more functional, or have other options and functionality rather than always spawning ammo when a blue player dies. find_weapon.lua Edit: I've attached a rough prototype of how it could work, I did test it pretty well, but I didn't test it with the zombies script loaded, and only with 2 players in the server. In theory it should be fine though. It relies on execute_command to spawn the ammo, it only spawns ammo for the gun that a player was holding while killing a zombie, so if they killed a zombie with a grenade they still get ammo for the weapon in their hand. If a zombie or someone is killed on blue team with a vehicle the script does nothing. You can change in the configuration section how high up from the body the ammo spawns, and also an adjustable delay as to how long to wait after they die to spawn it. Suicides or any other method of death other than a human killing a zombie will have the script do nothing. This relies heavily on where someone died, and not the actual position of their corpse, so if they fly far due to a blast after dying the ammo will still spawn where they were at the exact moment of death. Sorry, but you can use this script at your own risk, it works in theory, but is not the greatest, there are other better ways of doing things. Once again thanks to Chalwk and Enclusion. zombie_ammo.lua
  15. With this in mind, I've seen too many times where teams get stacked to a ridiculous extent, I guess that's part of the game. I do get that, I was playing a game a bit ago and built up over a long period all the way to finally control the big hill on bloodgulch, with so many attempts I was going crazy, then after the team that was controlling the hill realized they had lost it, they started dropping off like flies, and I was switched to their team via script and rq. Most of the time the scripted team changes don't bother me, because they keep the game going, but there are for sure instances where it can be a headache. I would probably say that any weaker/stronger based team switch scripts should be a cumulative weak or strong factor of an entire team rather than any single player. Like even if you started singling out players in a group with at 1.0 or greater k/d to switch it would probably get messy, I'm not sure what a fair way to do this is, but picking a player at random seems a bit more fair than the next one to die. Using the built in methods is also fair in a way. Where there is no script controlling team balance at all, and rely on halo's built in auto team balance where you can't switch from an already lesser team. It is fair, but there's nothing keeping the teams even other than new players joining, or players who switch in good faith and don't want to see the game end because everyone quits from one team. Not having auto team balance turned on at all is kinda crazy, I've had the instance happen where I was the only player on a team, and every other player had switched to red in a bloodgulch ctf match. I need to do some real testing with sapp's /balance_teams command, as I don't know how it functions to improve the situation of stacked teams.