Advertisement
Guest User

Untitled

a guest
Aug 15th, 2017
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.89 KB | None | 0 0
  1. @name SCRL
  2. @persist [SCR_ALPHANUMERIC_LENGTH SCR_CMD_COUNT]:number [SCR_ALPHANUMERIC_STRING SCR_PREFIX SCR_PREFIX_OPERATOR SCR_HELP_STRING SCR_SILENT_MESSAGE_FLAG]:string [SCR_ALPHANUMERIC_ARRAY SCR_CMD_PREFIXES SCR_INDICATOR_COLORS]:array [SCR_MSG_COLOR]:vector [SCR_OWNER]:entity [SCR_NUMERICALPHA_TABLE]:table
  3. @persist [SCR_Key_Number_Sequence]:array [SCR_Key_Length]:number [SCR_Channel SCR_Key_Word]:string
  4. #[
  5. STANDARDIZED COMMUNICATIONS RADIO LIBRARY
  6.  
  7. QUICK OVERVIEW:
  8. This is a modular library which can be imported and used for remote communications between people and contraptions.
  9. It is a message-based, encrypted, data bus that can be used to send tactical information, send requests, or otherwise communicate.
  10. This allows both secure messaging and instanteous location data transmission. It can be used to send targets to allies silently
  11. and more easily than other systems, as well as being quick and simple to integrate.
  12.  
  13. First you have to set a channel and a keyword. These are to be only shared with people who you are sharing communications with.
  14. Once this is done, you can send and recieve messages. Messages follow a set format listed below, and specialized e2s listen for these.
  15.  
  16. Although there is a more detailed low-level API, SCRL can be added to an E2 really, really simply:
  17.  
  18. if chatClk:
  19. scr_chat(Seat,Aimpos) <-- Listens to see if the last said thing is a new settings set or a message, handles it
  20. if dsClk:
  21. NewCommsReturn = scr_recieve() <-- Gets latest update from your channel, recieving transmissions. Stores as an array of data with a set pattern.
  22.  
  23. That's it. If you want, for quick & easy keypress activation, you can use:
  24. if keyClk(Seat):
  25. scr_keyTransmit(Seat,Aimpos) <-- sees if the seat's driver is pressing a number key, if so transmits the matched command
  26.  
  27. The comms return array is simple:
  28. The first index is the numeric command code (codes are listed below)
  29. The second index is a vector if one was sent with the message
  30. The third index is a text string, if one was sent with the message
  31.  
  32. HOW IT WORKS:
  33. Once a keyword is set it is encoded as a series of numeric shifts.
  34. When a message is translated, it is encrypted via Vigenere cipher off your keyword. Nobody without the keyword and channel can understand it, even admins!
  35. The recievers all decrypt the message, which is converted to an array.
  36. If you don't want to notify the person via a chat event, like for a beacon or something, add at the end of the text message a -s. This tells scrl that it's a silent command.
  37.  
  38. EXAMPLE SENT MESSAGES:
  39. This is a sample of the messages sent out, minus encryption:
  40. Code 1: ATK 3285 4381 -3256 tank located here Tell allies to attack a location or just attack in general
  41. Code 2: DEF 3221 3285 23462 Tell allies to defend a location or just attack in general
  42. Code 3: ARTY -3221 -235 2421 requesting 3 rounds of mortar fire Request artillery at a location, either from an ally or an automated system
  43. Code 4: SUPPLY 8005 32884 -3521 -s Marks ammunition resupply at a location, silent because of the -s
  44. Code 5: POS landing zone Transmit a fixed position, for example an airstrip
  45. Code 6: MSG cats are better than dogs Direct communication, just secured radio chat nobody can listen into (not even admins!)
  46.  
  47. LOW LEVEL API:
  48. The lower level API lets you directly call most functions for integrating into your own e2s. Fear not, it is not difficult.
  49. A LOT of work went into documenting everything meticulously to make it as easy to use as possible.
  50. Feel free to read the comment blocks documentation above the functions; here are the common ones which most people will want to use.
  51.  
  52. scr_transmit() sends messages based off settings directly, based off params provided. You can use this for automation of messages or unmanned chips. It'll do the holo thing for you.
  53. scr_updateSettings() updates the settings based off input parameters. It is highly recommended you don't use hard-coded e2 values as a rule of thumb since anyone who reads the code could know your passcodes.
  54.  
  55. Playsound, encrypt, and decrypt don't need to be accessed. You may use them as you wish in a standalone fashion; they are internal functions only.
  56.  
  57. DETAILS AND RATIONALE OF ENCRYPTION:
  58. Encryption is used because it is trivially simple to join a radio group, scan channels, and intercept. If someone knows the group to expect, they can join and intercept.
  59. If someone does not know the group to expect, they can poll and attempt to brute force it easily enough; trying this could, in theory, cause server instability. If
  60. you had a particularly unscrupulous admin they could pretty easily mod the lua to monitor ds groups, too. Therefore it was found to be simpler to make the messages themselves
  61. secure. In this way the utmost of security can be attained. Yes, it is excessive, but it is a hobbyist project and intended to work securely for a long, long time.
  62. The encryption system chosen was the Vigenere cipher. All single-substitution ciphers can be easily broken even with E2; Vigenere ciphers cannot. As even encrypting and
  63. decrypting knowing the key is non-trivial cpu-wise, attempts to brute force would fail, and short ciphers resist frequency analysis well, especially with mixed contents.
  64. This is also why the message-based rather than realtime model was chosen, in addition to ubiquity and adapatability.
  65.  
  66. DO NOT EDIT BELOW THIS LINE. DO NOT EDIT BELOW THIS LINE. DO NOT EDIT BELOW THIS LINE. DO NOT EDIT BELOW THIS LINE. DO NOT EDIT BELOW THIS LINE.
  67. ]#
  68.  
  69.  
  70. #constants which are implemented on import of the library
  71. SCR_PREFIX = "SCR"
  72. SCR_PREFIX_OPERATOR = "-"
  73. SCR_CMD_PREFIXES = array("ATTACK","DEFEND","ARTY","SUPPLY","POSITION","MSG")
  74. SCR_INDICATOR_COLORS = array(vec(255,0,0),vec(255,255,0),vec(255,128,0),vec(0,255,0),vec(128,128,255),vec(255))
  75. SCR_CMD_COUNT = SCR_CMD_PREFIXES:count()
  76. SCR_ALPHANUMERIC_STRING = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=!@#$%^&*()_+[]\{}|;':\",./<>?~"
  77. SCR_ALPHANUMERIC_ARRAY = SCR_ALPHANUMERIC_STRING:explode("")
  78. SCR_ALPHANUMERIC_LENGTH = SCR_ALPHANUMERIC_STRING:length()
  79. #flag used to say not to notify people of a message; useful for automation
  80. SCR_SILENT_MESSAGE_FLAG = "-s"
  81. #spooky scary hashmaps
  82. for(N=1,SCR_ALPHANUMERIC_LENGTH) {SCR_NUMERICALPHA_TABLE[SCR_ALPHANUMERIC_ARRAY[N,string],number] = N}
  83. SCR_HELP_STRING =
  84. "SCR CHAT COMMANDS:\nPut " + SCR_PREFIX_OPERATOR + " before any command. You can use the # or the word, ex: \""+SCR_PREFIX_OPERATOR+SCR_CMD_PREFIXES[1,string]+"\" is the same as \""+SCR_PREFIX_OPERATOR+"1\".\nUse \"-set # Word\" to set channel and password, like \"-set 3 secret\"."
  85. for(N=1,SCR_CMD_COUNT) {SCR_HELP_STRING = SCR_HELP_STRING + "\n" + SCR_PREFIX_OPERATOR + "" + N + " means " + SCR_CMD_PREFIXES[N,string]:lower()}
  86. SCR_MSG_COLOR = vec(96,255,96)
  87. SCR_OWNER = owner()
  88.  
  89.  
  90. #[A utility function used to notify the operator. Handles if used in a seated or unseated manner.]#
  91. function void scr_notify(String:string,Seat:entity)
  92. {
  93. if(Seat:driver()) {Seat:printColorDriver(SCR_MSG_COLOR,String)} else {print(String)}
  94. }
  95.  
  96.  
  97. #[Encrypts a string using the SCR_Key_Number_Sequence which was saved from your keyword.
  98. Returns the encrypted string.
  99. Example use: EncryptedString = MessageString:scr_encrypt() #returns encrypted message to send out]#
  100. function string string:scr_encrypt()
  101. {
  102. local MsgArray = This:explode("")
  103. local Length = MsgArray:count()
  104. #encodes the offsets--the letter-to-number of the raw text
  105. local Offsets = array()
  106. for(I=1,Length)
  107. {
  108. local Offset = SCR_NUMERICALPHA_TABLE[MsgArray[I,string],number]
  109. if(!Offset) {Offet = 1} #default case is a space. No unicode.
  110. Offsets[I,number] = Offset
  111. }
  112. #adds a shift off cipher; if it's beyond the max offset, cycles it back around
  113. local KeyIndex = 1
  114. for(I=1,Length)
  115. {
  116. #determines numeric shift
  117. local Shift = Offsets[I,number] + SCR_Key_Number_Sequence[KeyIndex,number]
  118. if(Shift > SCR_ALPHANUMERIC_LENGTH) {Shift = Shift - SCR_ALPHANUMERIC_LENGTH}
  119. Offsets[I,number] = Shift
  120. #increments key index; if beyond max length loops it back to create a repeating cipher
  121. KeyIndex++
  122. if(KeyIndex > SCR_Key_Length) {KeyIndex = 1}
  123. }
  124. #converts the numeric shifts to characters for return string
  125. local ReturnString = ""
  126. for(I=1,Length)
  127. {
  128. ReturnString = ReturnString + SCR_ALPHANUMERIC_ARRAY[Offsets[I,number],string]
  129. }
  130. return ReturnString
  131. }
  132.  
  133. #[Decrypts a string using the SCR_Key_Number_Sequence which was saved from your keyword.
  134. Returns the decrypted string
  135. Example use: DecryptedString = EncryptedString:scr_decrypt() #decrypts the encrypted message and saves plaintext as DecryptedString]#
  136. function string string:scr_decrypt()
  137. {
  138. local MsgArray = This:explode("")
  139. local Length = MsgArray:count()
  140. #converts message from symbols to numeric values
  141. local Offsets = array()
  142. for(I=1,Length)
  143. {
  144. local Offset = SCR_NUMERICALPHA_TABLE[MsgArray[I,string],number]
  145. if(!Offset) {Offet = 1} #default case is a space. No unicode.
  146. Offsets[I,number] = Offset
  147. }
  148. #removes the numeric shifts of the key
  149. local KeyIndex = 1
  150. for(I=1,Length)
  151. {
  152. #determines numeric shift
  153. local Shift = Offsets[I,number] - SCR_Key_Number_Sequence[KeyIndex,number]
  154. if(Shift < 1) {Shift = Shift + SCR_ALPHANUMERIC_LENGTH}
  155. Offsets[I,number] = Shift
  156. #increments key index; if beyond max length loops it back to create a repeating cipher
  157. KeyIndex++
  158. if(KeyIndex > SCR_Key_Length) {KeyIndex = 1}
  159. }
  160. #converts the numeric shifts back to characters for return string
  161. local ReturnString = ""
  162. for(I=1,Length)
  163. {
  164. ReturnString = ReturnString + SCR_ALPHANUMERIC_ARRAY[Offsets[I,number],string]
  165. }
  166. return ReturnString
  167. }
  168.  
  169. #[Plays a sound when recieving or sending a transmission.
  170. These are randomly selected from the ambient/chatter folder.]#
  171. function void scr_playSound()
  172. {
  173. local TypeRandomNum = randint(4)
  174. local SubtypeRandomNum = randint(5)
  175. local StringBase = ""
  176. local StringEnd = ".wav"
  177. if(TypeRandomNum == 1)
  178. {
  179. StringBase = "ambient/chatter/italian_radio"
  180. }
  181. elseif(TypeRandomNum == 2)
  182. {
  183. StringBase = "ambient/chatter/spanish_radio"
  184. }
  185. elseif(TypeRandomNum == 3)
  186. {
  187. StringBase = "ambient/chatter/arabic_radio"
  188. }
  189. elseif(TypeRandomNum == 4)
  190. {
  191. StringBase = "ambient/chatter/cb_radio_chatter_"
  192. SubtypeRandomNum = randint(3) #corner case handling
  193. }
  194. soundPlay(SCR_PREFIX,0,StringBase+toString(SubtypeRandomNum)+StringEnd)
  195. }
  196.  
  197. #[Creates the simple indicator for holo. It is a series of 3 arrows, of quite large size and displacement, intended to be easily visible.]#
  198. function void scr_drawHolo(Code:number,Location:vector,Driver:entity)
  199. {
  200. local Players = players()
  201. local User = Driver
  202. if(!Driver) {User = SCR_OWNER}
  203. for(N=1,Players:count()) {if(Players[N,entity] == User) {Players:removeEntity(N)}}
  204. local Color = SCR_INDICATOR_COLORS[Code,vector]
  205. for(N=1,3)
  206. {
  207. local Index = 996+N
  208. local OffsetAmount = 3 * (1 + (N-1)*2)
  209. holoCreate(Index,Location + vec(0,0,39.37 * OffsetAmount),vec(15),ang(-180,0,0))
  210. holoModel(Index,"hq_cone")
  211. holoMaterial(Index,"models/debugwhite")
  212. holoDisableShading(Index,1)
  213. holoVisible(Index,Players,0)
  214. holoColor(Index,vec4(Color,128))
  215. }
  216. }
  217.  
  218. #[Transmits an SCR order. Additional data can be attached as necessary. The formatting is strict but able to handle a broad variety of cases.
  219. The format is the text prefix code of the order, the xyz vector if one exists, the player name in allcaps, and any additional text.
  220. Note that coordinates and messages can be omitted. For example, you could simply say to attack without specifying where, or saying where in the message.
  221. It is expected that AUTOMATED systems will use the vector coordinates ONLY, while additional information can be used for context-dependent messaging.
  222. By using prefixes, we can automate responses and add context-aware indications. In addition, any third-party system can interface smoothly with an SCR system.
  223. This means that you can write your own custom code and as long as it sends messages encrypted and formatted like this, it will work.
  224. For example, a mortar that listens for fire support requests could use the message text to determine how many rounds to fire, or what type of rounds.
  225. Example use: "scr_transmit(6,owner():lastSaid(),owner():pos(),owner()) #sends whatever you just said as a secure message, make sure you use hideChat(1)!
  226. Example use: "scr_transmit(1,"Target Spotted",Aimpos,Seat)" #sends a request to attack, with the words "Target Spotted", located at aimpos from someone in a seat.
  227. Example use: "scr_transmit(3,"",TargetVector,noentity()" #sends a textless request for fire support, with just a holo indicator and vector
  228. Example use: "scr_transmit(4,"-s",entity():pos(),noentity())" #silently transmits the location of a supply dump, for other e2s to cache, without text bothering players]#
  229. function string scr_transmit(Code:number,MessageText:string,Coordinate:vector,Seat:entity)
  230. {
  231. if(inrange(Code,1,SCR_CMD_COUNT))
  232. {
  233. #break coordinate down into encodable string if it exists
  234. local CoordString = ""
  235. if(Coordinate) {CoordString = "" + int(Coordinate[1]) + " " + int(Coordinate[2]) + " " + int(Coordinate[3])}
  236. #builds the string to transmit
  237. local TransmitString = SCR_CMD_PREFIXES[Code,string] + " " + CoordString + " " + MessageText
  238. #encrypts
  239. local EncryptedMessage = ""
  240. EncryptedMessage = TransmitString:scr_encrypt()
  241. #draw location if sent, and plays a sound, then sends message
  242. local MessageArray = MessageText:explode(" ")
  243. if(!(MessageArray[MessageArray:count()-1,string] == SCR_SILENT_MESSAGE_FLAG))
  244. {
  245. if(Seat) {scr_drawHolo(Code,Coordinate,Seat:driver())}
  246. }
  247. scr_playSound()
  248. dsSend(SCR_Channel,SCR_PREFIX,2,EncryptedMessage)
  249. #returns a copy of the message if you want to back-check and verify it. You don't need to do anything with this.
  250. return EncryptedMessage
  251. }
  252. return ""
  253. }
  254.  
  255. #[Recieves an SCR order, and returns an array. Should be called on dsClk().
  256. It will attempt to decrypt everything sent to it. If the digital signal is a valid command code
  257. and we decrypted successfully, it will return an array of the Code, vector coord data, message, and a copy of the actual full message as recieved.
  258. This return is formatted as array(string,vector,string,string).
  259. For example, an artillery fire mission would return array("FIREMISSION",vec(3253,-2321,38285),"Here is the tank","FIREMISSION 3253 -2321 38285 Here is the tank").
  260. Another example, a locationless attack request would return array("ATTACK",vec(),"","ATTACK").
  261. If you have a seat given as an arg, it will hint the driver with the data. If not, put in "noentity()"!
  262. Example use: if(dsClk()) {UpdatedSCRData = scr_recieve(Seat)} #gets updated data, hints driver
  263. Example use: if(dsClk()) {UpdatedSCRData = scr_recieve(entity())} #gets updated data, prints if scr is being used by owner, for items like backpack radios.
  264. Example use: if(dsClk()) {UpdatedSCRData = scr_recieve(noentity())} #gets updated data silently.]#
  265. function array scr_recieve(Seat:entity)
  266. {
  267. local PrintToChat = Seat:isValid()
  268. local Driver = Seat:driver()
  269. local DecryptedMessage = ""
  270. DecryptedMessage = dsGetString():scr_decrypt()
  271. local DecryptedMessageArray = DecryptedMessage:explode(" ")
  272. local DecryptedCommandCode = DecryptedMessageArray[1,string]
  273. local CommandIndex = 0
  274. for(N=1,SCR_CMD_COUNT)
  275. {
  276. if(DecryptedCommandCode == SCR_CMD_PREFIXES[N,string])
  277. {
  278. CommandIndex = N
  279. N = SCR_CMD_COUNT
  280. }
  281. }
  282. #valid command and decrypted successfully
  283. if(CommandIndex)
  284. {
  285. local DecryptedMessageLength = DecryptedMessageArray:count()
  286. #if valid #s, it'll return a proper vec, while strings will just return as 0. It'll check later that each is a valid non-zero # to prevent edge cases.
  287. local TransmittedX = DecryptedMessageArray[2,string]:toNumber()
  288. local TransmittedY = DecryptedMessageArray[3,string]:toNumber()
  289. local TransmittedZ = DecryptedMessageArray[4,string]:toNumber()
  290. local ValidVec = TransmittedX & TransmittedY & TransmittedZ
  291. local TransmittedVec = vec(TransmittedX,TransmittedY,TransmittedZ)
  292. local Range = round((entity():pos() - TransmittedVec):length() / 39.37)
  293. #message parsing
  294. local PureMessage = ""
  295. local HumanReadableMessage = "[" + SCR_PREFIX + "] " + dsGetSender():owner():name():upper() + " " + SCR_CMD_PREFIXES[CommandIndex,string] + ": "
  296. #adds each word after vec to the message string; adjusts offset if a valid vec for start of array-to-string copy
  297. for(N=(2 + (ValidVec*3)),DecryptedMessageLength) {PureMessage = PureMessage + " " + DecryptedMessageArray[N,string]}
  298. HumanReadableMessage = HumanReadableMessage + " " + PureMessage
  299. if(DecryptedMessageArray[DecryptedMessageLength-1,string] != SCR_SILENT_MESSAGE_FLAG)
  300. {
  301. if(ValidVec) {HumanReadableMessage = HumanReadableMessage + "(" + Range + "m)"}
  302. if(PrintToChat) {scr_notify(HumanReadableMessage,Seat)}
  303. if(TransmittedVec & PrintToChat) {scr_drawHolo(CommandIndex,TransmittedVec,Driver)}
  304. }
  305. #plays a little sound to inform you
  306. scr_playSound()
  307. #displays location
  308.  
  309. return array(DecryptedCommandCode,TransmittedVec,PureMessage,DecryptedMessage)
  310. }
  311. #invalid command, returns an empty array
  312. else
  313. {
  314. return array()
  315. }
  316. }
  317.  
  318. #[Encodes a string as a list of numeric shifts and saves to the SCR_Key_Number_Sequence array automatically.
  319. Also saves channel and updates scope of datasignals.
  320. Note that this string is NOT case sensitive; it is always interpreted as full uppercase, for ease of use.
  321. Returns a copy of SCR_Key_Number_Sequence, which is still saved to the backend automatically.
  322. Example use: scr_encodeAsKey(Keyword) #sets the VCED key to our keyword
  323. NOTE: Call this to set your "keyword", so once on start and if you change keywords]#
  324. function array scr_updateSettings(Channel:number,Keyword:string)
  325. {
  326. #sets datasignal scopes and group
  327. dsSetScope(2)
  328. dsJoinGroup(SCR_PREFIX)
  329. #splits string into array of chars, checks if in alphanum array, if so adds num to key_number_sequence
  330. SCR_Channel = "" + Channel
  331. #note it's like O(n^2) so key is limited to 10 chars
  332. SCR_Key_Word = Keyword:upper()
  333. SCR_Key_Word_Array = SCR_Key_Word:explode("")
  334. SCR_Key_Length = SCR_Key_Word:length()
  335. for(I=1,SCR_Key_Length) {SCR_Key_Number_Sequence[I,number] = SCR_NUMERICALPHA_TABLE[SCR_Key_Word_Array[I,string],number]}
  336. #play a little sound as confirmation
  337. soundPlay(SCR_PREFIX+"!",0,"ambient/tones/equip1.wav")
  338. scr_transmit(6,"Joined SCR channel.",vec(),noentity())
  339. return SCR_Key_Number_Sequence
  340. }
  341.  
  342. #[easy chat-callable standardized way to use SCR w/ an aimpos. User implementation is optional; other methods are fine too.
  343. It will hint the owner of the e2 with the verification popup. It DOES work if you aren't chip owner, but, you shouldn't transmit messages!
  344. This is because hideChat only works for owner of e2, and you'd be giving some of your message contents to everyone else.
  345. An external person would hear from your chat your code, but not the transmitted vector.
  346.  
  347. Note you also use this to set the password and channel. However, this will NOT work if you aren't chip owner--hideChat wouldn't work!
  348.  
  349. Returns the numerical index code if a message was transmitted, 0 if nothing or just hinted help, and -1 if it changed settings.
  350. Example use: if(chatClk()) {scr_chat(Seat,Aimpos)} #handles all scr chat for a seated player
  351. Example use: if(chatClk()) {scr_chat(entity():owner(),owner():aimPos())} #handles all scr chat for owner, like for backpack radios
  352. Example use: if(chatClk()) {scr_chat(noentity(),vec())} #listens only, doesn't transmit
  353. Example chat syntax: -1 here, throw a few rounds down. <-- sends a message to attack, sends transmitVector if there is one
  354. Example chat syntax: -set 6 mypassword <-- changes your pw and channel.]#
  355. function number scr_chat(Seat:entity,TransmitVector:vector)
  356. {
  357. local Said = ""
  358. local Seated = 0
  359. local Valid = 0
  360. local Driver = Seat:driver()
  361. local SendingMode = Seat:isValid()
  362. if(Seat:driver())
  363. {
  364.  
  365. Said = Driver:lastSaid()
  366. Seated++
  367. Valid = (Driver == lastSpoke()) & chatClk(Driver)
  368. }
  369. else
  370. {
  371. Said = SCR_OWNER:lastSaid()
  372. Valid = (SCR_OWNER == lastSpoke()) & chatClk(SCR_OWNER)
  373. }
  374. if(Valid)
  375. {
  376. #split last said into words, then analyze first section for a token
  377. local Split = Said:explode(" ")
  378. local FirstToken = Split[1,string]
  379. local FirstTokenSplit = FirstToken:explode("")
  380. local SilentMode = Split[Split:count(),string] == SCR_SILENT_MESSAGE_FLAG
  381.  
  382. #update settings, can only be done by owner!
  383. if((Split[1,string]:upper() == (SCR_PREFIX_OPERATOR + "SET")) & (!Seated | (Driver == SCR_OWNER)))
  384. {
  385. hideChat(1)
  386. scr_updateSettings(Split[2,string]:toNumber(),Split[3,string])
  387. scr_notify(SCR_PREFIX_OPERATOR + SCR_PREFIX + ":\nChannel: " + SCR_Channel + "\nPassword: " + SCR_Key_Word,Seat)
  388. return -1
  389. }
  390.  
  391. #has a proper start symbol token, so scr should listen
  392. elseif((FirstTokenSplit[1,string] == SCR_PREFIX_OPERATOR) & SendingMode)
  393. {
  394. hideChat(1)
  395. local CodeString = FirstTokenSplit[2,string]:upper()
  396. local Code = CodeString:toNumber()
  397. if(!Code)
  398. {
  399. for(N=1,SCR_CMD_COUNT) {if(CodeString == SCR_CMD_PREFIXES[N,string]) {Code = N}}
  400. }
  401.  
  402. #valid output
  403. if(inrange(Code,1,SCR_CMD_COUNT))
  404. {
  405. local MessageText = ""
  406. for(N=2,Split:count()) {MessageText = MessageText + Split[N,string] + " "}
  407. scr_transmit(Code,MessageText,TransmitVector,Seat)
  408. if(!SilentMode) {if(MessageText:length()) {scr_notify("Transitted " + SCR_CMD_PREFIXES[Code,string] + ": " + MessageText,Seat)} else {scr_notify("Transmitted " + SCR_CMD_PREFIXES[Code,string],Seat)}}
  409. return 1
  410. }
  411. else
  412. {
  413. scr_notify(SCR_HELP_STRING,Seat)
  414. }
  415. }
  416. }
  417. return 0
  418. }
  419.  
  420. #[easy keypress-callable standardized way to use SCR w/ an aimpos.
  421. It will tell the seat driver what they transmitted, and transmits off numpad presses or regular num presses.
  422. If you don't want to transmit on each valid num press, only call the command if another modifier key is pressed.
  423. If the user presses 0, it will display a help prompt.
  424. Returns they numerical index of the key if successful,
  425. Example use: if(keyClk()) {scr_keyTransmit(Seat,Aimpos)} #sends a simple command based off a number input
  426. Example use: driver presses the key 2 <-- sends the scr command 2 with transmitVector, if a valid vector]#
  427. function number scr_keyTransmit(UserOrSeat:entity,TransmitVector:vector)
  428. {
  429. local Valid = 0 #if in put is valid
  430. local User = noentity()
  431. local Seated = 0
  432. if(UserOrSeat == owner())
  433. {
  434. User = UserOrSeat
  435. Valid++
  436. }
  437. else
  438. {
  439. User = UserOrSeat:driver()
  440. Seated++
  441. Valid++
  442. }
  443. local KeyClk = keyClk()
  444. local KeyClkPressed = keyClkPressed()
  445. if(Valid) {Valid = (User:keyPressed(KeyClkPressed))}
  446. if(Valid)
  447. {
  448. if((KeyClkPressed == "0") | (KeyClkPressed == "pad_0"))
  449. {
  450. if(Seated) {UserOrSeat:printDriver(SCR_HELP_STRING)} else {print(SCR_HELP_STRING)}
  451. return -1
  452. }
  453. else
  454. {
  455. local Num = KeyClkPressed:right(1):toNumber() #thanks ferv. Way easier.
  456. if(inrange(Num,1,SCR_CMD_COUNT))
  457. {
  458. scr_transmit(Num,"",TransmitVector,UserOrSeat)
  459. scr_notify("Transitted " + SCR_CMD_PREFIXES[Num,string],UserOrSeat)
  460. Num = SCR_CMD_COUNT
  461. return Num
  462. }
  463. else
  464. {
  465. return 0
  466. }
  467. }
  468. }
  469.  
  470. }
  471.  
  472. #misuse check, similar to the name-check convention in python
  473. if(entity():getName() == "SCRL")
  474. {
  475. print("ERROR: [SCRL] is not to be used standalone, but as an imported library!")
  476. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement