aboutsummaryrefslogtreecommitdiff
path: root/gamemode/shared
diff options
context:
space:
mode:
authorAlexander Pickering <alexandermpickering@gmail.com>2016-07-10 17:04:29 -0400
committerAlexander Pickering <alexandermpickering@gmail.com>2016-07-10 17:04:29 -0400
commit1de5f9ac6f038bfed2230cc1272b253794b2f41a (patch)
tree15bc9d515f1f48c036522afb7cc71f60243849a9 /gamemode/shared
downloadartery-1de5f9ac6f038bfed2230cc1272b253794b2f41a.tar.gz
artery-1de5f9ac6f038bfed2230cc1272b253794b2f41a.tar.bz2
artery-1de5f9ac6f038bfed2230cc1272b253794b2f41a.zip
Initial commit
Diffstat (limited to 'gamemode/shared')
-rw-r--r--gamemode/shared/aes.lua526
-rw-r--r--gamemode/shared/concommands.lua28
-rw-r--r--gamemode/shared/fuzzel.lua286
-rw-r--r--gamemode/shared/inventory.lua213
-rw-r--r--gamemode/shared/inventory_common.lua205
-rw-r--r--gamemode/shared/itemcommon/common_inventory.lua9
-rw-r--r--gamemode/shared/itemsystem/exampleitem.lua25
-rw-r--r--gamemode/shared/itemsystem/scrapgun.lua60
-rw-r--r--gamemode/shared/loaditems.lua55
-rw-r--r--gamemode/shared/lockbox/array.lua211
-rw-r--r--gamemode/shared/lockbox/base64.lua157
-rw-r--r--gamemode/shared/lockbox/bit.lua11
-rw-r--r--gamemode/shared/lockbox/ecb.lua191
-rw-r--r--gamemode/shared/lockbox/padding.lua21
-rw-r--r--gamemode/shared/lockbox/queue.lua47
-rw-r--r--gamemode/shared/lockbox/stream.lua112
-rw-r--r--gamemode/shared/sh_setup.lua165
-rw-r--r--gamemode/shared/sparkel.lua17
18 files changed, 2339 insertions, 0 deletions
diff --git a/gamemode/shared/aes.lua b/gamemode/shared/aes.lua
new file mode 100644
index 0000000..5c4072a
--- /dev/null
+++ b/gamemode/shared/aes.lua
@@ -0,0 +1,526 @@
+print("Hello from aes.lua!")
+
+local Stream = include("lockbox/stream.lua");
+local Array = include("lockbox/array.lua");
+
+local Bit = include("lockbox/bit.lua");
+--local Math = require("math");
+
+
+local AND = bit.band;
+local OR = bit.bor;
+local NOT = bit.bnot;
+local XOR = bit.bxor;
+--local LROT = Bit.lrotate;
+--local RROT = Bit.rrotate;
+local LSHIFT = bit.lshift;
+local RSHIFT = bit.rshift;
+
+local SBOX = {
+ [0]=0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
+ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
+ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
+ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
+ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
+ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
+ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
+ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
+ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
+ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
+ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16};
+
+local ISBOX = {
+ [0]=0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
+ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
+ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
+ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
+ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
+ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
+ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
+ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
+ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
+ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
+ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D};
+
+local ROW_SHIFT = { 1, 6, 11, 16, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,};
+local IROW_SHIFT = { 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3, 16, 13, 10, 7, 4,};
+
+local ETABLE = {
+ [0]=0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, 0x96, 0xA1, 0xF8, 0x13, 0x35,
+ 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, 0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA,
+ 0xE5, 0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, 0x90, 0xAB, 0xE6, 0x31,
+ 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, 0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD,
+ 0x4C, 0xD4, 0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, 0x28, 0x78, 0x88,
+ 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, 0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A,
+ 0xB5, 0xC4, 0x57, 0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, 0x61, 0xA3,
+ 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, 0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0,
+ 0xFB, 0x16, 0x3A, 0x4E, 0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, 0x41,
+ 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, 0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75,
+ 0x9F, 0xBA, 0xD5, 0x64, 0xAC, 0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80,
+ 0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, 0xB1, 0xC8, 0x43, 0xC5, 0x54,
+ 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, 0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA,
+ 0x45, 0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, 0xC6, 0x51, 0xF3, 0x0E,
+ 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, 0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17,
+ 0x39, 0x4B, 0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, 0x52, 0xF6, 0x01};
+
+local LTABLE = {
+ [0]=0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1A, 0xC6, 0x4B, 0xC7, 0x1B, 0x68, 0x33, 0xEE, 0xDF, 0x03,
+ 0x64, 0x04, 0xE0, 0x0E, 0x34, 0x8D, 0x81, 0xEF, 0x4C, 0x71, 0x08, 0xC8, 0xF8, 0x69, 0x1C, 0xC1,
+ 0x7D, 0xC2, 0x1D, 0xB5, 0xF9, 0xB9, 0x27, 0x6A, 0x4D, 0xE4, 0xA6, 0x72, 0x9A, 0xC9, 0x09, 0x78,
+ 0x65, 0x2F, 0x8A, 0x05, 0x21, 0x0F, 0xE1, 0x24, 0x12, 0xF0, 0x82, 0x45, 0x35, 0x93, 0xDA, 0x8E,
+ 0x96, 0x8F, 0xDB, 0xBD, 0x36, 0xD0, 0xCE, 0x94, 0x13, 0x5C, 0xD2, 0xF1, 0x40, 0x46, 0x83, 0x38,
+ 0x66, 0xDD, 0xFD, 0x30, 0xBF, 0x06, 0x8B, 0x62, 0xB3, 0x25, 0xE2, 0x98, 0x22, 0x88, 0x91, 0x10,
+ 0x7E, 0x6E, 0x48, 0xC3, 0xA3, 0xB6, 0x1E, 0x42, 0x3A, 0x6B, 0x28, 0x54, 0xFA, 0x85, 0x3D, 0xBA,
+ 0x2B, 0x79, 0x0A, 0x15, 0x9B, 0x9F, 0x5E, 0xCA, 0x4E, 0xD4, 0xAC, 0xE5, 0xF3, 0x73, 0xA7, 0x57,
+ 0xAF, 0x58, 0xA8, 0x50, 0xF4, 0xEA, 0xD6, 0x74, 0x4F, 0xAE, 0xE9, 0xD5, 0xE7, 0xE6, 0xAD, 0xE8,
+ 0x2C, 0xD7, 0x75, 0x7A, 0xEB, 0x16, 0x0B, 0xF5, 0x59, 0xCB, 0x5F, 0xB0, 0x9C, 0xA9, 0x51, 0xA0,
+ 0x7F, 0x0C, 0xF6, 0x6F, 0x17, 0xC4, 0x49, 0xEC, 0xD8, 0x43, 0x1F, 0x2D, 0xA4, 0x76, 0x7B, 0xB7,
+ 0xCC, 0xBB, 0x3E, 0x5A, 0xFB, 0x60, 0xB1, 0x86, 0x3B, 0x52, 0xA1, 0x6C, 0xAA, 0x55, 0x29, 0x9D,
+ 0x97, 0xB2, 0x87, 0x90, 0x61, 0xBE, 0xDC, 0xFC, 0xBC, 0x95, 0xCF, 0xCD, 0x37, 0x3F, 0x5B, 0xD1,
+ 0x53, 0x39, 0x84, 0x3C, 0x41, 0xA2, 0x6D, 0x47, 0x14, 0x2A, 0x9E, 0x5D, 0x56, 0xF2, 0xD3, 0xAB,
+ 0x44, 0x11, 0x92, 0xD9, 0x23, 0x20, 0x2E, 0x89, 0xB4, 0x7C, 0xB8, 0x26, 0x77, 0x99, 0xE3, 0xA5,
+ 0x67, 0x4A, 0xED, 0xDE, 0xC5, 0x31, 0xFE, 0x18, 0x0D, 0x63, 0x8C, 0x80, 0xC0, 0xF7, 0x70, 0x07};
+
+local MIXTABLE = {
+ 0x02, 0x03, 0x01, 0x01,
+ 0x01, 0x02, 0x03, 0x01,
+ 0x01, 0x01, 0x02, 0x03,
+ 0x03, 0x01, 0x01, 0x02};
+
+local IMIXTABLE = {
+ 0x0E, 0x0B, 0x0D, 0x09,
+ 0x09, 0x0E, 0x0B, 0x0D,
+ 0x0D, 0x09, 0x0E, 0x0B,
+ 0x0B, 0x0D, 0x09, 0x0E};
+
+local RCON = {
+[0] = 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
+0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
+0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
+0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
+0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
+0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
+0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
+0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
+0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
+0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
+0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
+0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
+0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
+0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
+0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d};
+
+
+local GMUL = function(A,B)
+ if(A == 0x01) then return B; end
+ if(B == 0x01) then return A; end
+ if(A == 0x00) then return 0; end
+ if(B == 0x00) then return 0; end
+ print("Gettin gthe LTable of " .. A)
+ print("Getting the LTable of " .. B)
+ local LA = LTABLE[A];
+ local LB = LTABLE[B];
+
+ local sum = LA + LB;
+ if (sum > 0xFF) then sum = sum - 0xFF; end
+
+ return ETABLE[sum];
+end
+
+local byteSub = Array.substitute;
+
+local shiftRow = Array.permute;
+
+local mixCol = function(i,mix)
+ local out = {};
+
+ local a,b,c,d;
+ print("I is:")
+ PrintTable(i)
+ a = GMUL(i[ 1],mix[ 1]);
+ b = GMUL(i[ 2],mix[ 2]);
+ c = GMUL(i[ 3],mix[ 3]);
+ d = GMUL(i[ 4],mix[ 4]);
+ out[ 1] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[ 1],mix[ 5]);
+ b = GMUL(i[ 2],mix[ 6]);
+ c = GMUL(i[ 3],mix[ 7]);
+ d = GMUL(i[ 4],mix[ 8]);
+ out[ 2] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[ 1],mix[ 9]);
+ b = GMUL(i[ 2],mix[10]);
+ c = GMUL(i[ 3],mix[11]);
+ d = GMUL(i[ 4],mix[12]);
+ out[ 3] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[ 1],mix[13]);
+ b = GMUL(i[ 2],mix[14]);
+ c = GMUL(i[ 3],mix[15]);
+ d = GMUL(i[ 4],mix[16]);
+ out[ 4] = XOR(XOR(a,b),XOR(c,d));
+
+
+ a = GMUL(i[ 5],mix[ 1]);
+ b = GMUL(i[ 6],mix[ 2]);
+ c = GMUL(i[ 7],mix[ 3]);
+ d = GMUL(i[ 8],mix[ 4]);
+ out[ 5] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[ 5],mix[ 5]);
+ b = GMUL(i[ 6],mix[ 6]);
+ c = GMUL(i[ 7],mix[ 7]);
+ d = GMUL(i[ 8],mix[ 8]);
+ out[ 6] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[ 5],mix[ 9]);
+ b = GMUL(i[ 6],mix[10]);
+ c = GMUL(i[ 7],mix[11]);
+ d = GMUL(i[ 8],mix[12]);
+ out[ 7] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[ 5],mix[13]);
+ b = GMUL(i[ 6],mix[14]);
+ c = GMUL(i[ 7],mix[15]);
+ d = GMUL(i[ 8],mix[16]);
+ out[ 8] = XOR(XOR(a,b),XOR(c,d));
+
+
+ a = GMUL(i[ 9],mix[ 1]);
+ b = GMUL(i[10],mix[ 2]);
+ c = GMUL(i[11],mix[ 3]);
+ d = GMUL(i[12],mix[ 4]);
+ out[ 9] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[ 9],mix[ 5]);
+ b = GMUL(i[10],mix[ 6]);
+ c = GMUL(i[11],mix[ 7]);
+ d = GMUL(i[12],mix[ 8]);
+ out[10] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[ 9],mix[ 9]);
+ b = GMUL(i[10],mix[10]);
+ c = GMUL(i[11],mix[11]);
+ d = GMUL(i[12],mix[12]);
+ out[11] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[ 9],mix[13]);
+ b = GMUL(i[10],mix[14]);
+ c = GMUL(i[11],mix[15]);
+ d = GMUL(i[12],mix[16]);
+ out[12] = XOR(XOR(a,b),XOR(c,d));
+
+
+ a = GMUL(i[13],mix[ 1]);
+ b = GMUL(i[14],mix[ 2]);
+ c = GMUL(i[15],mix[ 3]);
+ d = GMUL(i[16],mix[ 4]);
+ out[13] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[13],mix[ 5]);
+ b = GMUL(i[14],mix[ 6]);
+ c = GMUL(i[15],mix[ 7]);
+ d = GMUL(i[16],mix[ 8]);
+ out[14] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[13],mix[ 9]);
+ b = GMUL(i[14],mix[10]);
+ c = GMUL(i[15],mix[11]);
+ d = GMUL(i[16],mix[12]);
+ out[15] = XOR(XOR(a,b),XOR(c,d));
+ a = GMUL(i[13],mix[13]);
+ b = GMUL(i[14],mix[14]);
+ c = GMUL(i[15],mix[15]);
+ d = GMUL(i[16],mix[16]);
+ out[16] = XOR(XOR(a,b),XOR(c,d));
+
+ return out;
+end
+
+local keyRound = function(key,round)
+ local i=(round-1)*32;
+ local out=key;
+ print("Doing keyRound on key:")
+ PrintTable(key)
+ print("key[i+1]=")
+ print(key[i+1])
+ print("SBOX[out[30+i]]=")
+ print(SBOX[out[30+i]])
+ print("out[30+i]=")
+ print(out[30+i])
+ print("RCON[round]=")
+ print(RCON[round])
+ out[33+i] = XOR(key[ 1+i],XOR(SBOX[key[30+i]],RCON[round]));
+ out[34+i] = XOR(key[ 2+i],SBOX[key[31+i]]);
+ out[35+i] = XOR(key[ 3+i],SBOX[key[32+i]]);
+ out[36+i] = XOR(key[ 4+i],SBOX[key[29+i]]);
+
+ out[37+i] = XOR(out[33+i],key[ 5+i]);
+ out[38+i] = XOR(out[34+i],key[ 6+i]);
+ out[39+i] = XOR(out[35+i],key[ 7+i]);
+ out[40+i] = XOR(out[36+i],key[ 8+i]);
+
+ out[41+i] = XOR(out[37+i],key[ 9+i]);
+ out[42+i] = XOR(out[38+i],key[10+i]);
+ out[43+i] = XOR(out[39+i],key[11+i]);
+ out[44+i] = XOR(out[40+i],key[12+i]);
+
+ out[45+i] = XOR(out[41+i],key[13+i]);
+ out[46+i] = XOR(out[42+i],key[14+i]);
+ out[47+i] = XOR(out[43+i],key[15+i]);
+ out[48+i] = XOR(out[44+i],key[16+i]);
+
+
+ out[49+i] = XOR(SBOX[out[45+i]],key[17+i]);
+ out[50+i] = XOR(SBOX[out[46+i]],key[18+i]);
+ out[51+i] = XOR(SBOX[out[47+i]],key[19+i]);
+ out[52+i] = XOR(SBOX[out[48+i]],key[20+i]);
+
+ out[53+i] = XOR(out[49+i],key[21+i]);
+ out[54+i] = XOR(out[50+i],key[22+i]);
+ out[55+i] = XOR(out[51+i],key[23+i]);
+ out[56+i] = XOR(out[52+i],key[24+i]);
+
+ out[57+i] = XOR(out[53+i],key[25+i]);
+ out[58+i] = XOR(out[54+i],key[26+i]);
+ out[59+i] = XOR(out[55+i],key[27+i]);
+ out[60+i] = XOR(out[56+i],key[28+i]);
+
+ out[61+i] = XOR(out[57+i],key[29+i]);
+ out[62+i] = XOR(out[58+i],key[30+i]);
+ out[63+i] = XOR(out[59+i],key[31+i]);
+ out[64+i] = XOR(out[60+i],key[32+i]);
+
+ return out;
+end
+
+local keyExpand = function(key)
+ local bytes = Array.copy(key);
+
+ for i=1,7 do
+ keyRound(bytes,i);
+ end
+
+ local keys = {};
+
+ keys[ 1] = Array.slice(bytes,1,16);
+ keys[ 2] = Array.slice(bytes,17,32);
+ keys[ 3] = Array.slice(bytes,33,48);
+ keys[ 4] = Array.slice(bytes,49,64);
+ keys[ 5] = Array.slice(bytes,65,80);
+ keys[ 6] = Array.slice(bytes,81,96);
+ keys[ 7] = Array.slice(bytes,97,112);
+ keys[ 8] = Array.slice(bytes,113,128);
+ keys[ 9] = Array.slice(bytes,129,144);
+ keys[10] = Array.slice(bytes,145,160);
+ keys[11] = Array.slice(bytes,161,176);
+ keys[12] = Array.slice(bytes,177,192);
+ keys[13] = Array.slice(bytes,193,208);
+ keys[14] = Array.slice(bytes,209,224);
+ keys[15] = Array.slice(bytes,225,240);
+
+ return keys;
+
+end
+
+local addKey = Array.XOR;
+
+
+
+local AES = {};
+
+AES.blockSize = 16;
+
+AES.encrypt = function(key,block)
+ print("Calling keyExpand on :")
+ PrintTable(key)
+ local key = keyExpand(key);
+
+ --round 0
+ block = addKey(block,key[1]);
+
+ print("block is:")
+ PrintTable(block)
+
+ --round 1
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[2]);
+
+ --round 2
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[3]);
+
+ --round 3
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[4]);
+
+ --round 4
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[5]);
+
+ --round 5
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[6]);
+
+ --round 6
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[7]);
+
+ --round 7
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[8]);
+
+ --round 8
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[9]);
+
+ --round 9
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[10]);
+
+ --round 10
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[11]);
+
+ --round 11
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[12]);
+
+ --round 12
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[13]);
+
+ --round 13
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = mixCol(block,MIXTABLE);
+ block = addKey(block,key[14]);
+
+ --round 14
+ block = byteSub(block,SBOX);
+ block = shiftRow(block,ROW_SHIFT);
+ block = addKey(block,key[15]);
+
+ return block;
+
+end
+
+AES.decrypt = function(key,block)
+
+ local key = keyExpand(key);
+
+ --round 0
+ block = addKey(block,key[15]);
+
+ --round 1
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[14]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 2
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[13]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 3
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[12]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 4
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[11]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 5
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[10]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 6
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[9]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 7
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[8]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 8
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[7]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 9
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[6]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 10
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[5]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 11
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[4]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 12
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[3]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 13
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[2]);
+ block = mixCol(block,IMIXTABLE);
+
+ --round 14
+ block = shiftRow(block,IROW_SHIFT);
+ block = byteSub(block,ISBOX);
+ block = addKey(block,key[1]);
+
+ return block;
+end
+
+return AES;
diff --git a/gamemode/shared/concommands.lua b/gamemode/shared/concommands.lua
new file mode 100644
index 0000000..b4e844a
--- /dev/null
+++ b/gamemode/shared/concommands.lua
@@ -0,0 +1,28 @@
+--[[
+ Various console command helper functions
+]]
+
+local fuzzel = include("fuzzel.lua")
+
+local concmd = {}
+
+function concmd.AutocompleteFunction(...)
+ local opt = {...}
+ opt = type(opt[1]) == "table" and opt[1] or opt
+ return function(cmd,strargs)
+ --Remove spaces and quotes, since we don't want to match them
+ strargs = string.gsub(strargs,"[\" ]","")
+ --Find the options that most closely resemble our command so far
+ local sorted = fuzzel.fad(strargs,opt)
+ --Add quotes if needed, and preppend the command to each option
+ for k,v in pairs(sorted) do
+ if string.find(v," ") ~= nil then
+ sorted[k] = "\"" .. v .. "\""
+ end
+ sorted[k] = cmd .. " " .. sorted[k]
+ end
+ return sorted
+ end
+end
+
+return concmd
diff --git a/gamemode/shared/fuzzel.lua b/gamemode/shared/fuzzel.lua
new file mode 100644
index 0000000..6aad45f
--- /dev/null
+++ b/gamemode/shared/fuzzel.lua
@@ -0,0 +1,286 @@
+--[[
+ Fuzzel v1.3 - Alexander "Apickx" Pickering
+ Entered into the public domain June 2, 2016
+ You are not required to, but consider putting a link to the source in your file's comments!
+
+ Some helper functions for calculateing distance between two strings
+
+ Provides:
+ fuzzel.LevenshteinDistance_extended(string_first, string_second, number_addcost, number_substituecost, number_deletecost)
+ Calculates the Levenshtein Distance between two strings, useing the costs given. "Real" Levenshtein Distance uses values 1,1,1 for costs.
+ returns number_distance
+
+ fuzzel.LevenshteinDistance(string_first, strings_second)
+ Calculates the "real" Levenshtein Distance
+ returns number_distance
+
+ fuzzel.LevensteinRatio(string_first, string_second)
+ The Levenshtein Ratio divided by the first string's length. Useing a ratio is a decent way to determin if a spelling is "close enough"
+ returns number_distance
+
+ fuzzel.DamerauLevenshteinDistance_extended(string_first, string_second, number_addcost, number_substituecost, number_deletecost, number_transpositioncost)
+ Damerau-Levenshtein Distance is almost exactly like Levenshtein Distance, with the caveat that two letters next to each other, with swapped positions only counts as "one" cost (in "real" Damerau-Levenshtein Distance)
+ returns number
+
+ fuzzel.DamerauLevenshteinDistance(stirng_first, strings_second)
+ Calculates the "real" Damerau-Levenshtein Distance
+ returns number
+
+ fuzzel.DamerauLevenshteinRatio(string_first, string_second)
+ The Damerau-Levenshtein Distance divided by the first string's length
+ returns number_ratio
+
+ fuzzel.HammingDistance(string_first, string_second)
+ Purely the number of substitutions needed to change one string into another. Note that both strings must be the same length.
+ returns number_distance
+
+ fuzzel.HammingRatio(string_first, string_second)
+ The hamming distance divided by the length of the first string
+ returns number_ratio
+
+ fuzzel.FuzzyFindDistance(string_needle, vararg_in)
+ in may be either a table, or a list of arguments. fuzzel.FuzzySearchDistance will find the string that most closely resembles needle, based on Damerau-Levenshtein Distance. If multiple options have the same distance, it will return the first one encountered (This may not be in any sort of order!)
+ returns string_closest, number_distance
+
+ fuzzel.FuzzyFindRatio(string_needle, vararg_in)
+ in may be either a table, or a list of arguments. Same as above, except it returns the string with the closest Damerau-Levenshtein ratio.
+ returns string_closest, nubmer_ratio
+
+ fuzzel.FuzzySortDistance(string_needle, vararg_in)
+ Sorts either the table, or the arguments, and returns a table. Uses Damerau-Levenshtein Distance
+ returns table_sorted
+
+ fuzzel.FuzzySortRatio(string needle, vararg_in)
+ Same as above, but uses Damerau-Levenshtein Ratio instead
+ returns table_sorted
+
+ fuzzel.FuzzyAutocompleteDistance(string_needle, vararg in)
+ vararg_in can be either a table, or a list of entries, this will fuzzy sort based on the length of the input, which makes it better at autocompletion than fuzzy sorting. Uses Damerau-Levenshtein Distance.
+ returns table_sorted
+
+ fuzzel.FuzzyAutocompleteRatio(string_needle, vararg_in)
+ Same as above, but uses DamerauLevenshteinRatio
+ returns table_sorted
+
+ Example:
+ Returns a function that will return the closest string to the string it was passed
+ -----------------FuzzelExample.lua------------------
+ --Include the module
+ local fuzzel = require("fuzzel.lua")
+
+ --A couple of options
+ local options = {
+ "Fat Cat",
+ "Lazy Dog",
+ "Brown Fox",
+ }
+
+ --And use it, to see what option closest matches "Lulzy Cat"
+ local close,distance = fuzzel.FuzzyFindDistance("Lulzy Cat", options)
+ print("\"Lulzy Cat\" is close to \"" .. close .. "\", distance:" .. distance)
+
+ --Sort the options to see the order in which they most closely match "Frag God"
+ print("\"Frag God\" is closest to:")
+ for k,v in ipairs(fuzzel.FuzzySortRatio("Frag God",options)) do
+ print(k .. "\t:\t" .. v)
+ end
+ -------------End FuzzelExample.lua------------------
+ Outputs:
+ "Lulzy Cat" is close to "Fat Cat"
+ "Frag God" is closest to:
+ 1 : Fat Cat
+ 2 : Lazy Dog
+ 3 : Brown Fox
+
+ Some easy-to-use mnemonics
+ fuzzel.ld_e = fuzzel.LevenshteinDistance_extended
+ fuzzel.ld = fuzzel.LevenshteinDistance
+ fuzzel.lr = fuzzel.LevensteinRatio
+ fuzzel.dld_e = fuzzel.DamerauLevenshteinDistance_extended
+ fuzzel.dld = fuzzel.DamerauLevenshteinDistance
+ fuzzel.dlr = fuzzel.DamerauLevenshteinRatio
+ fuzzel.hd = fuzzel.HammingDistance
+ fuzzel.hr = fuzzel.HammingRatio
+ fuzzel.ffd = fuzzel.FuzzyFindDistance
+ fuzzel.ffr = fuzzel.FuzzyFindRatio
+ fuzzel.fsd = fuzzel.FuzzySortDistance
+ fuzzel.fsr = fuzzel.FuzzySortRatio
+ fuzzel.fad = fuzzel.FuzzyAutocompleteDistance
+ fuzzel.far = fuzzel.FuzzyAutocompleteRatio
+
+]]--You probably don't want to touch anything past this point
+
+--Assign locals to these to the minifier can compress the file better
+local strlen,chrat,min,asrt,prs,iprs,typ,upack,tblins,tblsrt,strsub,tru,fal = string.len,string.byte,math.min,assert,pairs,ipairs,type,unpack,table.insert,table.sort,string.sub,true,false
+
+local fuzzel = {}
+
+--A clever way to allow the minifier to minify function names, this basically just assigns variables with their string equivalent.
+local da, le, di, ra, fu, fi, so, ex, ha, au = "Damerau", "Levenshtein", "Distance", "Ratio", "Fuzzy", "Find", "Sort", "_extended", "Hamming", "Autocomplete"
+local LevenshteinDistance_extended,LevenshteinDistance,LevenshteinRatio,DamerauLevenshteinDistance_extended,DamerauLevenshteinDistance,DamerauLevenshteinRatio,FuzzyFindDistance,FuzzyFindRatio,FuzzySortDistance,FuzzySortRatio,HammingDistance,HammingRatio,FuzzyAutocompleteDistance,FuzzyAutocompleteRatio = le..di..ex,le..di,le..ra,da..le..di..ex,da..le..di,da..le..ra,fu..fi..di,fu..fi..ra,fu..so..di,fu..so..ra,ha..di,ha..ra,fu..au..di,fu..au..ra
+
+local function genericDistance( stringa, stringb, addcost, subcost, delcost, ...)
+ local arg = {...}
+
+ --Length of each string
+ local salen, sblen = strlen(stringa), strlen(stringb)
+
+ --Create a 0 matrix the size of len(a) x len(b)
+ local dyntbl = {}
+ for i = 0,salen do
+ dyntbl[i] = {}
+ for j = 0,sblen do
+ dyntbl[i][j] = 0
+ end
+ end
+
+ --Initalize the matrix
+ for i = 1,salen do
+ dyntbl[i][0] = i
+ end
+ for j = 1,sblen do
+ dyntbl[0][j] = j
+ end
+
+ --And build up the matrix based on costs-so-far
+ for j = 1,sblen do
+ for i = 1,salen do
+ local ca,cb = chrat(stringa,i),chrat(stringb,j)
+ dyntbl[i][j] = min(
+ dyntbl[i-1][j] + delcost, --deletion
+ dyntbl[i][j-1] + addcost, --insertion
+ dyntbl[i-1][j-1] + (ca == cb and 0 or subcost) --substituion
+ )
+ if arg[1] and i > 1 and j > 1 and ca == chrat(stringb,j-1) and chrat(stringa,i-1) == cb then
+ dyntbl[i][j] = min(dyntbl[i][j],
+ dyntbl[i-2][j-2] + (ca == cb and 0 or arg[2])) --transposition
+ end
+ end
+ end
+
+ return dyntbl[salen][sblen]
+end
+
+fuzzel[LevenshteinDistance_extended] = function(stringa, stringb, addcost, subcost, delcost)
+ return genericDistance(stringa, stringb, addcost, subcost, delcost)
+end
+fuzzel.ld_e = fuzzel[LevenshteinDistance_extended]
+
+fuzzel[LevenshteinDistance] = function(stringa,stringb)
+ return fuzzel.ld_e(stringa,stringb,1,1,1)
+end
+fuzzel.ld = fuzzel[LevenshteinDistance]
+
+fuzzel[LevenshteinRatio] = function(stringa,stringb)
+ return fuzzel.ld(stringa,stringb) / strlen(stringa)
+end
+fuzzel.lr = fuzzel[LevenshteinRatio]
+
+fuzzel[DamerauLevenshteinDistance_extended] = function(stringa, stringb, addcost, subcost, delcost, trncost)
+ return genericDistance(stringa,stringb,addcost,subcost,delcost,tru,trncost)
+end
+fuzzel.dld_e = fuzzel[DamerauLevenshteinDistance_extended]
+
+fuzzel[DamerauLevenshteinDistance] = function(stringa,stringb)
+ return fuzzel.dld_e(stringa,stringb,1,1,1,1)
+end
+fuzzel.dld = fuzzel[DamerauLevenshteinDistance]
+
+fuzzel[DamerauLevenshteinRatio] = function(stringa,stringb)
+ return fuzzel.dld(stringa,stringb) / strlen(stringa)
+end
+fuzzel.dlr = fuzzel[DamerauLevenshteinRatio]
+
+fuzzel[HammingDistance] = function(stringa,stringb)
+ local len,dist = strlen(stringa),0
+ asrt(len == strlen(stringb), ha.." "..di.." cannot be calculated on two strings of different lengths:\"" .. stringa .. "\" \"" .. stringb .. "\"")
+ for i = 1,len do
+ dist = dist + ((chrat(stringa,i) ~= chrat(stringb,i)) and 1 or 0)
+ end
+ return dist
+end
+fuzzel.hd = fuzzel[HammingDistance]
+
+fuzzel[HammingRatio] = function(stringa,stringb)
+ return fuzzel.hd(stringa,stringb) / strlen(stringa)
+end
+fuzzel.hr = fuzzel[HammingRatio]
+
+local function FuzzySearch(str,func,...)
+ local arg = {...}
+
+ --Allow varargs, or a table
+ local looparg = typ(arg[1]) == "table" and arg[1] or arg
+
+ --Find the string with the shortest distance to the string we were supplied
+ local tmin,sout = func(looparg[1],str),looparg[1]
+ for k,v in prs(looparg) do
+ local t = func(v,str)
+ if t <= tmin then
+ tmin,sout = t,k
+ end
+ end
+ return looparg[sout], tmin
+end
+
+fuzzel[FuzzyFindDistance] = function(str,...)
+ return upack{FuzzySearch(str,fuzzel.dld,...)}
+end
+fuzzel.ffd = fuzzel[FuzzyFindDistance]
+
+fuzzel[FuzzyFindRatio] = function(str,...)
+ return upack{FuzzySearch(str,fuzzel.dlr,...)}
+end
+
+local function FuzzySort(str, func, short, ...)
+ local arg = {...}
+
+ --allow varargs, or a table
+ local looparg = typ(arg[1]) == "table" and arg[1] or arg
+
+ --Roughly sort everything by it's distance to the string
+ local usorted,sorted,otbl,slen = {},{},{},strlen(str)
+ for k,v in prs(looparg) do
+ local sstr = short and strsub(v,0,slen) or v
+ local dist = func(str,sstr)
+ if usorted[dist] == nil then
+ usorted[dist] = {}
+ tblins(sorted,dist)
+ end
+ tblins(usorted[dist],v)
+ end
+
+ --Actually sort them into something can can be iterated with ipairs
+ tblsrt(sorted)
+
+ --Then build our output table
+ for k,v in iprs(sorted) do
+ for i,j in prs(usorted[v]) do
+ tblins(otbl,j)
+ end
+ end
+ return otbl
+end
+fuzzel.ffr = fuzzel[FuzzyFindRatio]
+
+fuzzel[FuzzySortDistance] = function(str,...)
+ return FuzzySort(str,fuzzel.dld,fal,...)
+end
+fuzzel.fsd = fuzzel[FuzzySortDistance]
+
+fuzzel[FuzzySortRatio] = function(str,...)
+ return FuzzySort(str,fuzzel.dlr,fal,...)
+end
+fuzzel.fsr = fuzzel[FuzzySortRatio]
+
+fuzzel[FuzzyAutocompleteDistance] = function(str, ...)
+ return FuzzySort(str,fuzzel.dld,tru,...)
+end
+fuzzel.fad = fuzzel[FuzzyAutocompleteDistance]
+
+fuzzel[FuzzyAutocompleteRatio] = function(str,...)
+ return FuzzySort(str,fuzzel.dlr,tru,...)
+end
+fuzzel.far = fuzzel[FuzzyAutocompleteRatio]
+
+return fuzzel
diff --git a/gamemode/shared/inventory.lua b/gamemode/shared/inventory.lua
new file mode 100644
index 0000000..42f4516
--- /dev/null
+++ b/gamemode/shared/inventory.lua
@@ -0,0 +1,213 @@
+
+print("Hello from inventory.lua!")
+local pmeta = FindMetaTable("Player")
+local emeta = FindMetaTable("Entity")
+local invfuncs = include("inventory_common.lua")
+
+--A 2d array of the inventory.
+pmeta.Inventory = {}
+
+--each backpack has 1:a tbl containing items or false, 2: a tbl {width,height} and 3:name
+pmeta.Inventory.Backpacks = {}
+--Eqiped stuff at base, player has 1=Head, 2=Body, 3=Legs, 4=Boots, 5=Gloves, 6=Left Hand, 7=Right Hand
+pmeta.Inventory.Equiped = {}
+local equipedslots = {
+ "Head","Body","Legs","Boots","Gloves","Left","Right"
+}
+for _,v in pairs(equipedslots) do
+ pmeta.Inventory.Equiped[v] = false
+end
+
+function pmeta:PutInvItem(backpack,x,y,item)
+ invfuncs.PutItemInBackpack(self.Inventory.Backpacks[backpack],x,y,item)
+end
+
+function pmeta:FindSpotForItem(item)
+ for n,v in pairs(self.Inventory.Backpacks) do
+ for row = 1,v[2][2] do
+ for col = 1,v[2][1] do
+ if self:CanFitInBackpack(v,row,col,item) then
+ return row,col,n
+ end
+ end
+ end
+ end
+end
+
+function pmeta:GiveItem(item)
+ local x,y,b = self:FindSpotForItem(item)
+ self:PutInvItem(b,x,y,item)
+ self:SynchronizeInventory()
+end
+
+function pmeta:CanFitInBackpack(backpack,x,y,item)
+ return invfuncs.CanFitInBackpack(backpack,x,y,item)
+end
+
+if SERVER then
+ util.AddNetworkString("synchinventory")
+ util.AddNetworkString("moveitem")
+ util.AddNetworkString("equipitem")
+ util.AddNetworkString("unequipitem")
+end
+
+net.Receive("unequipitem",function(len,ply)
+ local itemslot = net.ReadString()
+ local tobackpack = net.ReadUInt(16)
+ local topos = {}
+ topos[1] = net.ReadUInt(16)
+ topos[2] = net.ReadUInt(16)
+ local item = ply.Inventory.Equiped[itemslot]
+ if ply:CanFitInBackpack(
+ ply.Inventory.Backpacks[tobackpack],
+ topos[1],
+ topos[2],
+ item
+ ) then
+ ply.Inventory.Equiped[itemslot] = false
+ ply:PutInvItem(tobackpack,topos[1],topos[2],item)
+ ply:SynchronizeInventory()
+ end
+end)
+
+net.Receive("equipitem",function(len,ply)
+ local backpacknum = net.ReadUInt(16)
+ local frompos = {}
+ frompos[1] = net.ReadUInt(16)
+ frompos[2] = net.ReadUInt(16)
+ local equippos = net.ReadString()
+ local item = ply.Inventory.Backpacks[backpacknum][1][frompos[1]][frompos[2]]
+ if item.Equipable ~= nil and item.Equipable == equippos then
+ --Remove from the backpack
+ for k = 1,#item.Shape do
+ for i = 1,#(item.Shape[k]) do
+ if k == 1 and i == 1 then continue end
+ ply.Inventory.Backpacks[backpacknum][1][frompos[1] + k - 1][frompos[2] + i - 1] = false
+ end
+ end
+ ply.Inventory.Backpacks[backpacknum][1][frompos[1]][frompos[2]] = false
+ ply.Inventory.Equiped[equippos] = item
+ if item.onEquip ~= nil then
+ item:onEquip(ply)
+ end
+ ply:SynchronizeInventory()
+ end
+end)
+
+net.Receive("moveitem",function(len,ply)
+ local froment = net.ReadEntity()
+ local toent = net.ReadEntity()
+
+ local frombackpack = net.ReadUInt(16)
+ local tobackpack = net.ReadUInt(16)
+
+ local frompos = {net.ReadUInt(16),net.ReadUInt(16)}
+ local topos = {net.ReadUInt(16),net.ReadUInt(16)}
+
+ print("Moveing from ",frompos[1],frompos[2],"to",topos[1],topos[2])
+
+ if froment:IsPlayer() and toent:IsPlayer() and (froment ~= toent) then--Just don't allow stealing between players, anything else is fine
+ ply:PrintMessage( HUD_PRINTCENTER, "You can't steal from this person!" )
+ return
+ end
+ print("Passed the stealing check")
+ local item = froment.Inventory.Backpacks[frombackpack][1][frompos[1]][frompos[2]]
+
+ --Set the shape it was at to false
+ for k = 1,#item.Shape do
+ for i = 1,#(item.Shape[k]) do
+ if k == 1 and i == 1 then continue end
+ froment.Inventory.Backpacks[frombackpack][1][frompos[1] + k - 1][frompos[2] + i - 1] = false
+ end
+ end
+ froment.Inventory.Backpacks[frombackpack][1][frompos[1]][frompos[2]] = false
+ print("Set shape to false")
+ --now check if it can fit in the backpack
+ if invfuncs.CanFitInBackpack(toent.Inventory.Backpacks[tobackpack],topos[1],topos[2],item) then
+ print("It can fit there")
+ invfuncs.PutItemInBackpack(toent.Inventory.Backpacks[tobackpack],topos[1],topos[2],item)
+ else
+ invfuncs.PutItemInBackpack(froment.Inventory.Backpacks[frombackpack],frompos[1],frompos[2],item)
+ end
+ froment:SynchronizeInventory()
+ toent:SynchronizeInventory()
+end)
+
+function pmeta:LoadInventory(json)
+ local reinv = util.JSONToTable(json)
+ for k,v in pairs(reinv) do
+ self.Inventory[k] = v
+ end
+ self:SynchronizeInventory()
+end
+
+function pmeta:SynchronizeInventory()
+ print("Player synchronize called")
+ net.Start("synchinventory")
+ net.WriteEntity(self)
+ net.WriteFloat(#self.Inventory.Backpacks)
+ for k,v in pairs(self.Inventory.Backpacks) do
+ invfuncs.SerializeBackpack(v)
+ end
+ for k,v in pairs(equipedslots) do
+ if self.Inventory.Equiped and self.Inventory.Equiped[v] ~= false then
+ net.WriteString(v)
+ local data = self.Inventory.Equiped[v]:Serialize()
+ net.WriteString(self.Inventory.Equiped[v].Name)
+ net.WriteUInt(#data,32)
+ net.WriteData(data,#data)
+ end
+ end
+ net.WriteString("END_EQUIPED")
+ net.Send(self)
+end
+if CLIENT then
+ net.Receive("synchinventory",function(len,ply)
+ if LocalPlayer().invdisplays == nil then
+ LocalPlayer().invdisplays = {}
+ end
+ local what = net.ReadEntity()
+ what.Inventory.Backpacks = {}
+ local numbackpacks = net.ReadFloat()
+ for k = 1,numbackpacks do
+ local tbackpack = invfuncs.DeSerializeBackpack()
+ table.insert(what.Inventory.Backpacks,tbackpack)
+ end
+ local neq = net.ReadString()
+ local updated_slots = {}
+ while neq ~= "END_EQUIPED" do
+ local itemslot = neq
+ local itemname = net.ReadString()
+ local itemdata = net.ReadData(net.ReadUInt(32))
+ local item = ART.GetItemByName(itemname):DeSerialize(itemdata)
+ what.Inventory.Equiped[itemslot] = item
+ updated_slots[itemslot] = true
+ neq = net.ReadString()
+ end
+ if what.Inventory.Equiped ~= nil then
+ for k,v in pairs(equipedslots) do
+ if updated_slots[v] then continue end
+ what.Inventory.Equiped[v] = false
+ end
+ end
+ local discopy = LocalPlayer().invdisplays
+ LocalPlayer().invdisplays = {}
+ PrintTable(discopy)
+ for k,ptbl in pairs(discopy) do
+ if not ptbl.panel:IsValid() then continue end
+ if ptbl.panel.Close ~= nil then
+ ptbl.panel:Close()
+ else
+ print(ptbl.panel)
+ error("panel has no close method")
+ ptbl.panel:Remove()
+ end
+ ptbl.redraw()
+ end
+ end)
+end
+
+concommand.Add("artery_showinventory",function(ply,cmd,args)
+ PrintTable(ply.Inventory)
+ PrintTable(ply.ClientInventory)
+end)
diff --git a/gamemode/shared/inventory_common.lua b/gamemode/shared/inventory_common.lua
new file mode 100644
index 0000000..e86d0a6
--- /dev/null
+++ b/gamemode/shared/inventory_common.lua
@@ -0,0 +1,205 @@
+--[[
+ Some functions that are needed multiple places in the code, to deal with player inventories.
+]]
+local invfuncs = {}
+
+--Forcibly put an item in a backpack, you should check to make sure there's room first
+invfuncs.PutItemInBackpack = function(backpack,x,y,item)
+ backpack[1][x][y] = item
+ for k = 1,#item.Shape do
+ for i = 1,#(item.Shape[k]) do
+ if k == 1 and i == 1 then continue end
+ backpack[1][x + k - 1][y + i - 1] = item.Shape[k][i]
+ end
+ end
+end
+
+--Writes a backpack to the net stream
+invfuncs.SerializeBackpack = function(backpack)
+ net.WriteString(backpack[3]) --Name
+ net.WriteUInt(backpack[2][1],16) --width
+ net.WriteUInt(backpack[2][2],16) --height
+ for k,v in pairs(backpack[1]) do
+ for i,j in pairs(v) do
+ if type(j) ~= "table" then continue end
+ net.WriteString(j.Name)
+ net.WriteUInt(k,16)
+ net.WriteUInt(i,16)
+ local data = j:Serialize()
+ net.WriteUInt(#data,32)
+ net.WriteData(data,#data)
+ end
+ end
+ net.WriteString("END_ITEMS")
+end
+
+--Loads a backpack from the net stream
+invfuncs.DeSerializeBackpack = function()
+ local backpackname = net.ReadString()
+ local width = net.ReadUInt(16)
+ local height = net.ReadUInt(16)
+ --Build the backpack
+ local tb = {}
+ tb[1] = {}
+ tb[2] = {width,height}
+ tb[3] = backpackname
+ for x = 1,width do
+ tb[1][x] = {}
+ for y = 1,height do
+ tb[1][x][y] = false
+ end
+ end
+
+ local nitemname = net.ReadString()
+ while nitemname ~= "END_ITEMS" do
+ local xpos = net.ReadUInt(16)
+ local ypos = net.ReadUInt(16)
+ local data = net.ReadData(net.ReadUInt(32))
+ local nitem = ART.GetItemByName(nitemname):DeSerialize(data)
+ invfuncs.PutItemInBackpack(tb,xpos,ypos,nitem)
+ nitemname = net.ReadString()
+ end
+
+ return tb
+
+end
+
+--Checks to see if an item can fit in the backpack at a certain position
+invfuncs.CanFitInBackpack = function(backpack,x,y,item)
+ for k,v in pairs(item.Shape) do
+ for i,j in pairs(v) do
+ if not j then continue end
+ if backpack[1][x + k - 1] == nil then
+ return false
+ end
+ if backpack[1][x + k - 1][y + i - 1] or backpack[1][x + k - 1][y + i - 1] == nil then
+ return false
+ end
+ end
+ end
+ return true
+end
+
+--Creates a new backpack, this is NOT called when players join the server, even new ones.
+invfuncs.CreateBackpack = function(name,width,height)
+ local backpack = {}
+ backpack[1] = {}
+ backpack[2] = {width,height}
+ backpack[3] = name
+ for i = 1,width do --the width of the backpack.
+ backpack[1][i] = {}
+ end
+ for k,v in pairs(backpack[1]) do
+ for i = 1,height do --the height of the backpack.
+ backpack[1][k][i] = false
+ end
+ end
+ return backpack
+end
+
+--Displays a dropdown of options under the players mouse, if the option is clicked, does the function
+--Requires a table of strings to functions, or strings to tables of strings to functions.
+--Be careful not to make this a recursive table.
+local function createMenuFor(menu, tbl)
+ for k,v in pairs(tbl) do
+ if(isfunction(v)) then --This is a dead-end, add the menu
+ local thisoption = menu:AddOption(k,v)
+ else --Otherwise it should be a table, recursively call to create
+ local submenu = menu:AddSubMenu(k)
+ createMenuFor(submenu,v)
+ end
+ end
+end
+
+--Draws a backpack on the dpanel, client side only
+invfuncs.DrawBackpackOnDPanel = function(dp, backpack, backpacknum, tent)
+ local width = ScrW()
+ local height = ScrH()
+ local slotsize = math.Round(width / 32)
+ local backgrid = vgui.Create( "DGrid", dp )
+ backgrid:SetPos( 10, 30 )
+ backgrid:SetCols( backpack[2][1] )
+ backgrid:SetColWide( backpack[2][2] )
+ backgrid:Dock(FILL)
+ for i = 1,#(backpack[1]) do
+ for j = 1,#(backpack[1][i]) do
+ local item = backpack[1][j][i]
+ if type(backpack[1][j][i]) == "table" then
+ local itemwidth = 0
+ for _,l in pairs(item.Shape) do
+ itemwidth = math.Max(itemwidth,#l)
+ end
+ local itemheight = #item.Shape
+ local invicon = vgui.Create( "DButton", dp )
+ invicon:SetSize(slotsize * itemwidth, slotsize * itemheight)
+ invicon:SetPos(slotsize * (i - 1), slotsize * (j - 1))
+ invicon:SetText(item.Name)
+ if item.Tooltip then
+ invicon:SetTooltip(item.Tooltip)
+ end
+ --invicon.Paint = function(self, w, h) draw.RoundedBox(4, 0,0,w,h,Color(0,100,0)) end
+ invicon.DoClick = function()
+ if not item.GetOptions then return end
+ local menu = vgui.Create("DMenu")
+ createMenuFor(menu,item:GetOptions())
+ menu:Open()
+ end
+ invicon.Item = item
+ invicon.invpos = {j,i}
+ invicon.ent = tent
+ invicon.backpacknum = backpacknum
+ invicon:Droppable("Inventory")
+ elseif not backpack[1][j][i] then
+ local emptyslot = vgui.Create("DPanel", dp)
+ emptyslot:SetSize(slotsize,slotsize)
+ emptyslot:SetPos(slotsize * (i - 1), slotsize * (j - 1))
+ --emptyslot.Paint = function(self, w, h) draw.RoundedBox(4, 0,0,w,h,Color(0,0,100)) end
+ emptyslot:Receiver( "Inventory", function( receiver, tableOfDroppedPanels, isDropped, menuIndex, mouseX, mouseY )
+ if not isDropped then return end
+ local icon = tableOfDroppedPanels[1]
+ local item = icon.Item
+ local curpos = icon.invpos
+ --Set the shape it was at to false
+ if not icon.wasequiped and icon.ent == tent then
+ assert(curpos ~= nil, "print curpos was nil when not equiped")
+ for k = 1,#item.Shape do
+ for l = 1,#(item.Shape[k]) do
+ if k == 1 and l == 1 then continue end
+ backpack[1][curpos[1] + k - 1][curpos[2] + l - 1] = false
+ end
+ end
+ backpack[1][curpos[1]][curpos[2]] = false
+ end
+ if invfuncs.CanFitInBackpack(backpack,j,i,item) then
+ local fromtbl = icon.invpos
+ local wasequiped = icon.wasequiped
+ if wasequiped then
+ net.Start("unequipitem")
+ net.WriteString(wasequiped)
+ net.WriteUInt(backpacknum,16)
+ net.WriteUInt(i,16)
+ net.WriteUInt(j,16)
+ net.SendToServer()
+ else
+ net.Start("moveitem")
+ net.WriteEntity(icon.ent) -- from ent
+ net.WriteEntity(tent) -- to ent
+ net.WriteUInt(icon.backpacknum,16) -- from backpack number
+ net.WriteUInt(backpacknum,16) -- to backpack number
+ net.WriteUInt(fromtbl[1],16) -- From position
+ net.WriteUInt(fromtbl[2],16)
+ net.WriteUInt(j,16) -- To position
+ net.WriteUInt(i,16)
+ net.SendToServer()
+ if item.onEquip ~= nil then
+ item:onEquip(LocalPlayer())
+ end
+ end
+ end
+ end, {} )
+ end
+ end
+ end
+end
+
+return invfuncs
diff --git a/gamemode/shared/itemcommon/common_inventory.lua b/gamemode/shared/itemcommon/common_inventory.lua
new file mode 100644
index 0000000..3f5fb3a
--- /dev/null
+++ b/gamemode/shared/itemcommon/common_inventory.lua
@@ -0,0 +1,9 @@
+--[[
+ Stores some common functions related to inventories
+]]
+local common = {}
+
+--Must have Serialize and Deseralize created before calling.
+function MakeInventoryable(item,shape,width,height,xpos,ypos)
+
+end
diff --git a/gamemode/shared/itemsystem/exampleitem.lua b/gamemode/shared/itemsystem/exampleitem.lua
new file mode 100644
index 0000000..f39a979
--- /dev/null
+++ b/gamemode/shared/itemsystem/exampleitem.lua
@@ -0,0 +1,25 @@
+--[[
+ An example item
+]]
+local item = {}
+
+item.Name = "Test item"
+
+item.Serialize = function(self)
+ print("Trying to serailize!")
+ return ""
+end
+
+item.DeSerialize = function(self,string)
+ print("Trying to deserialize!")
+ return self
+end
+
+item.Shape = {
+ {true},
+ {true},
+ {true},
+}
+
+print("Hello from exampleitem.lua")
+ART.RegisterItem(item)
diff --git a/gamemode/shared/itemsystem/scrapgun.lua b/gamemode/shared/itemsystem/scrapgun.lua
new file mode 100644
index 0000000..bf21b42
--- /dev/null
+++ b/gamemode/shared/itemsystem/scrapgun.lua
@@ -0,0 +1,60 @@
+--[[
+ An example item
+]]
+local item = {}
+
+--Required, a name, all item names must be unique
+item.Name = "Scrap gun"
+
+--Optional, a tooltip to display
+item.Tooltip = "A gun made from bits of scrap"
+
+--Required Returns the data needed to rebuild this item, should only contain the minimum data nessessary since this gets sent over the network
+item.Serialize = function(self)
+ print("Trying to serailize!")
+ return ""
+end
+
+--Required, Rebuilds the item from data created in Serialize, if the item is different from the "main" copy of the item, it should retun a tabl.Copy(self), with the appropriate fields set.
+item.DeSerialize = function(self,string)
+ print("Trying to deserialize!")
+ return self
+end
+
+--Optional, when the player clicks this item, a menu will show up, if the menu item is clicked, the function is ran. This is all run client side, so if you want it to do something, you'll need to use the net library.
+function item.GetOptions(self)
+ local options = {}
+ options["test"] = function() print("You pressed test!") end
+ options["toste"] = function() print("You pressed toste!") end
+ return options
+end
+
+--Required, the shape of this item.
+item.Shape = {
+ {true,true},
+ {true},
+}
+
+--Optional, If this item can be equiped in any player slots, put them here.
+item.Equipable = "Left"
+
+--Optional, what to do when the player clicks, and this item is in the slot in inventory
+item.onClick = function(self,owner)
+ print("pew pew!")
+end
+
+--Optional, if we should do something special on equip(like draw the PAC for this weapon)
+item.onEquip = function(self,who)
+ print("onEquip",who)
+ if CLIENT then print("onEquip client!") end
+ if SERVER then
+ PrintTable(pac)
+ --local outfit = pac.luadata.ReadFile("pac3/mech.txt")
+ --who:AttachPACPart(outfit)
+ --print("onEquip server!")
+ end
+end
+
+print("Hello from scrapgun.lua")
+--Don't forget to register the item!
+ART.RegisterItem(item)
diff --git a/gamemode/shared/loaditems.lua b/gamemode/shared/loaditems.lua
new file mode 100644
index 0000000..18260f2
--- /dev/null
+++ b/gamemode/shared/loaditems.lua
@@ -0,0 +1,55 @@
+--[[
+ This file loads in all the items
+]]
+local concmd = include("concommands.lua")
+--local autolua = include("../autolua.lua")
+print("Hello from LoadItems.lua!")
+ART.Items = {}
+local requiredfields = {
+ "Name",
+}
+local defaultfields = {
+ ["Serialize"] = function(self) return "" end,
+ ["DeSerialize"] = function(self,string) return self end,
+ ["Shape"] = {{true}},
+}
+function ART.RegisterItem(tbl)
+ print("Registering item:" .. tbl.Name)
+ for k,v in pairs(requiredfields) do
+ assert(tbl[v] ~= nil, "Attempted to register an item without field:" .. v)
+ end
+ assert(ART.Items[tbl.Name] == nil, "Attempted to register 2 items with the same name!")
+ for k,v in pairs(defaultfields) do
+ if tbl[k] == nil then
+ tbl[k] = v
+ end
+ end
+ ART.Items[tbl.Name] = tbl
+ print("Art is now:")
+ PrintTable(ART)
+end
+
+--autolua.AddLuaSHFolder("/shared/itemsystem")
+
+function ART.GiveItem(player,name)
+ assert(ART.Items[name] ~= nil, "Attempted to give a nil item!")
+ player:GiveItem(ART.Items[name])
+ player:SynchronizeInventory()
+end
+
+function ART.GetItemByName(name)
+ assert(ART.Items[name] ~= nil,"Attempted to get a nil item:" .. name)
+ return ART.Items[name]
+end
+
+concommand.Add("artery_printitems",function(ply,cmd,args)
+ if not ply:IsAdmin() then return end
+ print("Items table:")
+ PrintTable(ART.Items)
+end)
+
+concommand.Add("artery_giveitem",function(ply,cmd,args)
+ if not ply:IsAdmin() then return end
+ print("Trying to give an item:" .. args[1])
+ ART.GiveItem(ply,args[1])
+end, concmd.AutocompleteFunction(table.GetKeys(ART.Items)), "Give an item to the specified player, or yourself if no player is specified.")
diff --git a/gamemode/shared/lockbox/array.lua b/gamemode/shared/lockbox/array.lua
new file mode 100644
index 0000000..7ae89fc
--- /dev/null
+++ b/gamemode/shared/lockbox/array.lua
@@ -0,0 +1,211 @@
+print("Hello from array.lua!")
+local String = string
+local Bit = include("bit.lua");
+
+local XOR = Bit.bxor;
+
+local Array = {};
+
+Array.size = function(array)
+ return #array;
+end
+
+Array.fromString = function(string)
+ local bytes = {};
+
+ local i=1;
+ local byte = String.byte(string,i);
+ while byte ~= nil do
+ bytes[i] = byte;
+ i = i + 1;
+ byte = String.byte(string,i);
+ end
+
+ return bytes;
+
+end
+
+Array.toString = function(bytes)
+ local chars = {};
+ local i=1;
+
+ local byte = bytes[i];
+ while byte ~= nil do
+ chars[i] = String.char(byte);
+ i = i+1;
+ byte = bytes[i];
+ end
+
+ return table.concat(chars,"");
+end
+
+Array.fromStream = function(stream)
+ local array = {};
+ local i=1;
+
+ local byte = stream();
+ while byte ~= nil do
+ array[i] = byte;
+ i = i+1;
+ byte = stream();
+ end
+
+ return array;
+end
+
+Array.readFromQueue = function(queue,size)
+ local array = {};
+
+ for i=1,size do
+ array[i] = queue.pop();
+ end
+
+ return array;
+end
+
+Array.writeToQueue = function(queue,array)
+ local size = Array.size(array);
+
+ for i=1,size do
+ queue.push(array[i]);
+ end
+end
+
+Array.toStream = function(array)
+ local queue = Queue();
+ local i=1;
+
+ local byte = array[i];
+ while byte ~= nil do
+ queue.push(byte);
+ i=i+1;
+ byte = array[i];
+ end
+
+ return queue.pop;
+end
+
+
+local fromHexTable = {};
+for i=0,255 do
+ fromHexTable[String.format("%02X",i)]=i;
+ fromHexTable[String.format("%02x",i)]=i;
+end
+
+Array.fromHex = function(hex)
+ local array = {};
+
+ for i=1,String.len(hex)/2 do
+ local h = String.sub(hex,i*2-1,i*2);
+ array[i] = fromHexTable[h];
+ end
+
+ return array;
+end
+
+
+local toHexTable = {};
+for i=0,255 do
+ toHexTable[i]=String.format("%02X",i);
+end
+
+Array.toHex = function(array)
+ local hex = {};
+ local i = 1;
+
+ local byte = array[i];
+ while byte ~= nil do
+ hex[i] = toHexTable[byte];
+ i=i+1;
+ byte = array[i];
+ end
+
+ return table.concat(hex,"");
+
+end
+
+Array.concat = function(a,b)
+ local concat = {};
+ local out=1;
+
+ local i=1;
+ local byte = a[i];
+ while byte ~= nil do
+ concat[out] = byte;
+ i = i + 1;
+ out = out + 1;
+ byte = a[i];
+ end
+
+ local i=1;
+ local byte = b[i];
+ while byte ~= nil do
+ concat[out] = byte;
+ i = i + 1;
+ out = out + 1;
+ byte = b[i];
+ end
+
+ return concat;
+end
+
+Array.truncate = function(a,newSize)
+ local x = {};
+
+ for i=1,newSize do
+ x[i]=a[i];
+ end
+
+ return x;
+end
+
+Array.XOR = function(a,b)
+ local x = {};
+
+ for k,v in pairs(a) do
+ x[k] = XOR(v,b[k]);
+ end
+
+ return x;
+end
+
+Array.substitute = function(input,sbox)
+ local out = {};
+
+ for k,v in pairs(input) do
+ out[k] = sbox[v];
+ end
+
+ return out;
+end
+
+Array.permute = function(input,pbox)
+ local out = {};
+
+ for k,v in pairs(pbox) do
+ out[k] = input[v];
+ end
+
+ return out;
+end
+
+Array.copy = function(input)
+ local out = {};
+
+ for k,v in pairs(input) do
+ out[k] = v;
+ end
+ return out;
+end
+
+Array.slice = function(input,start,stop)
+ local out = {};
+
+ for i=start,stop do
+ out[i-start+1] = input[i];
+ end
+ return out;
+end
+
+
+return Array;
diff --git a/gamemode/shared/lockbox/base64.lua b/gamemode/shared/lockbox/base64.lua
new file mode 100644
index 0000000..3d9ffc3
--- /dev/null
+++ b/gamemode/shared/lockbox/base64.lua
@@ -0,0 +1,157 @@
+local String = string
+local Bit = include("bit.lua");
+
+local Array = include("array.lua");
+local Stream = include("stream.lua");
+
+local AND = Bit.band;
+local OR = Bit.bor;
+local NOT = Bit.bnot;
+local XOR = Bit.bxor;
+local LROT = Bit.lrotate;
+local RROT = Bit.rrotate;
+local LSHIFT = Bit.lshift;
+local RSHIFT = Bit.rshift;
+
+
+local SYMBOLS = {
+[0]="A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
+ "Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f",
+ "g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v",
+ "w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/"};
+
+local LOOKUP = {};
+
+for k,v in pairs(SYMBOLS) do
+ LOOKUP[k]=v;
+ LOOKUP[v]=k;
+end
+
+
+local Base64 = {};
+
+Base64.fromStream = function(stream)
+ local bits = 0x00;
+ local bitCount = 0;
+ local base64 = {};
+
+ local byte = stream();
+ while byte ~= nil do
+ bits = OR(LSHIFT(bits,8),byte);
+ bitCount = bitCount + 8;
+ while bitCount >= 6 do
+ bitCount = bitCount - 6;
+ local temp = RSHIFT(bits,bitCount);
+ table.insert(base64,LOOKUP[temp]);
+ bits = AND(bits,NOT(LSHIFT(0xFFFFFFFF,bitCount)));
+ end
+ byte = stream();
+ end
+
+ if (bitCount == 4) then
+ bits = LSHIFT(bits,2);
+ table.insert(base64,LOOKUP[bits]);
+ table.insert(base64,"=");
+ elseif (bitCount == 2) then
+ bits = LSHIFT(bits,4);
+ table.insert(base64,LOOKUP[bits]);
+ table.insert(base64,"==");
+ end
+
+ return table.concat(base64,"");
+end
+
+Base64.fromArray = function(array)
+ local bits = 0x00;
+ local bitCount = 0;
+ local base64 = {};
+
+ local ind = 1;
+
+ local byte = array[ind]; ind = ind + 1;
+ while byte ~= nil do
+ bits = OR(LSHIFT(bits,8),byte);
+ bitCount = bitCount + 8;
+ while bitCount >= 6 do
+ bitCount = bitCount - 6;
+ local temp = RSHIFT(bits,bitCount);
+ table.insert(base64,LOOKUP[temp]);
+ bits = AND(bits,NOT(LSHIFT(0xFFFFFFFF,bitCount)));
+ end
+ byte = array[ind]; ind = ind + 1;
+ end
+
+ if (bitCount == 4) then
+ bits = LSHIFT(bits,2);
+ table.insert(base64,LOOKUP[bits]);
+ table.insert(base64,"=");
+ elseif (bitCount == 2) then
+ bits = LSHIFT(bits,4);
+ table.insert(base64,LOOKUP[bits]);
+ table.insert(base64,"==");
+ end
+
+ return table.concat(base64,"");
+end
+
+Base64.fromString = function(string)
+ return Base64.fromArray(Array.fromString(string));
+end
+
+
+
+Base64.toStream = function(base64)
+ return Stream.fromArray(Base64.toArray(base64));
+end
+
+Base64.toArray = function(base64)
+ local bits = 0x00;
+ local bitCount = 0;
+
+ local bytes = {};
+
+ for c in String.gmatch(base64,".") do
+ if (c == "=") then
+ bits = RSHIFT(bits,2); bitCount = bitCount - 2;
+ else
+ bits = LSHIFT(bits,6); bitCount = bitCount + 6;
+ bits = OR(bits,LOOKUP[c]);
+ end
+
+ while(bitCount >= 8) do
+ bitCount = bitCount - 8;
+ local temp = RSHIFT(bits,bitCount);
+ table.insert(bytes,temp);
+ bits = AND(bits,NOT(LSHIFT(0xFFFFFFFF,bitCount)));
+ end
+ end
+
+ return bytes;
+end
+
+Base64.toString = function(base64)
+ local bits = 0x00;
+ local bitCount = 0;
+
+ local chars = {};
+
+ for c in String.gmatch(base64,".") do
+ if (c == "=") then
+ bits = RSHIFT(bits,2); bitCount = bitCount - 2;
+ else
+ bits = LSHIFT(bits,6); bitCount = bitCount + 6;
+ bits = OR(bits,LOOKUP[c]);
+ end
+
+ while(bitCount >= 8) do
+ bitCount = bitCount - 8;
+ local temp = RSHIFT(bits,bitCount);
+ table.insert(chars,String.char(temp));
+ bits = AND(bits,NOT(LSHIFT(0xFFFFFFFF,bitCount)));
+ end
+ end
+
+ return table.concat(chars,"");
+end
+
+return Base64;
diff --git a/gamemode/shared/lockbox/bit.lua b/gamemode/shared/lockbox/bit.lua
new file mode 100644
index 0000000..0ccdb82
--- /dev/null
+++ b/gamemode/shared/lockbox/bit.lua
@@ -0,0 +1,11 @@
+local e = bit
+
+-- Workaround to support Lua 5.2 bit32 API with the LuaJIT bit one
+if e.rol and not e.lrotate then
+ e.lrotate = e.rol
+end
+if e.ror and not e.rrotate then
+ e.rrotate = e.ror
+end
+
+return bit
diff --git a/gamemode/shared/lockbox/ecb.lua b/gamemode/shared/lockbox/ecb.lua
new file mode 100644
index 0000000..67f4514
--- /dev/null
+++ b/gamemode/shared/lockbox/ecb.lua
@@ -0,0 +1,191 @@
+local Array = include("array.lua");
+local Stream = include("stream.lua");
+local Queue = include("queue.lua");
+
+local Bit = include("bit.lua");
+
+local CBC = {};
+
+CBC.Cipher = function()
+
+ local public = {};
+
+ local key;
+ local blockCipher;
+ local padding;
+ local inputQueue;
+ local outputQueue;
+ local iv;
+
+ public.setKey = function(keyBytes)
+ print("Set key to:")
+ print(keyBytes)
+ key = keyBytes;
+ return public;
+ end
+
+ public.setBlockCipher = function(cipher)
+ blockCipher = cipher;
+ return public;
+ end
+
+ public.setPadding = function(paddingMode)
+ padding = paddingMode;
+ return public;
+ end
+
+ public.init = function()
+ inputQueue = Queue();
+ outputQueue = Queue();
+ iv = nil;
+ return public;
+ end
+
+ public.update = function(messageStream)
+ print("Entering update")
+ local byte = messageStream();
+ while (byte ~= nil) do
+ print("processing byte")
+ inputQueue.push(byte);
+ print("inputQueue.size is:" .. inputQueue.size())
+ print("blockCipher.blockSize:" .. blockCipher.blockSize)
+ if(inputQueue.size() >= blockCipher.blockSize) then
+ print("reading from queue")
+ local block = Array.readFromQueue(inputQueue,blockCipher.blockSize);
+ if(iv == nil) then
+ print("iv was nil, iv is now")
+ iv = block;
+ PrintTable(block)
+ else
+ print("iv was not nil, doing thing")
+ local out = Array.XOR(iv,block);
+ print("Calling encrypt with key:")
+ print(key)
+ print("and out")
+ print(out)
+ out = blockCipher.encrypt(key,out);
+ print("Out was:")
+ print(out)
+ Array.writeToQueue(outputQueue,out);
+ iv = out;
+ end
+ end
+ byte = messageStream();
+ end
+ print("Before update returned, blockCipher was ")
+ PrintTable(blockCipher)
+ return public;
+ end
+
+ public.finish = function()
+ paddingStream = padding(blockCipher.blockSize,inputQueue.getHead());
+ public.update(paddingStream);
+
+ return public;
+ end
+
+ public.getOutputQueue = function()
+ return outputQueue;
+ end
+
+ public.asHex = function()
+ print("Outputqueue is:")
+ PrintTable(outputQueue)
+ return Stream.toHex(outputQueue.pop);
+ end
+
+ public.asBytes = function()
+ return Stream.toArray(outputQueue.pop);
+ end
+
+ return public;
+
+end
+
+
+CBC.Decipher = function()
+
+ local public = {};
+
+ local key;
+ local blockCipher;
+ local padding;
+ local inputQueue;
+ local outputQueue;
+ local iv;
+
+ public.setKey = function(keyBytes)
+ key = keyBytes;
+ return public;
+ end
+
+ public.setBlockCipher = function(cipher)
+ blockCipher = cipher;
+ return public;
+ end
+
+ public.setPadding = function(paddingMode)
+ padding = paddingMode;
+ return public;
+ end
+
+ public.init = function()
+ inputQueue = Queue();
+ outputQueue = Queue();
+ iv = nil;
+ return public;
+ end
+
+ public.update = function(messageStream)
+ print("Updateing decipher with messagestream")
+ local byte = messageStream();
+ while (byte ~= nil) do
+ inputQueue.push(byte);
+ if(inputQueue.size() >= blockCipher.blockSize) then
+ local block = Array.readFromQueue(inputQueue,blockCipher.blockSize);
+
+ if(iv == nil) then
+ iv = block;
+ print("Setting iv to ")
+ PrintTable(iv)
+ else
+ local out = block;
+ out = blockCipher.decrypt(key,out);
+ out = Array.XOR(iv,out);
+ Array.writeToQueue(outputQueue,out);
+ iv = block;
+ end
+ end
+ byte = messageStream();
+ end
+ return public;
+ end
+
+ public.finish = function()
+ paddingStream = padding(blockCipher.blockSize,inputQueue.getHead());
+ public.update(paddingStream);
+
+ return public;
+ end
+
+ public.getOutputQueue = function()
+ return outputQueue;
+ end
+
+ public.asHex = function()
+ return Stream.toHex(outputQueue.pop);
+ end
+
+ public.asBytes = function()
+ return Stream.toArray(outputQueue.pop);
+ end
+
+ public.asString = function()
+ return Stream.toString(outputQueue.pop)
+ end
+
+ return public;
+
+end
+
+return CBC;
diff --git a/gamemode/shared/lockbox/padding.lua b/gamemode/shared/lockbox/padding.lua
new file mode 100644
index 0000000..72be077
--- /dev/null
+++ b/gamemode/shared/lockbox/padding.lua
@@ -0,0 +1,21 @@
+local Stream = include("stream.lua");
+
+local ZeroPadding = function(blockSize,byteCount)
+
+ local paddingCount = blockSize - ((byteCount -1) % blockSize) + 1;
+ local bytesLeft = paddingCount;
+
+ local stream = function()
+ if bytesLeft > 0 then
+ bytesLeft = bytesLeft - 1;
+ return 0x00;
+ else
+ return nil;
+ end
+ end
+
+ return stream;
+
+end
+
+return ZeroPadding;
diff --git a/gamemode/shared/lockbox/queue.lua b/gamemode/shared/lockbox/queue.lua
new file mode 100644
index 0000000..55b067d
--- /dev/null
+++ b/gamemode/shared/lockbox/queue.lua
@@ -0,0 +1,47 @@
+local Queue = function()
+ local queue = {};
+ local tail = 0;
+ local head = 0;
+
+ local public = {};
+
+ public.push = function(obj)
+ queue[head] = obj;
+ head = head + 1;
+ return;
+ end
+
+ public.pop = function()
+ if tail < head
+ then
+ local obj = queue[tail];
+ queue[tail] = nil;
+ tail = tail + 1;
+ return obj;
+ else
+ return nil;
+ end
+ end
+
+ public.size = function()
+ return head - tail;
+ end
+
+ public.getHead = function()
+ return head;
+ end
+
+ public.getTail = function()
+ return tail;
+ end
+
+ public.reset = function()
+ queue = {};
+ head = 0;
+ tail = 0;
+ end
+
+ return public;
+end
+
+return Queue;
diff --git a/gamemode/shared/lockbox/stream.lua b/gamemode/shared/lockbox/stream.lua
new file mode 100644
index 0000000..aeb3b18
--- /dev/null
+++ b/gamemode/shared/lockbox/stream.lua
@@ -0,0 +1,112 @@
+local Queue = include("queue.lua");
+local String = string
+
+local Stream = {};
+
+
+Stream.fromString = function(string)
+ local i=0;
+ return function()
+ print("string is:" .. string)
+ print("len is:" .. string.len(string))
+ print("i is:" .. i)
+ i=i+1;
+ if(i <= string.len(string)) then
+ return string.byte(string,i);
+ else
+ return nil;
+ end
+ end
+end
+
+
+Stream.toString = function(stream)
+ local array = {};
+ local i=1;
+
+ local byte = stream();
+ while byte ~= nil do
+ array[i] = String.char(byte);
+ i = i+1;
+ byte = stream();
+ end
+
+ return table.concat(array,"");
+end
+
+
+Stream.fromArray = function(array)
+ local queue = Queue();
+ local i=1;
+
+ local byte = array[i];
+ while byte ~= nil do
+ queue.push(byte);
+ i=i+1;
+ byte = array[i];
+ end
+
+ return queue.pop;
+end
+
+
+Stream.toArray = function(stream)
+ local array = {};
+ local i=1;
+
+ local byte = stream();
+ while byte ~= nil do
+ array[i] = byte;
+ i = i+1;
+ byte = stream();
+ end
+
+ return array;
+end
+
+
+local fromHexTable = {};
+for i=0,255 do
+ fromHexTable[String.format("%02X",i)]=i;
+ fromHexTable[String.format("%02x",i)]=i;
+end
+
+Stream.fromHex = function(hex)
+ local queue = Queue();
+
+ for i=1,String.len(hex)/2 do
+ local h = String.sub(hex,i*2-1,i*2);
+ queue.push(fromHexTable[h]);
+ end
+
+ return queue.pop;
+end
+
+
+
+local toHexTable = {};
+for i=0,255 do
+ toHexTable[i]=String.format("%02X",i);
+end
+
+Stream.toHex = function(stream)
+ print("tohex called with stream")
+ print(stream)
+ local hex = {};
+ local i = 1;
+
+ local byte = stream();
+ print("First byte is")
+ print(byte)
+ while byte ~= nil do
+ print("Createing hex:")
+ print(table.concat(hex,""))
+ hex[i] = toHexTable[byte];
+ i=i+1;
+ byte = stream();
+ end
+
+ return table.concat(hex,"");
+end
+
+return Stream;
diff --git a/gamemode/shared/sh_setup.lua b/gamemode/shared/sh_setup.lua
new file mode 100644
index 0000000..9c44e57
--- /dev/null
+++ b/gamemode/shared/sh_setup.lua
@@ -0,0 +1,165 @@
+--[[
+ Some values that need to be setup by the server owner
+]]
+
+local aes = include("aes.lua")
+local ECBMode = include("lockbox/ecb.lua")
+local ZeroPadding = include("lockbox/padding.lua")
+local Array = include("lockbox/array.lua")
+local Stream = include("lockbox/stream.lua")
+print("sh_setup included aes successfully")
+
+local valuesneeded = {
+ ["mysql DB host"] = "String",
+ ["mysql DB dbname"] = "String",
+ ["mysql DB uname"] = "String",
+ ["mysql DB pass"] = "String",
+ ["mysql should encrypt pass"] = "Bool",
+ ["mysql encrypt password"] = "String",
+ ["world default server ip:port"] = "String",
+}
+
+ART.Config = ART.Config or {}
+
+if SERVER then
+ util.AddNetworkString( "ART_CONFIG_WRITE" )
+ local function ReadConfig(encryptkey)
+ encryptkey = encryptkey or ""
+ local ftext = file.Read("artery/config.txt", "DATA")
+ if ftext == nil then
+ print("Failed to read Config file, if this is a new setup, use art_setup to get started.")
+ return
+ end
+ local tbl = string.Explode("\n",ftext,false)
+ local strtbl = {}
+ for k,v in pairs(tbl) do
+ local ltext = v:Explode(":",false)
+ strtbl[ltext[1]] = ltext[2]
+ end
+ for k,v in pairs(valuesneeded) do
+ local tfunc = "to" .. v:lower()
+ ART.Config[k] = _G[tfunc](strtbl[k])
+ end
+ if ART.Config["mysql should encrypt pass"] then
+ if encryptkey == "" then
+ print("Failed to retrive MySQL database password, please enter it with the \"artery_dbpasswordkey\" command.")
+ return
+ end
+ ART.Config["mysql DB pass"] = aes.decrypt(lockstream.fromString(encryptkey),lockstream.fromString(ART.Config["mysql DB pass"]))
+ end
+ end
+
+ ReadConfig()
+
+ net.Receive( "ART_CONFIG_MYSQLPASS", function(len,ply)
+ if not ply:IsAdmin() then
+ return
+ end
+ end)
+
+ net.Receive( "ART_CONFIG_WRITE", function(len,ply)
+ print("Received write signal")
+ if not ply:IsAdmin() then return end
+ print("You're an admin!")
+ for k,v in pairs(valuesneeded) do
+ local ftype = "Read" .. v
+ ART.Config[k] = net[ftype]()
+ end
+ if ART.Config["mysql should encrypt pass"] then
+ local key = ART.Config["mysql encrypt password"]
+ local block = ART.Config["mysql DB pass"]
+ local akey = Array.fromString(key)
+ local ablock = Array.fromString(block)
+ local skey = Stream.fromString(key)
+ local sblock = Stream.fromString(block)
+ --print("sblock:" .. sblock)
+ --print("skey:" .. skey)
+ local cipher = ECBMode.Cipher().setKey(akey).setBlockCipher(aes).setPadding(ZeroPadding)
+ local ciphertxt = cipher.init().update(sblock).finish().asHex()
+ local decipher = ECBMode.Decipher().setKey(akey).setBlockCipher(aes).setPadding(ZeroPadding)
+ local deciphertxt = decipher.init().update(Stream.fromHex(ciphertxt)).finish().asHex()
+ print("Cyphertext of " .. block .. " is " .. ciphertxt)
+ print("Deciphertext of " .. ciphertxt .. " is " .. deciphertxt)
+ ART.Config["mysql DB pass"] = ciphertxt
+ end
+ local ftext = {}
+ for k,v in pairs(ART.Config) do
+ ftext[#ftext + 1] = k .. "=" .. tostring(v)
+ end
+ local wtext = table.concat(ftext,"\n")
+ print("Writeing:" .. wtext)
+ file.Write("artery/config.txt",wtext)
+ end)
+
+ net.Receive( "ART_CONFIG_REQUEST", function(len,ply)
+ if not ply:IsAdmin() then return end
+ for k,v in pairs(valuesneeded) do
+ local ftype = "Write" .. v
+ print("Calling " .. ftype .. " on " .. tostring(tbl[k]))
+ net[ftype](tbl[k])
+ end
+ end)
+end
+
+print("Got to before concommands were added")
+
+concommand.Add("artery_dbpasswordkey",function()
+ if CLIENT then return end
+
+end, nil, "Sets the encryption key for the mysql database password")
+
+if CLIENT then
+ print("Got to before setup command")
+
+ concommand.Add("artery_setup", function(ply,cmd,args)
+ print("setup called")
+ if SERVER then return end
+ print("Got past server gaurd")
+ local width = ScrW()
+ local height = ScrH()
+ local configpanel = vgui.Create( "DFrame" )
+ configpanel:SetPos( 0, height/8 )
+ configpanel:SetSize( width/4, (height/4)*3 )
+ configpanel:SetTitle( "Artery Settings" )
+ configpanel:SetDraggable( true )
+ configpanel:MakePopup()
+ local scrollpanel = vgui.Create( "DScrollPanel", configpanel )
+ scrollpanel:Dock(FILL)
+ local entries = {}
+ for k,v in pairs(valuesneeded) do
+ local settinglabel = vgui.Create( "DLabel", scrollpanel )
+ settinglabel:Dock(TOP)
+ settinglabel:SetText( k )
+ scrollpanel:AddItem(settinglabel)
+ local settingentry
+ if v == "String" then
+ settingentry = vgui.Create( "DTextEntry", scrollpanel )
+ settingentry:SetSize(width/10,18)
+ settingentry:Dock(TOP)
+ elseif v == "Bool" then
+ settingentry = vgui.Create( "DCheckBox", holder)
+ settingentry:Dock(TOP)
+ --settingentry:SetSize(18,18)
+ end
+ scrollpanel:AddItem(settingentry)
+ entries[k] = settingentry
+ end
+ local savebutton = vgui.Create( "DButton",scrollpanel )
+ savebutton.DoClick = function()
+ net.Start( "ART_CONFIG_WRITE")
+ for k,v in pairs(valuesneeded) do
+ local nfunc = "Write"..v
+ local value = nil
+ if v == "String" then value = entries[k]:GetValue()
+ elseif v == "Bool" then value = entries[k]:GetChecked() end
+ assert(value ~= nil, "Didn't know setting type:" .. v .. " for " .. k)
+ print("Doing " .. nfunc .. " on " .. tostring(value))
+ net[nfunc](value)
+ end
+ net.SendToServer()
+ end
+ savebutton:SetText("Save config")
+ savebutton:Dock(TOP)
+ scrollpanel:AddItem(savebutton)
+ end)
+end
diff --git a/gamemode/shared/sparkel.lua b/gamemode/shared/sparkel.lua
new file mode 100644
index 0000000..5882aac
--- /dev/null
+++ b/gamemode/shared/sparkel.lua
@@ -0,0 +1,17 @@
+
+function sparkel(...)
+ local arg = {...}
+ local looparg = type(arg[1]) == "string" and string.Explode(" ",arg[1],false) or arg
+ --One pass to find the high and low point
+ local max,min = tonumber(looparg[1]),tonumber(looparg[1])
+ for k,v in pairs(looparg) do
+ v = tonumber(v)
+ max = max > v and max or v
+ min = min < v and min or v
+ end
+ local scale = (max-min)/7
+ for k,v in pairs(looparg) do
+ Msg(utf8.char(9600+(1+(v/scale))))
+ end
+ Msg("\n")
+end