summaryrefslogtreecommitdiff
path: root/vq3srv
blob: 0b4f149923138fa67470bb8ca09b530c4ca24863 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python3
from argparse import ArgumentParser
from os import system
from random import shuffle
from sys import exit

# TODO: move this shit to a yaml config somewhere in /etc
USER = 'quake3' # linux user, for sudo -u
BIN = '/usr/bin/q3ded'
CONF = '/srv/q3/.q3a/baseq3/autoexec.cfg'
PARAM = '+exec autoexec.cfg'

MAPLISTS = {
    'ffa': [
        'q3dm2', 'q3dm3', 'q3dm4', 'q3dm5', 'q3dm6',
        'q3dm7', 'q3dm8', 'q3dm9', 'q3dm10', 'q3dm11'
    ],
    'duel': [
        'q3dm1', 'q3dm2', 'pro-q3dm6', 'pro-q3dm13',
        'q3tourney1', 'q3tourney3', 'q3tourney5', 'q3tourney6',
        'pro-q3tourney2', 'pro-q3tourney4'
    ],
    'ctf': list()
}
BOTS = {
    'level': '3',
    'names': [
        'Anarki', 'Angel', 'Crash', 'Doom', 'Hunter',
        'Klesk', 'Major', 'Mynx', 'Orbb', 'Slash', 'Xaero'
    ]
}


# these are saved to the q3config_server.cfg on the first run
# no point in keeping them here afterwards
BOOTSTRAP_OPTS = dict()
# BOOTSTRAP_OPTS = {
#     'sv_pure': '0', # enable client side mods, like better fonts or graphics
#     'sv_maxclients': '8',
#     'sv_hostname': 'myhost.tld'
#
#     # this will let your server send maps to clients
#     # the downloads are attempted from http://%sv_dlURL%/baseq3/mapname.pk3
#     # note the protocol - no support for https,
#     # as well as the need to have baseq3 as a part of the path
#     # note that clients have to seta cl_allowDownload 1 for that to work
#     'sv_dlURL': 'anyhost.tld/q3',
#     'sv_allowDownloads': '1'
# }


def parse_arguments():
    desc = 'host a q3 server'
    parser = ArgumentParser(description=desc)
    parser.add_argument('-m', '--gamemode', default='ffa')
    parser.add_argument('-f', '--fraglimit', type=int, default=15)
    parser.add_argument('-t', '--timelimit', type=int, default=10)
    parser.add_argument('-b', '--bots', type=int, default=0)
    return parser.parse_args()


def gen_confline(param, value):
    return 'seta {} "{}"\n'.format(param, value)


def gen_maplist(maplist):
    shuffle(maplist)
    num = 1
    stmpl = 'set d{} "map {} ; set nextmap vstr d{}"\n'
    script = str()
    while maplist:
        nextnum = 1 if len(maplist) == 1 else num + 1
        script += stmpl.format(num, maplist.pop(), nextnum)
        num += 1
    script += 'vstr d1\n'
    return script


def gen_addbots(count, level='3', names=list()):
    shuffle(names)
    btmpl = 'addbot {} {}\n'
    script = str()
    for bot in names[:count]:
        script += btmpl.format(bot, level)
    return script


def main():
    args = parse_arguments()
    cfg_data = str()
    try:
        assert args.gamemode in MAPLISTS
    except AssertionError:
        exit('Wrong game mode specified!')

    for param in BOOTSTRAP_OPTS:
        cfg_data += gen_confline(param, BOOTSTRAP_OPTS[param])
    cfg_data += gen_confline('fraglimit', args.fraglimit)
    cfg_data += gen_confline('timelimit', args.timelimit)
    # this should be last since it launches the actual maplist
    cfg_data += gen_maplist(MAPLISTS[args.gamemode])
    if args.bots:
        cfg_data += gen_addbots(args.bots, **BOTS)

    with open(CONF, 'w+') as config:
        config.write(cfg_data)
    system('sudo -u {} {} {}'.format(USER, BIN, PARAM))


if __name__ == '__main__':
    main()