1
0
mirror of https://github.com/citizenfx/cfx-server-data.git synced 2025-01-24 10:12:54 +08:00
This commit is contained in:
guava 2016-12-15 13:40:07 +01:00
commit ee4dd89693
95 changed files with 7368 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
CitizenMP.Server.exe
CitizenMP.Server.exe.config
NLog.config
/cache/

3
bin/README.txt Normal file
View File

@ -0,0 +1,3 @@
CitizenMP.Server.exe in bin/ is no longer use.
Please run the executable from the root directory.

40
citmp-server.yml Normal file
View File

@ -0,0 +1,40 @@
ListenPort: 30120
PreParseResources:
- mapmanager
AutoStartResources:
- chat
- spawnmanager
- fivem-map-skater
- baseevents
- rconlog
- hardcap # prevents too many players from joining
- scoreboard
# do change
RconPassword: lovely
# configure this, please
Hostname: default FiveReborn server
# don't change this, it'll cause your server to be unlisted
Game: GTA5
PlatformServer: updater.fivereborn.com
ScriptDebug: true
DebugLog: true
# set to false to hide from the online server list
Announce: true
# set to false to require players to be signed in to Steam
DisableAuth: true
# set to true to disable local script hook plugins
DisableScriptHook: false
# set to the path of an icon to use in the server browser. it should be square.
#ServerIcon: hello.png

BIN
hello.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
libuv.dll Normal file

Binary file not shown.

BIN
libuv.so Normal file

Binary file not shown.

BIN
mono/libSystem.Native.so Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
resource_type 'map' { gameTypes = { race = true } }
map 'map.lua'

View File

@ -0,0 +1,31 @@
spawnpoint 'ig_brucie' { 1127.99, -569.018, 12.5918, heading = 270 }
spawnpoint 'ig_brucie' { 1122.99, -569.018, 12.5918, heading = 270 }
spawnpoint 'ig_brucie' { 1119.99, -569.018, 12.5918, heading = 270 }
spawnpoint 'ig_brucie' { 1116.99, -569.018, 12.5918, heading = 270 }
checkpoint { pos = { 1175.38, -568.361, 12.9386 } }
checkpoint { pos = { 1192.41, -484.373, 12.9902 } }
checkpoint { pos = { 1370.24, -454.326, 16.1487 } }
checkpoint { pos = { 1380.32, -319.673, 19.2937 } }
checkpoint { pos = { 1153.19, -334.017, 17.6384 } }
--[[checkpoint { pos = { 1120.66, -272.068, 19.6985 } }
checkpoint { pos = { 1014.76, -270.757, 20.9716 } }
checkpoint { pos = { 1018.3, -367.436, 18.9644 } }
checkpoint { pos = { 634.072, -400.678, 40.1211 } }
checkpoint { pos = { 218.425, -400.586, 14.506 } }
checkpoint { pos = { 27.9617, -408.632, 13.7693 } }
checkpoint { pos = { -0.9286, -625.767, 13.7056 } }
checkpoint { pos = { -114.801, -646.633, 13.8117 } }
checkpoint { pos = { -123.565, -785.028, 4.2556 } }
checkpoint { pos = { 114.514, -730.95, 4.0023 } }
checkpoint { pos = { 267.888, -668.781, 4.0181 } }
checkpoint { pos = { 337.305, -509.17, 3.7381 } }
checkpoint { pos = { 309.906, -407.719, 4.0468 } }
checkpoint { pos = { 296.932, -253.16, 3.9989 } }
checkpoint { pos = { 157.697, -234.079, 13.8108 } }
checkpoint { pos = { 140.173, -389.505, 13.7984 } }
checkpoint { pos = { 340.356, -415.681, 31.418 } }
checkpoint { pos = { 566.093, -415.848, 39.5434 } }
checkpoint { pos = { 909.641, -422.129, 36.4247 } }
checkpoint { pos = { 1049.37, -416.408, 17.3975 } }
checkpoint { pos = { 1091.72, -553.691, 12.5552 } }]]

View File

@ -0,0 +1,9 @@
resource_type 'gametype' { name = 'Race' }
dependencies {
"spawnmanager",
"mapmanager"
}
client_script 'race_client.lua'
server_script 'race_server.lua'

View File

@ -0,0 +1,469 @@
local curCheckpoint, nextCheckpoint
local goGoGo
local playerCar
local weFinished
local resultsShown
local checkpoints = {}
local playerScores = {}
local function initializeMap()
echo("[RACE] initializeMap\n")
TriggerServerEvent('race:updateCheckpoints', checkpoints)
end
local function resetGameMode()
curCheckpoint = nil
nextCheckpoint = nil
SetMultiplayerHudTime('')
checkpointCount = 0
playerScores = {}
if IsThisMachineTheServer() then
-- load the initial map
initializeMap()
end
goGoGo = false
weFinished = false
resultsShown = false
end
local function updatePositions()
local players = {}
for id, data in pairs(playerScores) do
data.playerId = id
table.insert(players, data)
end
table.sort(players, function(a, b)
if a.finishPosition or b.finishPosition then
if not b.finishPosition then
return true
end
if not a.finishPosition then
return false
end
return a.finishPosition < b.finishPosition
end
if a.cp == b.cp then
local aPed = a.ped
local bPed = b.ped
local aPos
local bPos
if not DoesCharExist(aPed) or not DoesCharExist(bPed) then
aPos = { 0, 0 }
bPos = { 0, 0 }
else
aPos = a.ped.position
bPos = b.ped.position
end
local nextCp = checkpoints[a.cp + 1]
if not nextCp then
return a.cp > b.cp
end
local aDist = GetDistanceBetweenCoords2d(aPos[1], aPos[2], nextCp.pos[1], nextCp.pos[2])
local bDist = GetDistanceBetweenCoords2d(bPos[1], bPos[2], nextCp.pos[1], nextCp.pos[2])
return aDist < bDist
end
return a.cp > b.cp
end)
if not playerScores[GetPlayerId().serverId] then
return
end
local lastPosition = selfLastPosition
local i = 1
for _, v in ipairs(players) do
playerScores[v.playerId].position = i
i = i + 1
end
local selfPosition = playerScores[GetPlayerId().serverId].position
selfLastPosition = selfPosition
if selfPosition ~= lastPosition then
TriggerEvent('chatMessage', '', { 0, 0, 0 }, 'position changed to ' .. tostring(selfPosition) .. ' from ' .. tostring(lastPosition))
end
-- positions updated, we hope
end
AddEventHandler('race:onPlayerFinished', function(player, data)
local selfId = GetPlayerId().serverId
if not playerScores[player] then
local ped = sPlayer.ped
playerScores[player] = {
cp = #checkpoints,
ped = ped,
vehicle = ped.vehicle
}
end
playerScores[player].finishPosition = data.position
if selfId == player then
exports.obituary:printObituary('New world record!')
TriggerEvent('chatMessage', '', { 0, 0, 0 }, 'you finished!')
weFinished = true
tearDownCheckpoint(curCheckpoint)
tearDownCheckpoint(nextCheckpoint)
-- todo: spectate?
CreateThread(function()
Wait(500)
if playerCar then
FreezeCarPosition(playerCar, true)
end
end)
end
local sPlayer = GetPlayerByServerId(player)
if sPlayer then
exports.obituary:printObituary('<b>%s</b> finished in %s seconds', sPlayer.name, tostring(data.finishSeconds))
end
end)
AddEventHandler('onClientGameTypeStart', function()
CreateThread(function()
--[[while true do
Wait(500)
local player = GetPlayerId()
TriggerServerEvent('race:updatePos', player.ped.position)
end]]
end)
CreateThread(function()
while true do
Wait(250)
updatePositions()
end
end)
end)
function GetPlayerInteger(i)
local serverId = i.serverId
local players = GetPlayers()
for k, v in ipairs(players) do
if v.serverId == serverId then
return k
end
end
return 1
end
local function spawnVehicle(spawnPoint)
local carModel
if not spawnPoint.carModel then
carModel = 'admiral'
else
carModel = spawnPoint.carModel
end
if not tonumber(carModel) then
carModel = GetHashKey(carModel, _r)
end
-- is the model actually a model?
if not IsModelInCdimage(carModel) then
error("invalid spawn model")
end
-- is is even a vehicle?
if not IsThisModelAVehicle(carModel) then
error("this model ain't a vehicle!")
end
-- spawn a vehicle for our lovely player
RequestModel(carModel)
LoadAllObjectsNow()
playerCar = CreateCar(carModel, spawnPoint.x, spawnPoint.y, spawnPoint.z, 0, 1)
SetCarHeading(playerCar, spawnPoint.heading)
SetCarOnGroundProperly(playerCar)
WarpCharIntoCar(GetPlayerId().ped, playerCar)
if not goGoGo then
FreezeCarPosition(playerCar, true)
end
LockCarDoors(playerCar, 4)
-- and done, hopefully.
end
AddEventHandler('race:itsGoTime', function()
if playerCar then
-- let go of the brakes
FreezeCarPosition(playerCar, false)
end
-- gogogo
goGoGo = true
end)
string.lpad = function(str, len, char)
if char == nil then char = ' ' end
return string.rep(char, len - #str) .. str
end
AddEventHandler('race:results', function(time)
if playerCar then
FreezeCarPosition(playerCar, true)
end
tearDownCheckpoint(curCheckpoint)
tearDownCheckpoint(nextCheckpoint)
SetMultiplayerHudTime('')
updatePositions()
local players = {}
for id, data in pairs(playerScores) do
table.insert(players, data)
end
table.sort(players, function(a, b) return a.position < b.position end)
TriggerEvent('chatMessage', '', { 0, 0, 0 }, 'RESULTS')
for i, p in ipairs(players) do
local name = '**INVALID**'
local sp = GetPlayerByServerId(p.playerId)
if sp then
name = sp.name
end
TriggerEvent('chatMessage', '', { 0, 0, 0 }, tostring(i) .. '. ' .. name)
end
end)
AddEventHandler('race:hurryUp', function(time)
CreateThread(function()
echo("resultsShown: " .. tostring(resultsShown) .. " , weF: " .. tostring(weFinished) .. "\n")
while not resultsShown and not weFinished do
Wait(1000)
time = time - 1000
SetMultiplayerHudTime('00:' .. tostring(math.floor(time / 1000)):lpad(2, '0'))
echo(tostring(math.floor(time / 1000)):lpad(2, '0') .. ':' .. tostring(math.floor((time % 1000) / 100)):lpad(2, '0') .. "\n")
end
end)
end)
AddEventHandler('race:showGoMessage', function(message)
TriggerEvent('chatMessage', '', { 0, 0, 0 }, message)
end)
AddEventHandler('onClientMapStart', function(res)
resetGameMode()
requestedGo = true
TriggerServerEvent('race:requestGo')
end)
AddEventHandler('onClientMapStop', function(res)
DoScreenFadeOut(50)
end)
AddEventHandler('race:weGotPorn', function()
echo("[RACE] race:weGotPorn\n")
if not requestedGo then
return
end
requestedGo = false
exports.spawnmanager:setAutoSpawn(false)
exports.spawnmanager:spawnPlayer(GetPlayerInteger(GetPlayerId()), function(spawnPoint)
spawnVehicle(spawnPoint)
end)
TriggerServerEvent('race:requestCheckpoint', '1234')
end)
local function setUpCheckpoint(cp, next)
local nextPos, typeNum
if next then
nextPos = next.pos
typeNum = 2
else
nextPos = { 0.0, 0.0, 0.0 }
typeNum = 3
end
-- 2 = regular 'ground', 3 = finish 'ground', others are different 3dmarker types
cp.handle = CreateCheckpoint(typeNum, cp.pos[1], cp.pos[2], cp.pos[3] + 2.5, nextPos[1], nextPos[2], nextPos[3], 1.0001, _r)
cp.blip = AddBlipForCoord(cp.pos[1], cp.pos[2], cp.pos[3], _i)
if cp == nextCheckpoint then
ChangeBlipScale(cp.blip, 0.8)
end
ChangeBlipSprite(cp.blip, 3)
end
function tearDownCheckpoint(cp)
if not cp then
return
end
if cp.blip then
RemoveBlip(cp.blip)
cp.blip = nil
end
if cp.handle then
DeleteCheckpoint(cp.handle)
cp.handle = nil
end
end
AddEventHandler('race:setCheckpoint', function(cur, next, later)
if curCheckpoint then
tearDownCheckpoint(curCheckpoint)
end
if nextCheckpoint then
tearDownCheckpoint(nextCheckpoint)
end
curCheckpoint = cur
nextCheckpoint = next
if cur then
setUpCheckpoint(curCheckpoint, nextCheckpoint)
-- make a background thread waiting for the checkpoint to be reached
CreateThread(function()
local localCur = curCheckpoint
-- so we exit if the checkpoint target is changed
while curCheckpoint == localCur do
Wait(25)
if playerCar then
local px, py, pz = GetCarCoordinates(playerCar)
local distance = GetDistanceBetweenCoords2d(px, py, localCur.pos[1], localCur.pos[2])
if distance < 10 then
-- pass the fact we reached the checkpoint to the server
TriggerServerEvent('race:gotCP', '1234')
break
end
end
end
end)
end
if next then
setUpCheckpoint(nextCheckpoint, later)
end
end)
AddEventHandler('race:confirmCP', function()
PlayAudioEvent('FRONTEND_GAME_PICKUP_CHECKPOINT')
end)
AddEventHandler('race:updateStatus', function(player, curCP)
if curCP == -1 then
playerScores[player] = nil
end
local sPlayer = GetPlayerByServerId(player)
if not sPlayer then
return
end
local ped = sPlayer.ped
playerScores[player] = {
cp = curCP,
ped = ped,
vehicle = ped.vehicle
}
TriggerEvent('chatMessage', '', { 0, 0, 0 }, sPlayer.name .. ' now has cp ' .. curCP)
updatePositions()
end)
AddEventHandler('onClientMapStop', function()
if playerCar then
MarkCarAsNoLongerNeeded(playerCar)
playerCar = nil
end
if curCheckpoint and curCheckpoint.handle then
DeleteCheckpoint(curCheckpoint.handle)
end
if nextCheckpoint and nextCheckpoint.handle then
DeleteCheckpoint(nextCheckpoint.handle)
end
end)
AddEventHandler('getMapDirectives', function(add)
-- call the remote callback
add('checkpoint', function(state, data)
table.insert(checkpoints, data)
state.add('pos', data.pos)
-- delete callback follows on the next line
end, function(state, arg)
for i, sp in ipairs(checkpoints) do
if sp.pos[1] == state.pos[1] and sp.pos[2] == state.pos[2] and sp.pos[3] == state.pos[3] then
table.remove(checkpoints, i)
return
end
end
end)
end)

View File

@ -0,0 +1,209 @@
local checkpoints = {}
local raceId = 0
RegisterServerEvent('race:updateCheckpoints')
AddEventHandler('race:updateCheckpoints', function(cps)
if #checkpoints > 0 then
return
end
checkpoints = cps
TriggerClientEvent('race:weGotPorn', -1)
end)
local playerData = {}
local function ensurePlayerData(id)
if playerData[id] then
return
end
playerData[id] = {
curCheckpoint = 0
}
end
local raceStarted = false
local playerCount = 0
local function startRace()
raceStarted = true
print("really starting race")
local function raceCountdown(num)
local time = (4000 - (num * 1000))
print("setting countdown for " .. tostring(time))
SetTimeout(time, function()
print("trig'd countdown for " .. tostring(time))
if num == 0 then
TriggerClientEvent('race:itsGoTime', -1, 0)
TriggerClientEvent('race:showGoMessage', -1, 'GO')
else
TriggerClientEvent('race:showGoMessage', -1, tostring(num))
end
end)
end
raceCountdown(3) -- 3...
raceCountdown(2) -- 2...
raceCountdown(1) -- 1...
raceCountdown(0) -- GOGOGO
end
local function incrementPlayerCount()
playerCount = playerCount + 1
if playerCount > 4 then
startRace()
end
if playerCount == 1 then
SetTimeout(3000, function()
if raceStarted then
return
end
print("starting race")
startRace()
end)
end
end
local playersFinished
local raceEnded
AddEventHandler('onMapStart', function()
playerCount = 0
playersFinished = 0
raceId = raceId + 1
raceStarted = false
raceEnded = false
playerData = {}
checkpoints = {}
print("mmmmmm race")
end)
local function endRace()
raceEnded = true
TriggerClientEvent('race:results', -1, '1234')
SetTimeout(7500, function()
TriggerEvent('mapmanager:roundEnded')
end)
end
AddEventHandler('race:onPlayerFinished', function(player)
print(GetPlayerName(player) .. ' finished')
local data = playerData[player]
local finishSeconds = os.clock() - data.startTime
local position = playersFinished + 1
data.position = position
playersFinished = position
TriggerClientEvent('race:onPlayerFinished', -1, player, {
finishSeconds = finishSeconds,
position = position
})
if playersFinished == playerCount then
endRace()
elseif playersFinished == 1 then
local thisRaceId = raceId
TriggerClientEvent('race:hurryUp', -1, 30000)
SetTimeout(30000, function()
if raceId ~= thisRaceId or raceEnded then
return
end
endRace()
end)
end
end)
AddEventHandler('playerActivated', function()
if #checkpoints > 0 then
TriggerClientEvent('race:weGotPorn', source)
end
end)
RegisterServerEvent('race:requestGo')
AddEventHandler('race:requestGo', function()
if #checkpoints > 0 then
TriggerClientEvent('race:weGotPorn', source)
end
end)
AddEventHandler('playerDropped', function(player)
if playerData[player] and playerData[player].curCheckpoint > 0 then
TriggerClientEvent('race:updateStatus', -1, player, -1)
playerCount = playerCount - 1
end
end)
RegisterServerEvent('race:gotCP')
AddEventHandler('race:gotCP', function()
ensurePlayerData(source)
local data = playerData[source]
local next = data.curCheckpoint + 1
if next > #checkpoints then
print("omg finished")
TriggerEvent('race:onPlayerFinished', source)
return
end
data.curCheckpoint = next
TriggerClientEvent('race:confirmCP', source) -- for sound effects
TriggerClientEvent('race:setCheckpoint', source, checkpoints[next], checkpoints[next + 1], checkpoints[next + 2])
TriggerClientEvent('race:updateStatus', -1, source, next - 1)
end)
RegisterServerEvent('race:requestCheckpoint')
AddEventHandler('race:requestCheckpoint', function()
print('is it even in here')
ensurePlayerData(source)
print(source, 'requesting cp')
if playerData[source].curCheckpoint == 0 then
incrementPlayerCount()
print(source, 'requesting cp 0')
local curCP = 1
playerData[source].curCheckpoint = curCP
playerData[source].startTime = os.clock()
TriggerClientEvent('race:setCheckpoint', source, checkpoints[curCP], checkpoints[curCP + 1], checkpoints[curCP + 2])
TriggerClientEvent('race:updateStatus', -1, source, 0)
-- should have raceReallyStarted since 4-second countdown
if raceStarted then
TriggerClientEvent('race:itsGoTime', -1, 0)
end
end
end)

View File

@ -0,0 +1,18 @@
description 'output lists for game content'
SetResourceInfo('uiPage', 'client/html/index.html')
client_script 'client/channelfeed.lua'
export 'printTo'
export 'addChannel'
export 'removeChannel'
files
{
'client/html/index.html',
'client/html/feed.js',
'client/html/feed.css',
'client/fonts/roboto-regular.ttf',
'client/fonts/roboto-condensed.ttf',
}

View File

@ -0,0 +1,40 @@
local eventBuffer = {}
AddUIHandler('getNew', function(data, cb)
local localBuf = eventBuffer
eventBuffer = {}
cb(localBuf)
end)
function printTo(channel, data)
table.insert(eventBuffer, {
meta = 'print',
channel = channel,
data = data
})
PollUI()
end
function addChannel(id, options)
if not options.template then
return
end
options.id = id
table.insert(eventBuffer, {
meta = 'addChannel',
data = options
})
PollUI()
end
function removeChannel(id)
table.insert(eventBuffer, {
meta = 'removeChannel',
data = id
})
end

View File

@ -0,0 +1,118 @@
(function() {
var getLock = 0;
var channels = {};
var zoomLevel = '100%';
$(function()
{
zoomLevel = Math.round(($(window).height() / 720) * 100) + '%'; // yay dynamic typing
});
function refetchData()
{
getLock = 0;
$.get('http://channelfeed/getNew', function(data)
{
if (getLock > 1)
{
setTimeout(refetchData, 50);
return;
}
getLock++;
data.forEach(function(item)
{
switch (item.meta)
{
case 'print':
var channel = item.channel;
if (!(channel in channels))
{
return;
}
channel = channels[channel];
var elem = $($.Mustache.render(item.channel, item.data, { method: channel.method })).appendTo(channel.$elem);
setTimeout(function()
{
elem.fadeOut(400, function()
{
elem.remove();
});
}, 7500);
break;
case 'addChannel':
var channel = item.data;
if (channel.id in channels)
{
return;
}
channel.$elem = $('<div></div>').attr('id', 'channel-' + channel.id).appendTo('#channels');
if (channel.styles !== undefined)
{
channel.$elem.css(channel.styles);
}
channel.$elem = $('<div></div>').css('zoom', zoomLevel).appendTo(channel.$elem);
if (channel.styleUrl !== undefined)
{
$('<link>').appendTo('head').attr({ type: 'text/css', rel: 'stylesheet' }).attr('href', channel.styleUrl);
}
$.Mustache.add(channel.id, channel.template);
channels[channel.id] = channel;
break;
case 'removeChannel':
var channelId = item.data;
if (channelId in channels)
{
channel.$elem.parent().remove();
delete channels[channelId];
}
break;
case 'clear':
var channel = item.channel;
if (!(channel in channels))
{
return;
}
channel = channels[channel];
channel.$elem.html();
break;
}
});
});
}
window.addEventListener('message', function(event)
{
if (event.data.type != 'poll')
{
return;
}
refetchData();
});
})();

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
<script src="nui://game/ui/mustache.js" type="text/javascript"></script>
<script src="nui://game/ui/jquery.mustache.js" type="text/javascript"></script>
<script src="feed.js" type="text/javascript"></script>
</head>
<body>
<div id="channels">
</div>
</body>
</html>

Binary file not shown.

View File

@ -0,0 +1 @@
server_script 'irc.lua'

View File

@ -0,0 +1,4 @@
local reflection = clr.System.Reflection
local assembly = reflection.Assembly.LoadFrom('resources/[gameplay]/irc/ChatSharp.dll')
dofile('resources/[gameplay]/irc/irc_run.lua')

View File

@ -0,0 +1,91 @@
local chatSharp = clr.ChatSharp
local client = chatSharp.IrcClient('irc.rizon.net', chatSharp.IrcUser('citimate', 'mateyate'), false)
-- temporary workaround for connections that never triggered playerActivated but triggered playerDropped
local activatedPlayers = {}
client.ConnectionComplete:add(function(s : object, e : System.EventArgs) : void
client:JoinChannel('#meow')
end)
-- why is 'received' even misspelled here?
client.ChannelMessageRecieved:add(function(s : object, e : ChatSharp.Events.PrivateMessageEventArgs) : void
local msg = e.PrivateMessage
TriggerClientEvent('chatMessage', -1, msg.User.Nick, { 0, 0x99, 255 }, msg.Message)
end)
AddEventHandler('playerActivated', function()
client:SendMessage('* ' .. GetPlayerName(source) .. '(' .. GetPlayerGuid(source) .. '@' .. GetPlayerEP(source) .. ') joined the server', '#fourdeltaone')
table.insert(activatedPlayers, GetPlayerGuid(source))
end)
AddEventHandler('playerDropped', function()
-- find out if this connection ever triggered playerActivated
for index,guid in pairs(activatedPlayers) do
if guid == playerGuid then
-- show player dropping connection in chat
client:SendMessage('* ' .. GetPlayerName(source) .. '(' .. GetPlayerGuid(source) .. '@' .. GetPlayerEP(source) .. ') left the server', '#fourdeltaone')
table.remove(activatedPlayers, index)
return
end
end
end)
AddEventHandler('chatMessage', function(source, name, message)
print('hey there ' .. name)
local displayMessage = gsub(message, '^%d', '')
-- ignore zero-length messages
if string.len(displayMessage) == 0 then
return
end
-- ignore chat messages that are actually commands
if string.sub(displayMessage, 1, 1) == "/" then
return
end
client:SendMessage('[' .. tostring(GetPlayerName(source)) .. ']: ' .. displayMessage, '#fourdeltaone')
end)
AddEventHandler('onPlayerKilled', function(playerId, attackerId, reason, position)
local player = GetPlayerByServerId(playerId)
local attacker = GetPlayerByServerId(attackerId)
local reasonString = 'killed'
if reason == 0 or reason == 56 or reason == 1 or reason == 2 then
reasonString = 'meleed'
elseif reason == 3 then
reasonString = 'knifed'
elseif reason == 4 or reason == 6 or reason == 18 or reason == 51 then
reasonString = 'bombed'
elseif reason == 5 or reason == 19 then
reasonString = 'burned'
elseif reason == 7 or reason == 9 then
reasonString = 'pistoled'
elseif reason == 10 or reason == 11 then
reasonString = 'shotgunned'
elseif reason == 12 or reason == 13 or reason == 52 then
reasonString = 'SMGd'
elseif reason == 14 or reason == 15 or reason == 20 then
reasonString = 'assaulted'
elseif reason == 16 or reason == 17 then
reasonString = 'sniped'
elseif reason == 49 or reason == 50 then
reasonString = 'ran over'
end
client:SendMessage('* ' .. attacker.name .. ' ' .. reasonString .. ' ' .. player.name, '#fourdeltaone')
end)
client:ConnectAsync()
AddEventHandler('onResourceStop', function(name)
if name == GetInvokingResource() then
client:Quit('Resource stopping.')
end
end)

View File

@ -0,0 +1,5 @@
dependency 'obituary'
description 'death messages using the obituary resource'
client_script 'deathmessages.lua'

View File

@ -0,0 +1,42 @@
AddEventHandler('onPlayerDied', function(playerId, reason, position)
local player = GetPlayerByServerId(playerId)
if player then
exports.obituary:printObituary('<b>%s</b> died.', player.name)
end
end)
AddEventHandler('onPlayerKilled', function(playerId, attackerId, reason, position)
local player = GetPlayerByServerId(playerId)
local attacker = GetPlayerByServerId(attackerId)
local reasonString = 'killed'
if reason == 0 or reason == 56 or reason == 1 or reason == 2 then
reasonString = 'meleed'
elseif reason == 3 then
reasonString = 'knifed'
elseif reason == 4 or reason == 6 or reason == 18 or reason == 51 then
reasonString = 'bombed'
elseif reason == 5 or reason == 19 then
reasonString = 'burned'
elseif reason == 7 or reason == 9 then
reasonString = 'pistoled'
elseif reason == 10 or reason == 11 then
reasonString = 'shotgunned'
elseif reason == 12 or reason == 13 or reason == 52 then
reasonString = 'SMGd'
elseif reason == 14 or reason == 15 or reason == 20 then
reasonString = 'assaulted'
elseif reason == 16 or reason == 17 then
reasonString = 'sniped'
elseif reason == 49 or reason == 50 then
reasonString = 'ran over'
end
echo("obituary-deaths: onPlayerKilled\n")
if player and attacker then
exports.obituary:printObituary('<b>%s</b> %s <b>%s</b>.', attacker.name, reasonString, player.name)
end
end)

View File

@ -0,0 +1,7 @@
dependency 'channelfeed'
client_script 'obituary.lua'
export 'printObituary'
files 'obituary.css'

View File

@ -0,0 +1,46 @@
@font-face {
font-family: 'Roboto Condensed';
src: url('nui://channelfeed/client/fonts/roboto-condensed.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Roboto';
src: url('nui://channelfeed/client/fonts/roboto-regular.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
#channel-obituary
{
position: absolute;
}
#channel-obituary > div
{
width: 100%;
font-family: 'Roboto';
}
#channel-obituary div.item
{
background-color: rgba(50, 50, 50, .6);
padding: 4px;
padding-left: 8px;
padding-right: 8px;
border-radius: 4px;
color: #eee;
margin-bottom: 3px;
font-size: 65%;
}
#channel-obituary div.item b
{
font-family: 'Roboto Condensed';
font-size: 125%;
font-weight: normal;
color: #09f;
}

View File

@ -0,0 +1,51 @@
AddEventHandler('onClientResourceStart', function(name)
if name == GetCurrentResource() then
local x, y = GetHudPosition('HUD_RADAR')
local w, h = GetHudSize('HUD_RADAR')
x = x - 0.01
w = w + 0.02
if GetIsWidescreen() then
x = x / 1.333
w = w / 1.333
end
exports.channelfeed:addChannel('obituary', {
method = 'append',
styleUrl = 'nui://obituary/obituary.css',
styles = { -- temporary
left = tostring(x * 100) .. '%',
bottom = 'calc(' .. tostring((1 - y) * 100) .. '% + 10px)',
width = tostring(w * 100) .. '%'
},
template = '<div class="item">{{{text}}}</div>'
})
end
end)
function printObituary(format, ...)
local args = table.pack(...)
for i = 1, args.n do
if type(args[i]) == 'string' then
args[i] = args[i]:gsub('<', '&lt;')
end
end
echo("obituary: printObituary\n")
exports.channelfeed:printTo('obituary', {
text = string.format(format, table.unpack(args))
})
end
--[[AddEventHandler('chatMessage', function(name, color, message)
exports.channelfeed:printTo('obituary', {
text = message:gsub('<', '&lt;')
})
end)]]
AddEventHandler('onClientResourceStop', function()
-- todo: remove channel
end)

View File

@ -0,0 +1,9 @@
client_scripts {
"mapmanager_client.lua",
"mapmanager_shared.lua"
}
server_scripts {
"mapmanager_server.lua",
"mapmanager_shared.lua"
}

View File

@ -0,0 +1,200 @@
maps = {}
gametypes = {}
AddEventHandler('getResourceInitFuncs', function(isPreParse, add)
if not isPreParse then
add('map', function(file)
addMap(file, GetInvokingResource())
end)
add('resource_type', function(type)
return function(params)
local resourceName = GetInvokingResource()
if type == 'map' then
maps[resourceName] = params
elseif type == 'gametype' then
gametypes[resourceName] = params
end
end
end)
end
end)
mapFiles = {}
function addMap(file, owningResource)
if not mapFiles[owningResource] then
mapFiles[owningResource] = {}
end
table.insert(mapFiles[owningResource], file)
end
AddEventHandler('onClientResourceStart', function(res)
-- parse metadata for this resource
-- map files
local num = GetNumResourceMetadata(res, 'map')
if num then
for i = 0, num-1 do
local file = GetResourceMetadata(res, 'map', i)
if file then
addMap(file, res)
end
end
end
-- resource type data
local type = GetResourceMetadata(res, 'resource_type', 0)
if type then
Citizen.Trace("type " .. res .. " " .. type .. "\n")
local extraData = GetResourceMetadata(res, 'resource_type_extra', 0)
if extraData then
extraData = json.decode(extraData)
else
extraData = {}
end
if type == 'map' then
maps[res] = extraData
elseif type == 'gametype' then
gametypes[res] = extraData
end
end
-- handle starting
if mapFiles[res] then
for _, file in ipairs(mapFiles[res]) do
parseMap(file, res)
end
end
-- defer this to the next game tick to work around a lack of dependencies
Citizen.CreateThread(function()
Citizen.Wait(15)
if maps[res] then
TriggerEvent('onClientMapStart', res)
elseif gametypes[res] then
TriggerEvent('onClientGameTypeStart', res)
end
end)
end)
AddEventHandler('onClientResourceStop', function(res)
if maps[res] then
TriggerEvent('onClientMapStop', res)
elseif gametypes[res] then
TriggerEvent('onClientGameTypeStop', res)
end
if undoCallbacks[res] then
for _, cb in ipairs(undoCallbacks[res]) do
cb()
end
undoCallbacks[res] = nil
mapFiles[res] = nil
end
end)
undoCallbacks = {}
function parseMap(file, owningResource)
if not undoCallbacks[owningResource] then
undoCallbacks[owningResource] = {}
end
local env = {
math = math, pairs = pairs, ipairs = ipairs, next = next, tonumber = tonumber, tostring = tostring,
type = type, table = table, string = string, _G = env
}
TriggerEvent('getMapDirectives', function(key, cb, undocb)
env[key] = function(...)
local state = {}
state.add = function(k, v)
state[k] = v
end
local result = cb(state, ...)
local args = table.pack(...)
table.insert(undoCallbacks[owningResource], function()
undocb(state)
end)
return result
end
end)
local mt = {
__index = function(t, k)
if rawget(t, k) ~= nil then return rawget(t, k) end
-- as we're not going to return nothing here (to allow unknown directives to be ignored)
local f = function()
return f
end
return function() return f end
end
}
setmetatable(env, mt)
local fileData = LoadResourceFile(owningResource, file)
local mapFunction, err = load(fileData, file, 't', env)
if not mapFunction then
Citizen.Trace("Couldn't load map " .. file .. ": " .. err .. " (type of fileData: " .. type(fileData) .. ")\n")
return
end
mapFunction()
end
AddEventHandler('getMapDirectives', function(add)
add('vehicle_generator', function(state, name)
return function(opts)
local x, y, z, heading
local color1, color2
if opts.x then
x = opts.x
y = opts.y
z = opts.z
else
x = opts[1]
y = opts[2]
z = opts[3]
end
heading = opts.heading or 1.0
color1 = opts.color1 or -1
color2 = opts.color2 or -1
local hash = GetHashKey(name)
RequestModel(hash)
LoadAllObjectsNow()
local carGen = CreateScriptVehicleGenerator(x, y, z, heading, 5.0, 3.0, hash, color1, color2, -1, -1, true, false, false, true, true, -1)
SetScriptVehicleGenerator(carGen, true)
SetAllVehicleGeneratorsActive(true)
state.add('cargen', carGen)
end
end, function(state, arg)
Citizen.Trace("deleting car gen " .. tostring(state.cargen) .. "\n")
DeleteScriptVehicleGenerator(state.cargen)
end)
end)

View File

@ -0,0 +1,273 @@
-- loosely based on MTA's https://code.google.com/p/mtasa-resources/source/browse/trunk/%5Bmanagers%5D/mapmanager/mapmanager_main.lua
maps = {}
gametypes = {}
AddEventHandler('getResourceInitFuncs', function(isPreParse, add)
add('resource_type', function(type)
return function(params)
local resourceName = GetInvokingResource()
if type == 'map' then
maps[resourceName] = params
elseif type == 'gametype' then
gametypes[resourceName] = params
end
end
end)
add('map', function(file)
AddAuxFile(file)
end)
end)
AddEventHandler('onResourceStarting', function(resource)
if maps[resource] then
if getCurrentMap() and getCurrentMap() ~= resource then
if doesMapSupportGameType(getCurrentGameType(), resource) then
print("Changing map from " .. getCurrentMap() .. " to " .. resource)
changeMap(resource)
else
-- check if there's only one possible game type for the map
local map = maps[resource]
local count = 0
local gt
for type, flag in pairs(map.gameTypes) do
if flag then
count = count + 1
gt = type
end
end
if count == 1 then
print("Changing map from " .. getCurrentMap() .. " to " .. resource .. " (gt " .. gt .. ")")
changeGameType(gt)
changeMap(resource)
end
end
CancelEvent()
end
elseif gametypes[resource] then
if getCurrentGameType() and getCurrentGameType() ~= resource then
print("Changing gametype from " .. getCurrentGameType() .. " to " .. resource)
changeGameType(resource)
CancelEvent()
end
end
end)
math.randomseed(GetInstanceId())
local currentGameType = nil
local currentMap = nil
AddEventHandler('onResourceStart', function(resource)
if maps[resource] then
if not getCurrentGameType() then
for gt, _ in pairs(maps[resource].gameTypes) do
changeGameType(gt)
break
end
end
if getCurrentGameType() and not getCurrentMap() then
if doesMapSupportGameType(currentGameType, resource) then
if TriggerEvent('onMapStart', resource, maps[resource]) then
if maps[resource].name then
SetMapName(maps[resource].name)
else
SetMapName(resource)
end
currentMap = resource
else
currentMap = nil
end
end
end
elseif gametypes[resource] then
if not getCurrentGameType() then
if TriggerEvent('onGameTypeStart', resource, gametypes[resource]) then
currentGameType = resource
local gtName = gametypes[resource].name or resource
SetGameType(gtName)
print('Started gametype ' .. gtName)
TriggerClientEvent('onClientGameTypeStart', -1, getCurrentGameType())
SetTimeout(50, function()
if not currentMap then
local possibleMaps = {}
for map, data in pairs(maps) do
if data.gameTypes[currentGameType] then
table.insert(possibleMaps, map)
end
end
if #possibleMaps > 0 then
local rnd = math.random(#possibleMaps)
changeMap(possibleMaps[rnd])
end
end
end)
else
currentGameType = nil
end
end
end
end)
local function handleRoundEnd()
local possibleMaps = {}
for map, data in pairs(maps) do
if data.gameTypes[currentGameType] then
table.insert(possibleMaps, map)
end
end
if #possibleMaps > 0 then
local rnd = math.random(#possibleMaps)
changeMap(possibleMaps[rnd])
end
end
AddEventHandler('mapmanager:roundEnded', function()
-- set a timeout as we don't want to return to a dead environment
SetTimeout(50, handleRoundEnd) -- not a closure as to work around some issue in neolua?
end)
AddEventHandler('onResourceStop', function(resource)
if resource == currentGameType then
TriggerEvent('onGameTypeStop', resource)
currentGameType = nil
if currentMap then
StopResource(currentMap)
end
elseif resource == currentMap then
TriggerEvent('onMapStop', resource)
currentMap = nil
end
end)
AddEventHandler('rconCommand', function(commandName, args)
if commandName == 'map' then
if #args ~= 1 then
RconPrint("usage: map [mapname]\n")
end
if not maps[args[1]] then
RconPrint('no such map ' .. args[1] .. "\n")
CancelEvent()
return
end
if currentGameType == nil or not doesMapSupportGameType(currentGameType, args[1]) then
local map = maps[args[1]]
local count = 0
local gt
for type, flag in pairs(map.gameTypes) do
if flag then
count = count + 1
gt = type
end
end
if count == 1 then
print("Changing map from " .. getCurrentMap() .. " to " .. args[1] .. " (gt " .. gt .. ")")
changeGameType(gt)
changeMap(args[1])
RconPrint('map ' .. args[1] .. "\n")
else
RconPrint('map ' .. args[1] .. ' does not support ' .. currentGameType .. "\n")
end
CancelEvent()
return
end
changeMap(args[1])
RconPrint('map ' .. args[1] .. "\n")
CancelEvent()
elseif commandName == 'gametype' then
if #args ~= 1 then
RconPrint("usage: gametype [name]\n")
end
if not gametypes[args[1]] then
RconPrint('no such gametype ' .. args[1] .. "\n")
CancelEvent()
return
end
changeGameType(args[1])
RconPrint('gametype ' .. args[1] .. "\n")
CancelEvent()
end
end)
function getCurrentGameType()
return currentGameType
end
function getCurrentMap()
return currentMap
end
function changeGameType(gameType)
if currentMap and not doesMapSupportGameType(gameType, currentMap) then
StopResource(currentMap)
end
if currentGameType then
StopResource(currentGameType)
end
StartResource(gameType)
end
function changeMap(map)
if currentMap then
StopResource(currentMap)
end
StartResource(map)
end
function doesMapSupportGameType(gameType, map)
if not gametypes[gameType] then
return false
end
if not maps[map] then
return false
end
if not maps[map].gameTypes then
return true
end
return maps[map].gameTypes[gameType]
end

View File

@ -0,0 +1 @@
-- shared logic file for map manager - don't call any subsystem-specific functions here

View File

@ -0,0 +1,2 @@
client_script 'deathevents.lua'
client_script 'vehiclechecker.lua'

View File

@ -0,0 +1,73 @@
Citizen.CreateThread(function()
local isDead = false
local hasBeenDead = false
local diedAt
while true do
Wait(0)
local player = PlayerId()
if NetworkIsPlayerActive(player) then
local ped = PlayerPedId()
if IsPedFatallyInjured(ped) and not isDead then
isDead = true
if not diedAt then
diedAt = GetGameTimer()
end
local killer = NetworkGetEntityKillerOfPlayer(player)
local killerentitytype = GetEntityType(killer)
local killertype = -1
local killerinvehicle = false
local killervehiclename = ''
local killervehicleseat = 0
if killerentitytype == 1 then
killertype = GetPedType(killer)
if IsPedInAnyVehicle(killer, false) == 1 then
killerinvehicle = true
killervehiclename = GetDisplayNameFromVehicleModel(GetEntityModel(GetVehiclePedIsUsing(killer)))
killervehicleseat = GetPedVehicleSeat(killer)
else killerinvehicle = false
end
end
local killerid = GetPlayerByEntityID(killer)
if killer ~= ped and killerid ~= nil and NetworkIsPlayerActive(killerid) then killerid = GetPlayerServerId(killerid)
else killerid = -1
end
if killer == ped then
TriggerEvent('baseevents:onPlayerDied', killertype, { table.unpack(GetEntityCoords(ped)) })
TriggerServerEvent('baseevents:onPlayerDied', killertype, { table.unpack(GetEntityCoords(ped)) })
hasBeenDead = true
else
TriggerEvent('baseevents:onPlayerKilled', killerid, {killertype=killertype, killerinveh=killerinvehicle, killervehseat=killervehicleseat, killervehname=killervehiclename, killerpos=table.unpack(GetEntityCoords(ped))})
TriggerServerEvent('baseevents:onPlayerKilled', killerid, {killertype=killertype, killerinveh=killerinvehicle, killervehseat=killervehicleseat, killervehname=killervehiclename, killerpos=table.unpack(GetEntityCoords(ped))})
hasBeenDead = true
end
elseif not IsPedFatallyInjured(ped) then
isDead = false
diedAt = nil
end
-- check if the player has to respawn in order to trigger an event
if not hasBeenDead and diedAt ~= nil and diedAt > 0 then
TriggerEvent('baseevents:onPlayerWasted', { table.unpack(GetEntityCoords(ped)) })
TriggerServerEvent('baseevents:onPlayerWasted', { table.unpack(GetEntityCoords(ped)) })
hasBeenDead = true
elseif hasBeenDead and diedAt ~= nil and diedAt <= 0 then
hasBeenDead = false
end
end
end
end)
function GetPlayerByEntityID(id)
for i=0,32 do
if(NetworkIsPlayerActive(i) and GetPlayerPed(i) == id) then return i end
end
return nil
end

View File

@ -0,0 +1,54 @@
local isInVehicle = false
local isEnteringVehicle = false
local currentVehicle = 0
local currentSeat = 0
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
local ped = PlayerPedId()
if not isInVehicle and not IsPlayerDead(PlayerId()) then
if DoesEntityExist(GetVehiclePedIsTryingToEnter(ped)) and not isEnteringVehicle then
-- trying to enter a vehicle!
local vehicle = GetVehiclePedIsTryingToEnter(ped)
local seat = GetSeatPedIsTryingToEnter(ped)
isEnteringVehicle = true
TriggerServerEvent('baseevents:enteringVehicle', vehicle, seat, GetDisplayNameFromVehicleModel(GetEntityModel(vehicle)))
elseif not DoesEntityExist(GetVehiclePedIsTryingToEnter(ped)) and not IsPedInAnyVehicle(ped, true) and isEnteringVehicle then
-- vehicle entering aborted
TriggerServerEvent('baseevents:enteringAborted')
isEnteringVehicle = false
elseif IsPedInAnyVehicle(ped, false) then
-- suddenly appeared in a vehicle, possible teleport
isEnteringVehicle = false
isInVehicle = true
currentVehicle = GetVehiclePedIsUsing(ped)
currentSeat = GetPedVehicleSeat(ped)
local model = GetEntityModel(currentVehicle)
local name = GetDisplayNameFromVehicleModel()
TriggerServerEvent('baseevents:enteredVehicle', currentVehicle, currentSeat, GetDisplayNameFromVehicleModel(GetEntityModel(currentVehicle)))
end
elseif isInVehicle then
if not IsPedInAnyVehicle(ped, false) or IsPlayerDead(PlayerId()) then
-- bye, vehicle
local model = GetEntityModel(currentVehicle)
local name = GetDisplayNameFromVehicleModel()
TriggerServerEvent('baseevents:leftVehicle', currentVehicle, currentSeat, GetDisplayNameFromVehicleModel(GetEntityModel(currentVehicle)))
isInVehicle = false
currentVehicle = 0
currentSeat = 0
end
end
Citizen.Wait(50)
end
end)
function GetPedVehicleSeat(ped)
local vehicle = GetVehiclePedIsIn(ped, false)
for i=-2,GetVehicleMaxNumberOfPassengers(vehicle) do
if(GetPedInVehicleSeat(vehicle, i) == ped) then return i end
end
return -2
end

View File

@ -0,0 +1,15 @@
description 'chat management stuff'
ui_page 'html/chat.html'
client_script 'chat_client.lua'
server_script 'chat_server.lua'
export 'printChatLine'
files {
'html/chat.html',
'html/chat.css',
'html/chat.js',
'html/jquery.faketextbox.js'
}

View File

@ -0,0 +1,56 @@
local chatInputActive = false
local chatInputActivating = false
RegisterNetEvent('chatMessage')
AddEventHandler('chatMessage', function(name, color, message)
SendNUIMessage({
name = name,
color = color,
message = message
})
end)
RegisterNUICallback('chatResult', function(data, cb)
chatInputActive = false
SetNuiFocus(false)
if data.message then
local id = PlayerId()
--local r, g, b = GetPlayerRgbColour(id, _i, _i, _i)
local r, g, b = 0, 0x99, 255
TriggerServerEvent('chatMessageEntered', GetPlayerName(id), { r, g, b }, data.message)
end
cb('ok')
end)
Citizen.CreateThread(function()
SetTextChatEnabled(false)
while true do
Wait(0)
if not chatInputActive then
if IsControlPressed(0, 245) --[[ INPUT_MP_TEXT_CHAT_ALL ]] then
chatInputActive = true
chatInputActivating = true
SendNUIMessage({
meta = 'openChatBox'
})
end
end
if chatInputActivating then
if not IsControlPressed(0, 245) then
SetNuiFocus(true)
chatInputActivating = false
end
end
end
end)

View File

@ -0,0 +1,50 @@
RegisterServerEvent('chatCommandEntered')
RegisterServerEvent('chatMessageEntered')
AddEventHandler('chatMessageEntered', function(name, color, message)
if not name or not color or not message or #color ~= 3 then
return
end
TriggerEvent('chatMessage', source, name, message)
if not WasEventCanceled() then
TriggerClientEvent('chatMessage', -1, name, color, message)
end
print(name .. ': ' .. message)
end)
-- player join messages
AddEventHandler('playerActivated', function()
TriggerClientEvent('chatMessage', -1, '', { 0, 0, 0 }, '^2* ' .. GetPlayerName(source) .. ' joined.')
end)
AddEventHandler('playerDropped', function(reason)
TriggerClientEvent('chatMessage', -1, '', { 0, 0, 0 }, '^2* ' .. GetPlayerName(source) ..' left (' .. reason .. ')')
end)
-- say command handler
AddEventHandler('rconCommand', function(commandName, args)
if commandName == "say" then
local msg = table.concat(args, ' ')
TriggerClientEvent('chatMessage', -1, 'console', { 0, 0x99, 255 }, msg)
RconPrint('console: ' .. msg .. "\n")
CancelEvent()
end
end)
-- tell command handler
AddEventHandler('rconCommand', function(commandName, args)
if commandName == "tell" then
local target = table.remove(args, 1)
local msg = table.concat(args, ' ')
TriggerClientEvent('chatMessage', tonumber(target), 'console', { 0, 0x99, 255 }, msg)
RconPrint('console: ' .. msg .. "\n")
CancelEvent()
end
end)

View File

@ -0,0 +1,102 @@
body
{
background-color: transparent;
margin: 0px;
}
ul
{
margin: 0px;
padding: 0px;
list-style-type: none; /* hii */
}
#chat
{
position: absolute;
top: 30px;
left: 30px;
padding: 7px;
width: 30%;
font-size: 20px;
font-family: "Segoe UI", "Segoe UI Symbol", "Segoe UI Emoji", Arial, sans-serif;
color: #fff;
overflow: hidden;
text-shadow: 0px 0px 1px #333;
}
input.fake
{
position: absolute;
top: -10000px;
left: -10000px;
}
#chatInputHas
{
display: none;
}
#chatInputHas strong
{
display: inline-block;
vertical-align: middle;
text-transform: uppercase;
height: 29px;
line-height: 26px;
}
#chatInput
{
background-color: transparent;
border: none;
outline: none !important;
padding: 3px;
display: inline-block;
vertical-align: middle;
margin: 0px;
color: #fff;
text-shadow: 0px 0px 1px #333;
font: inherit;
white-space: pre;
overflow: hidden;
}
#chatInput > div:first-child
{
display: inline-block;
vertical-align: middle;
height: 23px;
line-height: 20px;
}
#chatInput .caret
{
display: inline-block;
min-width: 1px;
height: 22px;
margin-left: 1px;
vertical-align: bottom;
background-color: #fff;
box-shadow: 0px 0px 1px #333;
color: white;
}
#chatBuffer
{
height: 240px;
overflow: hidden;
}
.color-1{color: #ff4444;}
.color-2{color: #99cc00;}
.color-3{color: #ffbb33;}
.color-4{color: #0099cc;}
.color-5{color: #33b5e5;}
.color-6{color: #aa66cc;}
.color-8{color: #cc0000;}
.color-9{color: #cc0000;}

View File

@ -0,0 +1,20 @@
<html>
<head>
<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
<script src="jquery.faketextbox.js" type="text/javascript"></script>
<script src="chat.js" type="text/javascript"></script>
<link href="chat.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="chat">
<div id="chatBuffer">
<ul>
</ul>
</div>
<div id="chatInputHas">
<strong>Chat</strong>
<div id="chatInput" />
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,166 @@
function colorize(string)
{
var newString = '';
var inSpan = false;
for (i = 0; i < string.length; i++)
{
if (string[i] == '^')
{
if (string[i + 1] == '7' || string[i + 1] == '0')
{
if (inSpan)
{
newString += '</span>';
inSpan = false;
}
i += 2;
}
else if (string[i + 1] >= '0' && string[i + 1] <= '9')
{
if (inSpan)
{
newString += '</span>';
}
i += 2;
newString += '<span class="color-' + string[i - 1] + '">';
inSpan = true;
}
}
newString += string[i];
}
if (inSpan)
{
newString += '</span>';
}
return newString;
}
$(function()
{
var chatHideTimeout;
var inputShown = false;
function startHideChat()
{
if (chatHideTimeout)
{
clearTimeout(chatHideTimeout);
}
if (inputShown)
{
return;
}
chatHideTimeout = setTimeout(function()
{
if (inputShown)
{
return;
}
$('#chat').animate({ opacity: 0 }, 300);
}, 7000);
}
handleResult = function(elem, wasEnter)
{
inputShown = false;
$('#chatInputHas').hide();
startHideChat();
var obj = {};
if (wasEnter)
{
obj = { message: $(elem).val() };
}
$(elem).val('');
$.post('http://chat/chatResult', JSON.stringify(obj), function(data)
{
console.log(data);
});
};
$('#chatInput').fakeTextbox(); // //
$('#chatInput')[0].onPress(function(e)
{
if (e.which == 13)
{
handleResult(this, true);
}
});
$(document).keyup(function(e)
{
if (e.keyCode == 27)
{
handleResult($('#chatInput')[0].getTextBox(), false);
}
});
$(document).keypress(function(e)
{
if (e.keyCode == 9)
{
e.preventDefault();
return false;
}
});
window.addEventListener('message', function(event)
{
var item = event.data;
if (item.meta && item.meta == 'openChatBox')
{
inputShown = true;
$('#chat').css('opacity', '1');
$('#chatInputHas').show();
$('#chatInput')[0].doFocus();
return;
}
// TODO: use some templating stuff for this
var colorR = parseInt(item.color[0]);
var colorG = parseInt(item.color[1]);
var colorB = parseInt(item.color[2]);
var name = item.name.replace('<', '&lt;');
var message = item.message.replace('<', '&lt;');
message = colorize(message);
var buf = $('#chatBuffer');
var nameStr = '';
if (name != '')
{
nameStr = '<strong style="color: rgb(' + colorR + ', ' + colorG + ', ' + colorB + ')">' + name + ': </strong>';
}
buf.find('ul').append('<li>' + nameStr + message + '</li>');
buf.scrollTop(buf[0].scrollHeight - buf.height());
$('#chat').css('opacity', '1');
startHideChat();
}, false);
});

View File

@ -0,0 +1,103 @@
(function ($) {
$.fn.fakeTextbox = function () {
return this.each(function () {
var $me = $(this),
cursorTimer,
$tb = $('<input type="text" class="fake" />');
if ($me.data('ftbftw')) {
console.log('already initialized');
return;
}
$me.data('ftbftw', 1);
$tb.insertAfter($me);
function appendCaret(toHere, position, selStart, selEnd) {
if (position === selStart) {
toHere += "</div><div class='caret'>";
}
if (position === selEnd) {
toHere += "</div><div>";
}
return toHere;
}
function syncTextbox() {
var tbVal = $tb.val().replace('<', '&lt;');
var tbLen = tbVal.length;
var selStart = $tb.get(0).selectionStart;
var selEnd = $tb.get(0).selectionEnd;
var newOut = '<div>';
for (var i = 0; i < tbLen; i++) {
newOut = appendCaret(newOut, i, selStart, selEnd);
newOut += tbVal[i];
}
$me.html(colorize(appendCaret(newOut, i, selStart, selEnd) + '</div>'));
if (selStart != selEnd) {
$('.caret', $me).addClass('selection');
}
}
$me.click(function () {
$tb.focus();
});
$tb.bind("change keypress keyup", function()
{
setTimeout(syncTextbox, 1); //
})
.blur(function () {
clearInterval(cursorTimer);
cursorTimer = null;
var $cursor = $('.caret', $me);
$cursor.css({
visibility: 'visible'
});
$me.removeClass('focused');
}).focus(function () {
if (!cursorTimer) {
$me.addClass('focused');
cursorTimer = window.setInterval(function () {
var $cursor = $('.caret', $me);
if ($cursor.hasClass('selection') || $cursor.css('visibility') === 'hidden') {
$cursor.css({
visibility: 'visible'
});
} else {
$cursor.css({
visibility: 'hidden'
});
}
}, 500);
}
});
this.doFocus = function()
{
$tb.focus();
};
this.onPress = function(f)
{
$tb.bind('keypress', f);
};
this.getTextBox = function()
{
return $tb;
};
syncTextbox();
if ($me.hasClass('initFocus')) {
$tb.focus();
}
});
};
}(jQuery));

View File

@ -0,0 +1,2 @@
client_script 'client.lua'
server_script 'server.lua'

View File

@ -0,0 +1,11 @@
Citizen.CreateThread(function()
while true do
Wait(0)
if NetworkIsSessionStarted() then
TriggerServerEvent('hardcap:playerActivated')
return
end
end
end)

View File

@ -0,0 +1,29 @@
local playerCount = 0
local list = {}
RegisterServerEvent('hardcap:playerActivated')
AddEventHandler('hardcap:playerActivated', function()
if not list[source] then
playerCount = playerCount + 1
list[source] = true
end
end)
AddEventHandler('playerDropped', function()
if list[source] then
playerCount = playerCount - 1
list[source] = nil
end
end)
AddEventHandler('playerConnecting', function(name, setReason)
print('Connecting: ' .. name)
if playerCount >= 24 then
print('Full. :(')
setReason('This server is full (past 24 players).')
CancelEvent()
end
end)

View File

@ -0,0 +1,2 @@
client_script 'rconlog_client.lua'
server_script 'rconlog_server.lua'

View File

@ -0,0 +1,25 @@
RegisterNetEvent('rlUpdateNames')
AddEventHandler('rlUpdateNames', function()
local names = {}
for i = 0, 31 do
if NetworkIsPlayerActive(i) then
names[GetPlayerServerId(i)] = { id = i, name = GetPlayerName(i) }
end
end
TriggerServerEvent('rlUpdateNamesResult', names)
end)
Citizen.CreateThread(function()
while true do
Wait(0)
if NetworkIsSessionStarted() then
TriggerServerEvent('rlPlayerActivated')
return
end
end
end)

View File

@ -0,0 +1,80 @@
RconLog({ msgType = 'serverStart', hostname = 'lovely', maxplayers = 32 })
RegisterServerEvent('rlPlayerActivated')
local names = {}
AddEventHandler('rlPlayerActivated', function()
RconLog({ msgType = 'playerActivated', netID = source, name = GetPlayerName(source), guid = GetPlayerIdentifiers(source)[1], ip = GetPlayerEP(source) })
names[source] = { name = GetPlayerName(source), id = source }
TriggerClientEvent('rlUpdateNames', GetHostId())
end)
RegisterServerEvent('rlUpdateNamesResult')
AddEventHandler('rlUpdateNamesResult', function(res)
if source ~= GetHostId() then
print('bad guy')
return
end
for id, data in pairs(res) do
if data then
if data.name then
if not names[id] then
names[id] = data
end
if names[id].name ~= data.name or names[id].id ~= data.id then
names[id] = data
RconLog({ msgType = 'playerRenamed', netID = id, name = data.name })
end
end
else
names[id] = nil
end
end
end)
AddEventHandler('playerDropped', function()
RconLog({ msgType = 'playerDropped', netID = source, name = GetPlayerName(source) })
names[source] = nil
end)
AddEventHandler('chatMessage', function(netID, name, message)
RconLog({ msgType = 'chatMessage', netID = netID, name = name, message = message, guid = GetPlayerIdentifiers(netID)[1] })
end)
AddEventHandler('rconCommand', function(commandName, args)
if commandName == 'status' then
for netid, data in pairs(names) do
local guid = GetPlayerIdentifiers(netid)
if guid and guid[1] and data then
local ping = GetPlayerPing(netid)
RconPrint(netid .. ' ' .. guid[1] .. ' ' .. data.name .. ' ' .. GetPlayerEP(netid) .. ' ' .. ping .. "\n")
end
end
CancelEvent()
elseif commandName:lower() == 'clientkick' then
local playerId = table.remove(args, 1)
local msg = table.concat(args, ' ')
DropPlayer(playerId, msg)
CancelEvent()
elseif commandName:lower() == 'tempbanclient' then
local playerId = table.remove(args, 1)
local msg = table.concat(args, ' ')
TempBanPlayer(playerId, msg)
CancelEvent()
end
end)

View File

@ -0,0 +1,18 @@
description 'Scoreboard'
-- temporary!
ui_page 'html/scoreboard.html'
client_script 'scoreboard.lua'
files {
'html/scoreboard.html',
'html/style.css',
'html/reset.css',
'html/listener.js',
'html/res/futurastd-medium.css',
'html/res/futurastd-medium.eot',
'html/res/futurastd-medium.woff',
'html/res/futurastd-medium.ttf',
'html/res/futurastd-medium.svg',
}

View File

@ -0,0 +1,17 @@
$(function()
{
window.addEventListener('message', function(event)
{
var item = event.data;
var buf = $('#wrap');
buf.find('table').append("<tr class=\"heading\"><th>ID</th><th>Name</th><th>Wanted level</th></tr>");
if (item.meta && item.meta == 'close')
{
document.getElementById("ptbl").innerHTML = "";
$('#wrap').hide();
return;
}
buf.find('table').append(item.text);
$('#wrap').show();
}, false);
});

View File

@ -0,0 +1,8 @@
@font-face {
font-family: 'FuturaStdMedium';
src: url('futurastd-medium.eot');
src: url('futurastd-medium.eot') format('embedded-opentype'),
url('futurastd-medium.woff') format('woff'),
url('futurastd-medium.ttf') format('truetype'),
url('futurastd-medium.svg#FuturaStdMedium') format('svg');
}

View File

@ -0,0 +1,913 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg>
<metadata>
Created by FontForge 20110222 at Mon Aug 4 15:25:24 2014
By Orthosie Webhosting
Copyright (c) 1987, 1991, 1993, 2002 Adobe Systems Incorporated. All Rights Reserved.
</metadata>
<defs>
<font id="FuturaStdMedium" horiz-adv-x="578" >
<font-face
font-family="FuturaStdMedium"
font-weight="500"
font-stretch="normal"
units-per-em="1000"
panose-1="2 11 5 2 2 2 4 2 3 3"
ascent="825"
descent="-175"
x-height="468"
cap-height="754"
bbox="-163 -268 1113 995"
underline-thickness="50"
underline-position="-50"
unicode-range="U+0020-FB02"
/>
<missing-glyph horiz-adv-x="500"
d="M0 0v700h500v-700h-500zM250 395l170 255h-340zM280 350l170 -255v510zM80 50h340l-170 255zM50 605v-510l170 255z" />
<glyph glyph-name="fi" unicode="fi" horiz-adv-x="512"
d="M430 468v-468h-90v468h90zM385 745q26 0 44 -18.5t18 -44.5q0 -25 -18 -43t-44 -18t-44 18t-18 43q0 26 18 44.5t44 18.5zM294 868v-91q-43 19 -60 19q-18 0 -31 -9.5t-19 -21.5t-9.5 -32.5t-4 -32t-0.5 -31.5v-201h124v-84h-124v-384h-90v384h-41v84h41v228
q0 184 151 184q33 0 63 -12z" />
<glyph glyph-name="fl" unicode="fl" horiz-adv-x="497"
d="M431 868v-868h-90v868h90zM294 868v-91q-43 19 -60 19q-18 0 -31 -9.5t-19 -21.5t-9.5 -32.5t-4 -32t-0.5 -31.5v-201h124v-84h-124v-384h-90v384h-41v84h41v228q0 184 151 184q33 0 63 -12z" />
<glyph glyph-name=".notdef" horiz-adv-x="500"
d="M0 0v700h500v-700h-500zM250 395l170 255h-340zM280 350l170 -255v510zM80 50h340l-170 255zM50 605v-510l170 255z" />
<glyph glyph-name=".null" horiz-adv-x="0"
/>
<glyph glyph-name="nonmarkingreturn" horiz-adv-x="333"
/>
<glyph glyph-name="space" unicode=" " horiz-adv-x="289"
/>
<glyph glyph-name="exclam" unicode="!" horiz-adv-x="321"
d="M161 100q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5zM116 174v580h90v-580h-90z" />
<glyph glyph-name="quotedbl" unicode="&#x22;" horiz-adv-x="439"
d="M90 754h98l-18 -328h-62zM251 754h98l-18 -328h-62z" />
<glyph glyph-name="numbersign" unicode="#"
d="M217 718h77l-36 -194h124l35 194h79l-35 -194h92v-80h-107l-27 -154h101v-80h-117l-38 -210h-76l37 210h-123l-40 -210h-75l37 210h-100v80h115l27 154h-105v80h119zM245 444l-27 -154h123l27 154h-123z" />
<glyph glyph-name="dollar" unicode="$"
d="M333 349v-271q46 10 75.5 49t29.5 87q0 80 -105 135zM283 770v90h50v-90q114 -11 171 -116l-79 -45q-29 55 -92 74v-235q90 -39 142.5 -92.5t52.5 -137.5q0 -82 -57.5 -152.5t-137.5 -81.5v-95h-50v95q-87 1 -153 62t-80 148l90 19q13 -66 46 -99.5t97 -41.5v300l-36 18
q-70 36 -107 76t-37 107q0 75 52.5 133t127.5 64zM283 472v211q-40 -6 -66.5 -35t-26.5 -68q0 -71 93 -108z" />
<glyph glyph-name="percent" unicode="%" horiz-adv-x="708"
d="M193 710q-47 0 -81.5 -33t-34.5 -79q0 -45 34.5 -78t81.5 -33t81.5 33t34.5 78q0 46 -34.5 79t-81.5 33zM552 770l45 -26l-440 -760l-46 25zM516 267q-47 0 -81.5 -33t-34.5 -79q0 -45 34.5 -78t81.5 -33t81.5 33t34.5 78q0 46 -34.5 79t-81.5 33zM193 770
q72 0 124 -50.5t52 -121.5t-52.5 -121t-123.5 -50t-123.5 50t-52.5 121t52 121.5t124 50.5zM516 327q72 0 124 -50.5t52 -121.5t-52.5 -121t-123.5 -50t-123.5 50t-52.5 121t52 121.5t124 50.5z" />
<glyph glyph-name="ampersand" unicode="&#x26;" horiz-adv-x="692"
d="M287 372l-9 -6q-1 -1 -20 -14t-24 -16.5t-21.5 -16.5t-23 -19.5t-18.5 -19.5t-16.5 -23t-9 -23.5t-4.5 -26.5q0 -54 43 -96.5t97 -42.5q33 0 67 17t55 35t51 48zM307 490l12 8q4 3 19.5 14.5t21.5 17t17.5 17t17 20t10 21.5t4.5 26q0 39 -24.5 60.5t-63.5 21.5
q-35 0 -59.5 -22.5t-24.5 -57.5q0 -18 8 -36.5t14.5 -28t22.5 -29.5zM592 0l-82 102q-100 -118 -226 -118q-96 0 -163.5 63t-67.5 159q0 65 33.5 109t98.5 91l47 34q-83 87 -83 165q0 76 49 120.5t125 44.5q72 0 123 -42.5t51 -114.5q0 -30 -11.5 -57.5t-34.5 -52t-42 -40.5
t-49 -38l157 -190l88 102l60 -62l-92 -108l135 -167h-116z" />
<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="277"
d="M90 754h98l-18 -328h-62z" />
<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="292"
d="M161 809l74 -55q-86 -180 -86 -446t86 -446l-74 -55q-52 103 -78 236.5t-26 264.5t26 265t78 236z" />
<glyph glyph-name="parenright" unicode=")" horiz-adv-x="292"
d="M57 754l74 55q52 -102 78 -236t26 -265t-26 -264.5t-78 -236.5l-74 55q86 180 86 446t-86 446z" />
<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="432"
d="M184 754h69v-95l81 48l35 -59l-85 -50l85 -50l-35 -58l-81 50v-96h-69v97l-87 -49l-34 57l85 49l-84 50l31 57l89 -49v98z" />
<glyph glyph-name="plus" unicode="+"
d="M246 512h86v-213h213v-86h-213v-213h-86v213h-213v86h213v213z" />
<glyph glyph-name="comma" unicode="," horiz-adv-x="289"
d="M164 119l78 -31l-133 -267l-55 23z" />
<glyph glyph-name="hyphen" unicode="-" horiz-adv-x="332"
d="M57 358h219v-75h-219v75z" />
<glyph glyph-name="period" unicode="." horiz-adv-x="289"
d="M145 100q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5z" />
<glyph glyph-name="slash" unicode="/" horiz-adv-x="551"
d="M448 868l72 -32l-417 -962l-71 32z" />
<glyph glyph-name="zero" unicode="0"
d="M289 -16q-56 0 -101.5 26.5t-75 67.5t-49.5 94t-28.5 104.5t-8.5 100.5q0 63 14.5 127.5t43.5 126t82.5 100.5t122.5 39t122.5 -39t82.5 -100.5t43.5 -126t14.5 -127.5q0 -49 -8.5 -100.5t-28.5 -104.5t-49.5 -94t-75 -67.5t-101.5 -26.5zM289 690q-48 0 -83.5 -33.5
t-54 -84.5t-27 -100.5t-8.5 -93.5t8.5 -93t27 -100t54 -84t83.5 -33t83.5 33t54 84t27 100t8.5 93t-8.5 93.5t-27 100.5t-54 84.5t-83.5 33.5z" />
<glyph glyph-name="one" unicode="1"
d="M254 668h-131l52 86h169v-754h-90v668z" />
<glyph glyph-name="two" unicode="2"
d="M228 86h304v-86h-487l330 405q67 82 67 135q0 59 -44.5 101.5t-103.5 42.5q-57 0 -99 -40.5t-46 -97.5h-94q11 102 74.5 163t164.5 61q98 0 168 -64.5t70 -161.5q0 -86 -56 -155z" />
<glyph glyph-name="three" unicode="3"
d="M275 360v78q148 0 148 121q0 57 -37 93t-94 36q-51 0 -84 -29.5t-41 -78.5h-93q13 93 70.5 141.5t150.5 48.5t155.5 -55.5t62.5 -147.5q0 -116 -96 -170q107 -51 107 -187q0 -103 -68.5 -164.5t-172.5 -61.5q-92 0 -159 56t-71 146h91q7 -54 48.5 -87t97.5 -33
q62 0 103 43t41 105q0 71 -44.5 111t-114.5 35z" />
<glyph glyph-name="four" unicode="4"
d="M469 192h86v-82h-86v-110h-90v110h-372l462 676v-594zM379 192v311h-2l-212 -311h214z" />
<glyph glyph-name="five" unicode="5"
d="M528 668h-237l-47 -155l53 3q106 0 174 -78t68 -186q0 -118 -80.5 -193t-198.5 -75q-71 0 -134.5 35.5t-95.5 96.5l70 66q17 -47 66.5 -79.5t100.5 -32.5q76 0 129 54.5t53 130.5q0 73 -53.5 126t-126.5 53q-40 0 -78.5 -18t-62.5 -49h-18l116 387h302v-86z" />
<glyph glyph-name="six" unicode="6"
d="M379 770l68 -46l-201 -272l2 -2q36 18 74 18q91 0 154.5 -71.5t63.5 -164.5q0 -103 -73 -175.5t-176 -72.5q-99 0 -175 71.5t-76 169.5q0 89 82 199zM290 68q64 0 112 46t48 108q0 68 -49 115t-111 47t-111 -48t-49 -109q0 -65 47.5 -112t112.5 -47z" />
<glyph glyph-name="seven" unicode="7"
d="M437 668h-390v86h543l-470 -770l-73 45z" />
<glyph glyph-name="eight" unicode="8"
d="M289 352q-58 0 -102 -41.5t-44 -100.5q0 -56 45 -99t101 -43t101 43t45 99q0 59 -44 100.5t-102 41.5zM53 210q0 63 31 112t88 69q-99 56 -99 169q0 91 62.5 150.5t153.5 59.5t153.5 -59.5t62.5 -150.5q0 -113 -99 -169q57 -20 88 -69t31 -112q0 -102 -68.5 -164
t-167.5 -62t-167.5 62t-68.5 164zM289 690q-51 0 -89.5 -38t-38.5 -92q0 -45 40.5 -86.5t87.5 -41.5t87.5 41.5t40.5 86.5q0 54 -38.5 92t-89.5 38z" />
<glyph glyph-name="nine" unicode="9"
d="M213 -16l-68 47l201 271l-2 2q-28 -14 -73 -14q-92 0 -155.5 70t-63.5 162q0 103 73 175.5t176 72.5q99 0 175 -71.5t76 -169.5q0 -89 -82 -199zM302 370q70 0 115 47t45 111q0 61 -46.5 109.5t-107.5 48.5q-68 0 -117 -47t-49 -111q0 -65 49.5 -111.5t110.5 -46.5z" />
<glyph glyph-name="colon" unicode=":" horiz-adv-x="289"
d="M145 100q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5zM145 482q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5z" />
<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="289"
d="M156 119l78 -31l-133 -267l-55 23zM192 482q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5z" />
<glyph glyph-name="less" unicode="&#x3c;"
d="M545 498v-94l-384 -148l384 -148v-94l-512 207v70z" />
<glyph glyph-name="equal" unicode="="
d="M33 385h512v-86h-512v86zM33 213h512v-86h-512v86z" />
<glyph glyph-name="greater" unicode="&#x3e;"
d="M33 404v94l512 -207v-70l-512 -207v94l384 148z" />
<glyph glyph-name="question" unicode="?" horiz-adv-x="453"
d="M301 345h91q3 -64 -47 -112.5t-115 -48.5q-67 0 -114 46.5t-47 113.5q0 64 33 94.5t93 52.5q5 2 20 7.5t21 7.5t19 7.5t18 9t15 10t14 12.5t9 14t7 17t2 20q0 41 -26 65t-66 24q-35 0 -60.5 -25.5t-25.5 -60.5q0 -10 6 -32h-94l-2 33q-4 71 51 120.5t128 49.5
q76 0 128 -51t52 -126q0 -78 -54 -124q-31 -27 -124 -56q-73 -22 -73 -73q0 -30 20 -51t50 -21q32 0 52 22.5t19 54.5zM230 100q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5z" />
<glyph glyph-name="at" unicode="@" horiz-adv-x="800"
d="M503 372q7 60 -21 93.5t-81 33.5q-58 0 -95 -47t-37 -106q0 -46 27.5 -80t72.5 -34q62 0 94 39.5t40 100.5zM528 506l14 62h71l-50 -257q-9 -25 -8.5 -55.5t22.5 -30.5q36 0 72 60t36 132q0 124 -76.5 198.5t-193.5 74.5q-126 0 -212.5 -91.5t-86.5 -221.5
q0 -135 92.5 -224t223.5 -89q129 0 186 48l75 -60q-64 -34 -122 -51t-147 -17q-163 0 -275.5 112t-112.5 281q0 167 110.5 280t271.5 113q139 0 235 -87q112 -97 112 -230q0 -131 -62 -212q-34 -45 -75 -67t-79 -20q-44 2 -54 62q-62 -62 -136 -62q-67 0 -117.5 54.5
t-50.5 130.5q0 95 57 166.5t147 71.5q78 0 133 -71z" />
<glyph glyph-name="A" unicode="A" horiz-adv-x="703"
d="M525 189h-346l-86 -189h-101l360 786l360 -786h-101zM486 275l-134 305l-134 -305h268z" />
<glyph glyph-name="B" unicode="B" horiz-adv-x="535"
d="M158 670v-250h24q78 0 120 26t42 100q0 73 -41.5 98.5t-118.5 25.5h-26zM158 345v-261h72q178 0 178 133q0 38 -17.5 64.5t-47.5 39.5t-61 18.5t-66 5.5h-58zM64 0v754h92q58 0 104 -9t86.5 -30.5t63 -64t22.5 -103.5q0 -43 -22 -84.5t-59 -58.5v-2q65 -12 108 -67.5
t43 -123.5q0 -106 -76 -158.5t-186 -52.5h-176z" />
<glyph glyph-name="C" unicode="C" horiz-adv-x="661"
d="M621 719v-109q-83 74 -199 74q-125 0 -211.5 -90.5t-86.5 -217.5q0 -125 85.5 -215.5t210.5 -90.5q114 0 201 78v-111q-90 -53 -198 -53q-162 0 -277.5 113t-115.5 276q0 167 117 282t284 115q107 0 190 -51z" />
<glyph glyph-name="D" unicode="D" horiz-adv-x="665"
d="M64 0v754h156q183 0 303 -96.5t120 -276.5q0 -185 -119 -283t-307 -98h-153zM158 668v-582h33q76 0 138 15t112.5 48t79 91t28.5 137q0 80 -28.5 138t-79.5 90.5t-112.5 47.5t-137.5 15h-33z" />
<glyph glyph-name="E" unicode="E" horiz-adv-x="521"
d="M72 0v754h405v-86h-311v-211h302v-86h-302v-285h311v-86h-405z" />
<glyph glyph-name="F" unicode="F" horiz-adv-x="474"
d="M436 668h-271v-212h262v-86h-262v-370h-94v754h365v-86z" />
<glyph glyph-name="G" unicode="G" horiz-adv-x="780"
d="M460 380h299v-30q0 -157 -100 -261.5t-257 -104.5t-269 116.5t-112 274.5q0 163 114.5 279t276.5 116q89 0 170.5 -38.5t136.5 -107.5l-66 -63q-41 56 -105 89.5t-132 33.5q-126 0 -213.5 -89.5t-87.5 -216.5q0 -121 86.5 -214.5t206.5 -93.5q90 0 167 67t80 157h-195v86
z" />
<glyph glyph-name="H" unicode="H" horiz-adv-x="675"
d="M158 450h359v304h94v-754h-94v362h-359v-362h-94v754h94v-304z" />
<glyph glyph-name="I" unicode="I" horiz-adv-x="232"
d="M163 754v-754h-94v754h94z" />
<glyph glyph-name="J" unicode="J" horiz-adv-x="362"
d="M209 754h94v-479q0 -61 -7.5 -107.5t-28 -91t-63 -68.5t-105.5 -24t-118 33l47 80q33 -25 75 -25q22 0 39.5 8t28.5 18t19 30t11.5 34t5.5 40t2 37v36v479z" />
<glyph glyph-name="K" unicode="K" horiz-adv-x="600"
d="M166 427l320 327h123l-339 -339l345 -415h-127l-284 351l-38 -36v-315h-94v754h94v-327z" />
<glyph glyph-name="L" unicode="L" horiz-adv-x="385"
d="M166 754v-668h229v-86h-323v754h94z" />
<glyph glyph-name="M" unicode="M" horiz-adv-x="851"
d="M426 -16l-226 514h-2l-88 -498h-97l154 786l259 -594l259 594l154 -786h-97l-88 498h-2z" />
<glyph glyph-name="N" unicode="N" horiz-adv-x="785"
d="M63 0v790l566 -593v557h94v-785l-566 593v-562h-94z" />
<glyph glyph-name="O" unicode="O" horiz-adv-x="828"
d="M414 770q162 0 278.5 -115.5t116.5 -277.5q0 -167 -115 -280t-280 -113t-280 113t-115 280q0 162 116.5 277.5t278.5 115.5zM414 72q123 0 212 88.5t89 216.5q0 127 -85.5 216t-215.5 89t-215.5 -89t-85.5 -216q0 -128 89 -216.5t212 -88.5z" />
<glyph glyph-name="P" unicode="P" horiz-adv-x="495"
d="M166 316v-316h-94v754h108q167 0 235.5 -54.5t68.5 -163.5q0 -112 -73.5 -166t-190.5 -54h-54zM166 670v-270h30q41 0 72.5 5t62.5 18.5t48 42.5t17 72q0 42 -18 70t-51 40.5t-64 17t-72 4.5h-25z" />
<glyph glyph-name="Q" unicode="Q" horiz-adv-x="828"
d="M808 -16h-114l-65 67q-97 -67 -215 -67q-165 0 -280 113t-115 280q0 162 116.5 277.5t278.5 115.5t278.5 -115.5t116.5 -277.5q0 -80 -31 -152.5t-87 -125.5zM508 284l119 -118q42 37 65 95.5t23 115.5q0 127 -85.5 216t-215.5 89t-215.5 -89t-85.5 -216
q0 -128 89 -216.5t212 -88.5q82 0 150 43l-173 169h117z" />
<glyph glyph-name="R" unicode="R" horiz-adv-x="543"
d="M303 328l238 -328h-114l-222 319h-39v-319h-94v754h114q43 0 69.5 -1.5t64 -9.5t65.5 -24q46 -27 72.5 -76t26.5 -104q0 -82 -50 -141.5t-131 -69.5zM166 670v-273h30q41 0 72.5 5t62.5 18.5t48 42.5t17 72q0 135 -205 135h-25z" />
<glyph glyph-name="S" unicode="S" horiz-adv-x="537"
d="M482 656l-75 -45q-42 71 -121 71q-48 0 -87 -30t-39 -77q0 -68 105 -108l54 -21q90 -35 138.5 -87t48.5 -140q0 -102 -69.5 -168.5t-171.5 -66.5q-91 0 -156 59.5t-77 151.5l95 20q-1 -61 41.5 -102t104.5 -41q60 0 99.5 43.5t39.5 103.5q0 55 -34.5 86.5t-95.5 56.5
l-52 22q-77 33 -120.5 76t-43.5 115q0 88 66 141.5t156 53.5q130 0 194 -114z" />
<glyph glyph-name="T" unicode="T" horiz-adv-x="456"
d="M275 668v-668h-94v668h-179v86h452v-86h-179z" />
<glyph glyph-name="U" unicode="U" horiz-adv-x="669"
d="M59 754h94v-445q0 -237 182 -237t182 237v445h94v-477q0 -128 -74.5 -210.5t-201.5 -82.5t-201.5 82.5t-74.5 210.5v477z" />
<glyph glyph-name="V" unicode="V" horiz-adv-x="640"
d="M96 754l225 -558l224 558h103l-327 -794l-328 794h103z" />
<glyph glyph-name="W" unicode="W" horiz-adv-x="1027"
d="M90 754l211 -540l213 556l213 -556l211 540h102l-313 -784l-213 553l-213 -553l-313 784h102z" />
<glyph glyph-name="X" unicode="X" horiz-adv-x="574"
d="M237 395l-208 359h107l154 -275l164 275h107l-217 -359l229 -395h-105l-178 309l-185 -309h-105z" />
<glyph glyph-name="Y" unicode="Y" horiz-adv-x="573"
d="M240 328l-246 426h108l185 -322l185 322h108l-246 -426v-328h-94v328z" />
<glyph glyph-name="Z" unicode="Z" horiz-adv-x="552"
d="M162 86h382v-86h-535l382 668h-328v86h481z" />
<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="311"
d="M153 725v-834h98v-84h-190v1002h190v-84h-98z" />
<glyph glyph-name="backslash" unicode="\" horiz-adv-x="551"
d="M31 868h84l404 -868h-84z" />
<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="311"
d="M158 -109v834h-98v84h190v-1002h-190v84h98z" />
<glyph glyph-name="asciicircum" unicode="^"
d="M33 308l200 446h112l200 -446h-94l-162 362l-163 -362h-93z" />
<glyph glyph-name="underscore" unicode="_" horiz-adv-x="500"
d="M500 -75v-50h-500v50h500z" />
<glyph glyph-name="grave" unicode="`" horiz-adv-x="360"
d="M76 690l83 44l125 -166l-44 -27z" />
<glyph glyph-name="a" unicode="a" horiz-adv-x="556"
d="M264 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM501 468v-468h-90v73h-2q-60 -89 -159 -89q-103 0 -163.5 73.5t-60.5 179.5q0 100 61 172.5t160 72.5q101 0 162 -92h2v78h90z" />
<glyph glyph-name="b" unicode="b" horiz-adv-x="556"
d="M288 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM55 0v868h90v-478h2q61 92 163 92q98 0 159 -72.5t61 -172.5q0 -106 -60 -179.5t-164 -73.5q-48 0 -89.5 24t-69.5 65h-2v-73h-90z" />
<glyph glyph-name="c" unicode="c" horiz-adv-x="441"
d="M406 451v-116q-55 63 -134 63q-65 0 -110.5 -49t-45.5 -115q0 -72 45.5 -119t116.5 -47q73 0 128 62v-115q-58 -31 -129 -31q-104 0 -177.5 71t-73.5 175q0 108 73.5 180t182.5 72q71 0 124 -31z" />
<glyph glyph-name="d" unicode="d" horiz-adv-x="556"
d="M264 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM411 0v73h-2q-28 -41 -69.5 -65t-89.5 -24q-104 0 -164 73.5t-60 179.5q0 100 61 172.5t159 72.5q102 0 163 -92h2v478h90v-868h-90z" />
<glyph glyph-name="e" unicode="e" horiz-adv-x="488"
d="M473 219h-357q1 -63 40 -109t101 -46q49 0 80.5 22.5t59.5 68.5l76 -43q-33 -60 -90.5 -94t-126.5 -34q-105 0 -167.5 70t-62.5 176q0 112 59 182t169 70q107 0 163 -69.5t56 -179.5v-14zM121 287h262q-8 54 -42 85.5t-87 31.5q-52 0 -88.5 -33t-44.5 -84z" />
<glyph glyph-name="f" unicode="f" horiz-adv-x="275"
d="M294 868v-91q-43 19 -60 19q-18 0 -31 -9.5t-19 -21.5t-9.5 -32.5t-4 -32t-0.5 -31.5v-201h124v-84h-124v-384h-90v384h-41v84h41v228q0 184 151 184q33 0 63 -12z" />
<glyph glyph-name="g" unicode="g" horiz-adv-x="555"
d="M263 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM500 468v-459q0 -133 -50 -205t-178 -72q-99 0 -162 57t-64 155h90q0 -62 38.5 -97t101.5 -35q77 0 105.5 45t28.5 127v89h-2q-28 -41 -69.5 -65
t-89.5 -24q-104 0 -164 73.5t-60 179.5q0 100 61 172.5t159 72.5q103 0 163 -94h2v80h90z" />
<glyph glyph-name="h" unicode="h" horiz-adv-x="523"
d="M62 868h90v-463h2q20 37 58.5 57t82.5 20q92 0 129 -54t37 -149v-279h-90v268q0 69 -19.5 101.5t-83.5 32.5q-28 0 -49 -7t-33 -23t-19.5 -30.5t-10.5 -41t-3.5 -41.5t-0.5 -44v-215h-90v868z" />
<glyph glyph-name="i" unicode="i" horiz-adv-x="254"
d="M172 468v-468h-90v468h90zM127 745q26 0 44 -18.5t18 -44.5q0 -25 -18 -43t-44 -18t-44 18t-18 43q0 26 18 44.5t44 18.5z" />
<glyph glyph-name="j" unicode="j" horiz-adv-x="254"
d="M172 468v-736h-90v736h90zM127 745q26 0 44 -18.5t18 -44.5q0 -25 -18 -43t-44 -18t-44 18t-18 43q0 26 18 44.5t44 18.5z" />
<glyph glyph-name="k" unicode="k" horiz-adv-x="462"
d="M158 868v-576l176 176h119l-200 -194l220 -274h-117l-167 213l-31 -31v-182h-90v868h90z" />
<glyph glyph-name="l" unicode="l" horiz-adv-x="222"
d="M156 868v-868h-90v868h90z" />
<glyph glyph-name="m" unicode="m" horiz-adv-x="767"
d="M149 468v-59h2q20 32 53.5 52.5t70.5 20.5q87 0 135 -83q22 38 61 60.5t83 22.5q155 0 155 -202v-280h-90v265q0 27 -2.5 47.5t-11 43t-27 34.5t-46.5 12t-47.5 -11.5t-30 -28t-16.5 -41.5t-7.5 -45t-1.5 -46v-230h-90v248q0 24 -1 40t-5.5 40t-13 38t-25.5 25t-41 11
q-34 0 -56.5 -15.5t-32 -44t-12.5 -53.5t-3 -59v-230h-90v468h90z" />
<glyph glyph-name="n" unicode="n" horiz-adv-x="523"
d="M152 468v-63h2q20 37 58.5 57t82.5 20q92 0 129 -54t37 -149v-279h-90v268q0 69 -19.5 101.5t-83.5 32.5q-28 0 -49 -7t-33 -23t-19.5 -30.5t-10.5 -41t-3.5 -41.5t-0.5 -44v-215h-90v468h90z" />
<glyph glyph-name="o" unicode="o" horiz-adv-x="540"
d="M270 482q105 0 177.5 -72t72.5 -177t-72.5 -177t-177.5 -72t-177.5 72t-72.5 177t72.5 177t177.5 72zM270 396q-66 0 -113 -48t-47 -115q0 -66 47 -114.5t113 -48.5t113 48.5t47 114.5q0 67 -47 115t-113 48z" />
<glyph glyph-name="p" unicode="p" horiz-adv-x="556"
d="M288 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM145 468v-78h2q61 92 163 92q98 0 159 -72.5t61 -172.5q0 -106 -60 -179.5t-164 -73.5q-48 0 -89.5 24t-69.5 65h-2v-341h-90v736h90z" />
<glyph glyph-name="q" unicode="q" horiz-adv-x="556"
d="M264 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM501 468v-736h-90v341h-2q-28 -41 -69.5 -65t-89.5 -24q-104 0 -164 73.5t-60 179.5q0 100 61 172.5t159 72.5q102 0 163 -92h2v78h90z" />
<glyph glyph-name="r" unicode="r" horiz-adv-x="351"
d="M158 468v-76h3q17 42 50.5 66t77.5 24q38 0 74 -23l-41 -82q-22 19 -55 19q-35 0 -58 -14.5t-33.5 -41t-14 -52t-3.5 -58.5v-230h-90v468h90z" />
<glyph glyph-name="s" unicode="s" horiz-adv-x="384"
d="M323 400l-73 -39q-20 41 -60 41q-19 0 -34 -13.5t-15 -32.5q0 -9 2.5 -16.5t10 -14t13 -11.5t18 -11.5t19.5 -10t23.5 -10.5t22.5 -10q50 -23 79 -53t29 -80q0 -66 -47.5 -110.5t-113.5 -44.5q-53 0 -98.5 28.5t-63.5 76.5l77 35q33 -60 85 -60q29 0 50 18.5t21 47.5
t-33 51l-88 47q-46 25 -68 49.5t-22 68.5q0 57 40.5 96.5t97.5 39.5q88 0 128 -82z" />
<glyph glyph-name="t" unicode="t" horiz-adv-x="240"
d="M165 384v-384h-90v384h-49v84h49v179h90v-179h88v-84h-88z" />
<glyph glyph-name="u" unicode="u" horiz-adv-x="512"
d="M58 468h90v-259q0 -65 23.5 -103t84.5 -38t84.5 38t23.5 103v259h90v-269q0 -100 -49 -157.5t-149 -57.5t-149 57.5t-49 157.5v269z" />
<glyph glyph-name="v" unicode="v" horiz-adv-x="445"
d="M88 468l134 -292l135 292h101l-236 -484l-235 484h101z" />
<glyph glyph-name="w" unicode="w" horiz-adv-x="718"
d="M86 468l136 -298l138 324l137 -324l136 298h102l-238 -484l-137 313l-138 -313l-238 484h102z" />
<glyph glyph-name="x" unicode="x" horiz-adv-x="489"
d="M195 254l-168 214h106l111 -151l121 151h109l-172 -214l201 -254h-105l-154 190l-149 -190h-109z" />
<glyph glyph-name="y" unicode="y" horiz-adv-x="484"
d="M201 80l-214 388h105l158 -297l147 297h101l-379 -736h-102z" />
<glyph glyph-name="z" unicode="z" horiz-adv-x="495"
d="M177 84h304v-84h-479l317 384h-263v84h438z" />
<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="334"
d="M48 271v73q75 33 75 151v182q0 55 29.5 93.5t55.5 38.5h78v-84h-40q-15 0 -22 -10t-8 -20t-1 -32v-184q0 -52 -18 -93.5t-31.5 -55.5t-26.5 -23q8 -5 18 -15t24.5 -29.5t24 -53t9.5 -73.5v-184q0 -22 1 -32t8 -20t22 -10h40v-84h-78q-26 0 -55.5 38.5t-29.5 93.5v182
q0 118 -75 151z" />
<glyph glyph-name="bar" unicode="|" horiz-adv-x="570"
d="M328 786v-1000h-86v1000h86z" />
<glyph glyph-name="braceright" unicode="}" horiz-adv-x="334"
d="M286 344v-73q-75 -33 -75 -151v-182q0 -55 -29.5 -93.5t-55.5 -38.5h-78v84h40q15 0 22 10t8 20t1 32v184q0 40 9.5 73.5t24 53t24.5 29.5t18 15q-13 9 -26.5 23t-31.5 55.5t-18 93.5v184q0 22 -1 32t-8 20t-22 10h-40v84h78q26 0 55.5 -38.5t29.5 -93.5v-182
q0 -118 75 -151z" />
<glyph glyph-name="asciitilde" unicode="~"
d="M478 334l67 -50q-67 -122 -152 -122q-40 0 -115 51q-7 5 -21 14.5t-21 14.5t-17 11t-17.5 8.5t-13.5 2.5q-24 0 -45 -20t-47 -62l-63 45q22 32 30.5 43t30.5 35.5t44.5 34.5t47.5 10q55 0 122 -51q6 -5 18.5 -14.5t19 -14.5t15.5 -11t16.5 -8.5t14.5 -2.5q24 0 39.5 17
t39.5 57q5 8 7 12z" />
<glyph glyph-name="uni00A0" unicode="&#xa0;" horiz-adv-x="289"
/>
<glyph glyph-name="exclamdown" unicode="&#xa1;" horiz-adv-x="321"
d="M161 508q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5zM116 323h90v-581h-90v581z" />
<glyph glyph-name="cent" unicode="&#xa2;"
d="M356 704v-76q74 -4 122 -31v-115h-2q-47 61 -120 63v-328q73 10 122 62v-117q-50 -24 -105 -28l-17 -1v-85h-48v89q-91 14 -149.5 81t-58.5 159q0 94 58 164.5t150 84.5v78h48zM308 220v319q-51 -6 -85.5 -56t-34.5 -102q0 -56 33 -103t87 -58z" />
<glyph glyph-name="sterling" unicode="&#xa3;"
d="M90 -16l-79 40q31 54 65.5 82.5t88.5 30.5q30 100 -8 164h-129v58h100q-58 110 -58 180q0 95 75.5 163t171.5 68q105 0 170 -64.5t70 -169.5l-90 -34v28q0 63 -41.5 107.5t-104.5 44.5q-61 0 -111 -47.5t-50 -103.5q0 -24 8 -50t16.5 -42t24.5 -42.5t22 -37.5h148v-58
h-124q26 -84 0 -172l74 -26q6 -2 27.5 -11t37 -13.5t29.5 -4.5q19 0 36.5 13.5t26 26t20.5 34.5l75 -46q-23 -53 -62.5 -85.5t-93.5 -32.5q-48 0 -131 33q-79 32 -116 32q-62 0 -88 -65z" />
<glyph glyph-name="currency" unicode="&#xa4;"
d="M483 546l60 -60l-41 -44q42 -66 42 -142t-42 -142l41 -44l-60 -60l-46 44q-63 -48 -148 -48t-148 48l-46 -44l-60 60l41 44q-42 66 -42 142t42 142l-41 44l60 60l46 -44q63 48 148 48t148 -48zM289 130q72 0 123 50t52 120q1 74 -49 122t-126 48t-126 -48t-49 -122
q2 -70 52.5 -120t122.5 -50z" />
<glyph glyph-name="yen" unicode="&#xa5;"
d="M336 260v-260h-94v260h-236v58h236v10l-54 94h-182v58h148l-158 274h108l185 -322l185 322h108l-158 -274h148v-58h-181l-55 -94v-10h236v-58h-236z" />
<glyph glyph-name="brokenbar" unicode="&#xa6;" horiz-adv-x="570"
d="M328 161v-250h-86v250h86zM328 661v-250h-86v250h86z" />
<glyph glyph-name="section" unicode="&#xa7;"
d="M214 335l175 -87q27 17 43.5 46t16.5 59q0 32 -19.5 51t-56.5 37l-184 93q-27 -17 -43.5 -46t-16.5 -60q0 -18 6.5 -32.5t22 -26t25.5 -18t31 -16.5zM310 192l-141 69q-34 17 -51.5 27.5t-38.5 29.5t-30 43t-9 57q0 90 96 162q-44 50 -44 111q0 75 57.5 126t133.5 51
q80 0 137 -45t62 -123h-87q-2 41 -35.5 65t-76.5 24q-42 0 -71.5 -29t-29.5 -71q0 -36 22.5 -59t62.5 -42l133 -67q31 -16 49 -26.5t42 -29t35.5 -42t11.5 -51.5q0 -49 -24.5 -94t-64.5 -75q53 -50 53 -122q0 -86 -63 -139.5t-150 -53.5q-99 0 -162.5 58t-63.5 157v15h89
q-2 -62 36 -105t100 -43q49 0 86.5 32t37.5 81q0 21 -8.5 38t-26.5 31t-30 21t-37 19z" />
<glyph glyph-name="dieresis" unicode="&#xa8;" horiz-adv-x="470"
d="M130 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 17.5t-17.5 43.5q0 25 18 42.5t43 17.5zM341 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 17.5t-18 43.5q0 25 18 42.5t43 17.5z" />
<glyph glyph-name="copyright" unicode="&#xa9;" horiz-adv-x="800"
d="M400 -16q-165 0 -279.5 114.5t-114.5 278.5t114.5 278.5t279.5 114.5t279.5 -114.5t114.5 -278.5t-114.5 -278.5t-279.5 -114.5zM400 706q-136 0 -233 -95.5t-97 -233.5t97 -233.5t233 -95.5t233 95.5t97 233.5t-97 233.5t-233 95.5zM600 458h-61q-9 41 -42 63t-83 22
q-76 0 -114.5 -47.5t-38.5 -113.5q0 -72 41 -118t114 -46q102 0 123 89h61q-9 -69 -61.5 -111t-122.5 -42q-98 0 -158.5 65t-60.5 161q0 100 59 163.5t159 63.5q71 0 121.5 -40t63.5 -109z" />
<glyph glyph-name="ordfeminine" unicode="&#xaa;" horiz-adv-x="334"
d="M167 519q46 0 72.5 29.5t26.5 72.5t-26.5 72t-72.5 29q-43 0 -69.5 -30t-26.5 -71q0 -42 26 -72t70 -30zM322 761v-280h-59v43h-2q-39 -53 -103 -53q-67 0 -106.5 44t-39.5 108q0 60 40 103.5t104 43.5t106 -55h1v46h59z" />
<glyph glyph-name="guillemotleft" unicode="&#xab;" horiz-adv-x="523"
d="M311 320l149 -191l-56 -41l-182 232l182 240l56 -41zM119 320l149 -191l-56 -41l-182 232l182 240l56 -41z" />
<glyph glyph-name="logicalnot" unicode="&#xac;"
d="M459 115v184h-426v86h512v-270h-86z" />
<glyph glyph-name="uni00AD" unicode="&#xad;" horiz-adv-x="332"
d="M57 358h219v-75h-219v75z" />
<glyph glyph-name="registered" unicode="&#xae;" horiz-adv-x="800"
d="M400 -16q-165 0 -279.5 114.5t-114.5 278.5t114.5 278.5t279.5 114.5t279.5 -114.5t114.5 -278.5t-114.5 -278.5t-279.5 -114.5zM400 706q-136 0 -233 -95.5t-97 -233.5t97 -233.5t233 -95.5t233 95.5t97 233.5t-97 233.5t-233 95.5zM468 357l112 -204h-73l-113 204h-82
v-204h-64v442h186q152 0 152 -117q0 -60 -34 -89.5t-84 -31.5zM422 531h-110v-110h68q7 0 26.5 -0.5t28.5 0t25.5 1.5t25 4t18.5 8.5t14 15t4 21.5q0 20 -7.5 33t-23 18.5t-30.5 7t-39 1.5z" />
<glyph glyph-name="macron" unicode="&#xaf;" horiz-adv-x="500"
d="M70 694h361v-68h-361v68z" />
<glyph glyph-name="degree" unicode="&#xb0;" horiz-adv-x="400"
d="M350 620q0 -62 -44 -106t-106 -44t-106 44t-44 106q-1 62 43.5 106t106.5 44t106 -44t44 -106zM199 720q-42 0 -71 -29t-28 -71q0 -43 28.5 -71.5t71.5 -28.5q42 0 71 28.5t29 71.5q0 42 -29 71t-72 29z" />
<glyph glyph-name="plusminus" unicode="&#xb1;"
d="M33 0v86h512v-86h-512zM246 562h86v-173h213v-86h-213v-173h-86v173h-213v86h213v173z" />
<glyph glyph-name="twosuperior" unicode="&#xb2;" horiz-adv-x="346"
d="M144 360h188v-58h-317l215 243q38 44 38 81q0 33 -29 56.5t-62 23.5q-37 0 -61.5 -21t-26.5 -55h-67q7 61 48 97.5t107 36.5q63 0 109 -39t46 -97q0 -55 -33 -93z" />
<glyph glyph-name="threesuperior" unicode="&#xb3;" horiz-adv-x="346"
d="M163 518v58q43 0 68.5 17t25.5 50t-25 51t-58 18q-32 0 -53.5 -14t-21.5 -42h-67q9 55 46 84.5t98 29.5t103 -33.5t42 -88.5q0 -67 -66 -102q73 -32 73 -112q0 -62 -46 -99t-114 -37q-59 0 -102.5 33.5t-46.5 88.5h64q10 -64 90 -64q37 0 64 22t27 58q0 38 -29 61t-72 21
z" />
<glyph glyph-name="acute" unicode="&#xb4;" horiz-adv-x="360"
d="M201 734l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="mu" unicode="&#xb5;" horiz-adv-x="512"
d="M58 468h90v-259q0 -65 23.5 -103t84.5 -38t84.5 38t23.5 103v259h90v-269q0 -100 -49 -157.5t-149 -57.5q-56 0 -108 44v-296h-90v736z" />
<glyph glyph-name="paragraph" unicode="&#xb6;"
d="M538 754v-84h-61v-823h-84v823h-62v-823h-84v436q-86 0 -142.5 57t-63.5 157q-7 95 56.5 176t158.5 81h282z" />
<glyph glyph-name="periodcentered" unicode="&#xb7;" horiz-adv-x="289"
d="M145 314q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5z" />
<glyph glyph-name="cedilla" unicode="&#xb8;" horiz-adv-x="330"
d="M244 -46l-105 -135l-53 27l87 137z" />
<glyph glyph-name="onesuperior" unicode="&#xb9;" horiz-adv-x="346"
d="M151 696h-86l34 58h116v-452h-64v394z" />
<glyph glyph-name="ordmasculine" unicode="&#xba;" horiz-adv-x="324"
d="M162 770q68 0 115.5 -43t47.5 -107q0 -63 -47.5 -106t-115.5 -43t-115 43t-47 106q0 64 47 107t115 43zM162 718q-43 0 -73 -28.5t-30 -69.5q0 -39 30 -68t73 -29t73.5 29t30.5 68q0 41 -30.5 69.5t-73.5 28.5z" />
<glyph glyph-name="guillemotright" unicode="&#xbb;" horiz-adv-x="523"
d="M63 129l149 191l-149 199l56 41l182 -240l-182 -232zM255 129l149 191l-149 199l56 41l182 -240l-182 -232z" />
<glyph glyph-name="onequarter" unicode="&#xbc;" horiz-adv-x="867"
d="M778 124h49v-58h-49v-66h-64v66h-243l307 407v-349zM714 124v164h-3l-123 -164h126zM126 696h-86l34 58h116v-452h-64v394zM631 770l51 -26l-440 -760l-51 28z" />
<glyph glyph-name="onehalf" unicode="&#xbd;" horiz-adv-x="867"
d="M126 302v394h-86l34 58h116v-452h-64zM639 58h188v-58h-317l215 243q38 44 38 81q0 33 -29 56.5t-62 23.5q-37 0 -61.5 -21t-26.5 -55h-67q7 61 48 97.5t107 36.5q63 0 109 -39t46 -97q0 -55 -33 -93zM579 770l51 -26l-440 -760l-51 28z" />
<glyph glyph-name="threequarters" unicode="&#xbe;" horiz-adv-x="867"
d="M778 124h49v-58h-49v-66h-64v66h-243l307 407v-349zM714 124v164h-3l-123 -164h126zM184 518v58q43 0 68.5 17t25.5 50t-25 51t-58 18q-32 0 -53.5 -14t-21.5 -42h-67q9 55 46 84.5t98 29.5t103 -33.5t42 -88.5q0 -67 -66 -102q73 -32 73 -112q0 -62 -46 -99t-114 -37
q-59 0 -102.5 33.5t-46.5 88.5h64q10 -64 90 -64q37 0 64 22t27 58q0 38 -29 61t-72 21zM687 770l51 -26l-440 -760l-51 28z" />
<glyph glyph-name="questiondown" unicode="&#xbf;" horiz-adv-x="453"
d="M152 157h-91q-3 64 47 112.5t115 48.5q67 0 114 -46.5t47 -113.5q0 -64 -33 -94.5t-93 -52.5q-5 -2 -20 -7.5t-21 -7.5t-19 -7.5t-18 -9t-15 -10t-14 -12.5t-9 -14t-7 -17t-2 -20q0 -41 26 -65t66 -24q35 0 60.5 25.5t25.5 60.5q0 10 -6 32h94l2 -33q4 -71 -51 -120.5
t-128 -49.5q-76 0 -128 51t-52 126q0 78 54 124q31 27 124 56q73 22 73 73q0 30 -20 51t-50 21q-32 0 -52 -22.5t-19 -54.5zM223 508q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5z" />
<glyph glyph-name="Agrave" unicode="&#xc0;" horiz-adv-x="703"
d="M525 189h-346l-86 -189h-101l360 786l360 -786h-101zM486 275l-134 305l-134 -305h268zM208 951l83 44l125 -166l-44 -27z" />
<glyph glyph-name="Aacute" unicode="&#xc1;" horiz-adv-x="703"
d="M525 189h-346l-86 -189h-101l360 786l360 -786h-101zM486 275l-134 305l-134 -305h268zM413 995l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="Acircumflex" unicode="&#xc2;" horiz-adv-x="703"
d="M525 189h-346l-86 -189h-101l360 786l360 -786h-101zM486 275l-134 305l-134 -305h268zM192 850l159 145l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="Atilde" unicode="&#xc3;" horiz-adv-x="703"
d="M525 189h-346l-86 -189h-101l360 786l360 -786h-101zM486 275l-134 305l-134 -305h268zM208 834l-47 40l3 5q17 24 29 38t33 26t46 12q41 0 89 -26q50 -27 72 -27q35 0 64 48l47 -39q-40 -82 -118 -82q-29 0 -83 26q-54 25 -78 25q-17 0 -32.5 -14t-24.5 -32z" />
<glyph glyph-name="Adieresis" unicode="&#xc4;" horiz-adv-x="703"
d="M525 189h-346l-86 -189h-101l360 786l360 -786h-101zM486 275l-134 305l-134 -305h268zM247 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 18t-18 43t18 42.5t43 17.5zM458 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 18t-17.5 43
t18 42.5t43 17.5z" />
<glyph glyph-name="Aring" unicode="&#xc5;" horiz-adv-x="703"
d="M525 189h-346l-86 -189h-101l360 786l360 -786h-101zM486 275l-134 305l-134 -305h268zM352 985q38 0 64.5 -26.5t26.5 -64.5t-26.5 -64t-64.5 -26t-64 26t-26 64t26.5 64.5t63.5 26.5zM352 849q19 0 32.5 13t13.5 32t-13.5 32.5t-32.5 13.5q-18 0 -31.5 -13.5
t-13.5 -32.5t13.5 -32t31.5 -13z" />
<glyph glyph-name="AE" unicode="&#xc6;" horiz-adv-x="997"
d="M532 189h-343l-86 -189h-103l362 754h330l38 -86h-309l91 -211h301l40 -86h-302l121 -285h311l38 -86h-406zM497 275l-130 292l-138 -292h268z" />
<glyph glyph-name="Ccedilla" unicode="&#xc7;" horiz-adv-x="661"
d="M621 719v-109q-83 74 -199 74q-125 0 -211.5 -90.5t-86.5 -217.5q0 -125 85.5 -215.5t210.5 -90.5q114 0 201 78v-111q-90 -53 -198 -53q-162 0 -277.5 113t-115.5 276q0 167 117 282t284 115q107 0 190 -51zM410 -46l-105 -135l-53 27l87 137z" />
<glyph glyph-name="Egrave" unicode="&#xc8;" horiz-adv-x="521"
d="M72 0v754h405v-86h-311v-211h302v-86h-302v-285h311v-86h-405zM137 951l83 44l125 -166l-44 -27z" />
<glyph glyph-name="Eacute" unicode="&#xc9;" horiz-adv-x="521"
d="M72 0v754h405v-86h-311v-211h302v-86h-302v-285h311v-86h-405zM322 995l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="Ecircumflex" unicode="&#xca;" horiz-adv-x="521"
d="M72 0v754h405v-86h-311v-211h302v-86h-302v-285h311v-86h-405zM113 850l159 145l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="Edieresis" unicode="&#xcb;" horiz-adv-x="521"
d="M72 0v754h405v-86h-311v-211h302v-86h-302v-285h311v-86h-405zM168 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 18t-17.5 43t18 42.5t43 17.5zM379 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 18t-18 43t18 42.5t43 17.5z" />
<glyph glyph-name="Igrave" unicode="&#xcc;" horiz-adv-x="232"
d="M163 754v-754h-94v754h94zM-18 951l83 44l125 -166l-44 -27z" />
<glyph glyph-name="Iacute" unicode="&#xcd;" horiz-adv-x="232"
d="M163 754v-754h-94v754h94zM167 995l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="Icircumflex" unicode="&#xce;" horiz-adv-x="232"
d="M163 754v-754h-94v754h94zM-44 850l159 145l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="Idieresis" unicode="&#xcf;" horiz-adv-x="232"
d="M163 754v-754h-94v754h94zM11 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 18t-18 43t18 42.5t43 17.5zM222 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 18t-17.5 43t18 42.5t43 17.5z" />
<glyph glyph-name="Eth" unicode="&#xd0;" horiz-adv-x="665"
d="M64 442v312h156q183 0 303 -96.5t120 -276.5q0 -185 -119 -283t-307 -98h-153v362h-64v80h64zM158 668v-226h134v-80h-134v-276h33q76 0 138 15t112.5 48t79 91t28.5 137q0 80 -28.5 138t-79.5 90.5t-112.5 47.5t-137.5 15h-33z" />
<glyph glyph-name="Ntilde" unicode="&#xd1;" horiz-adv-x="785"
d="M63 0v790l566 -593v557h94v-785l-566 593v-562h-94zM249 834l-47 40l3 5q17 24 29 38t33 26t46 12q41 0 89 -26q50 -27 72 -27q35 0 64 48l47 -39q-40 -82 -118 -82q-29 0 -83 26q-54 25 -78 25q-17 0 -32.5 -14t-24.5 -32z" />
<glyph glyph-name="Ograve" unicode="&#xd2;" horiz-adv-x="828"
d="M414 770q162 0 278.5 -115.5t116.5 -277.5q0 -167 -115 -280t-280 -113t-280 113t-115 280q0 162 116.5 277.5t278.5 115.5zM414 72q123 0 212 88.5t89 216.5q0 127 -85.5 216t-215.5 89t-215.5 -89t-85.5 -216q0 -128 89 -216.5t212 -88.5zM280 951l83 44l125 -166
l-44 -27z" />
<glyph glyph-name="Oacute" unicode="&#xd3;" horiz-adv-x="828"
d="M414 770q162 0 278.5 -115.5t116.5 -277.5q0 -167 -115 -280t-280 -113t-280 113t-115 280q0 162 116.5 277.5t278.5 115.5zM414 72q123 0 212 88.5t89 216.5q0 127 -85.5 216t-215.5 89t-215.5 -89t-85.5 -216q0 -128 89 -216.5t212 -88.5zM465 995l83 -44l-164 -149
l-44 27z" />
<glyph glyph-name="Ocircumflex" unicode="&#xd4;" horiz-adv-x="828"
d="M414 770q162 0 278.5 -115.5t116.5 -277.5q0 -167 -115 -280t-280 -113t-280 113t-115 280q0 162 116.5 277.5t278.5 115.5zM414 72q123 0 212 88.5t89 216.5q0 127 -85.5 216t-215.5 89t-215.5 -89t-85.5 -216q0 -128 89 -216.5t212 -88.5zM254 850l159 145l161 -145
l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="Otilde" unicode="&#xd5;" horiz-adv-x="828"
d="M414 770q162 0 278.5 -115.5t116.5 -277.5q0 -167 -115 -280t-280 -113t-280 113t-115 280q0 162 116.5 277.5t278.5 115.5zM414 72q123 0 212 88.5t89 216.5q0 127 -85.5 216t-215.5 89t-215.5 -89t-85.5 -216q0 -128 89 -216.5t212 -88.5zM270 834l-47 40l3 5
q17 24 29 38t33 26t46 12q41 0 89 -26q50 -27 72 -27q35 0 64 48l47 -39q-40 -82 -118 -82q-29 0 -83 26q-54 25 -78 25q-17 0 -32.5 -14t-24.5 -32z" />
<glyph glyph-name="Odieresis" unicode="&#xd6;" horiz-adv-x="828"
d="M414 770q162 0 278.5 -115.5t116.5 -277.5q0 -167 -115 -280t-280 -113t-280 113t-115 280q0 162 116.5 277.5t278.5 115.5zM414 72q123 0 212 88.5t89 216.5q0 127 -85.5 216t-215.5 89t-215.5 -89t-85.5 -216q0 -128 89 -216.5t212 -88.5zM309 955q25 0 42.5 -17.5
t17.5 -42.5t-17.5 -43t-42.5 -18t-43 18t-18 43t18 42.5t43 17.5zM520 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 18t-17.5 43t18 42.5t43 17.5z" />
<glyph glyph-name="multiply" unicode="&#xd7;"
d="M33 451l60 61l196 -195l196 195l60 -61l-195 -195l195 -195l-60 -61l-196 195l-196 -195l-60 61l195 195z" />
<glyph glyph-name="Oslash" unicode="&#xd8;" horiz-adv-x="828"
d="M659 557l-428 -422q81 -63 183 -63q123 0 212 88.5t89 216.5q0 102 -56 180zM178 189l430 423q-80 70 -194 70q-130 0 -215.5 -89t-85.5 -216q0 -107 65 -188zM7 21l104 102q-92 108 -92 254q0 162 116.5 277.5t278.5 115.5q146 0 257 -96l96 95l54 -53l-98 -96
q86 -108 86 -243q0 -167 -115 -280t-280 -113q-141 0 -249 86l-104 -102z" />
<glyph glyph-name="Ugrave" unicode="&#xd9;" horiz-adv-x="669"
d="M59 754h94v-445q0 -237 182 -237t182 237v445h94v-477q0 -128 -74.5 -210.5t-201.5 -82.5t-201.5 82.5t-74.5 210.5v477zM201 951l83 44l125 -166l-44 -27z" />
<glyph glyph-name="Uacute" unicode="&#xda;" horiz-adv-x="669"
d="M59 754h94v-445q0 -237 182 -237t182 237v445h94v-477q0 -128 -74.5 -210.5t-201.5 -82.5t-201.5 82.5t-74.5 210.5v477zM386 995l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="Ucircumflex" unicode="&#xdb;" horiz-adv-x="669"
d="M59 754h94v-445q0 -237 182 -237t182 237v445h94v-477q0 -128 -74.5 -210.5t-201.5 -82.5t-201.5 82.5t-74.5 210.5v477zM175 850l159 145l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="Udieresis" unicode="&#xdc;" horiz-adv-x="669"
d="M59 754h94v-445q0 -237 182 -237t182 237v445h94v-477q0 -128 -74.5 -210.5t-201.5 -82.5t-201.5 82.5t-74.5 210.5v477zM230 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 18t-17.5 43t18 42.5t43 17.5zM441 955q25 0 42.5 -17.5t17.5 -42.5
t-17.5 -43t-42.5 -18t-43 18t-18 43t18 42.5t43 17.5z" />
<glyph glyph-name="Yacute" unicode="&#xdd;" horiz-adv-x="573"
d="M240 328l-246 426h108l185 -322l185 322h108l-246 -426v-328h-94v328zM368 995l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="Thorn" unicode="&#xde;" horiz-adv-x="495"
d="M166 176v-176h-94v754h94v-140h14q167 0 235.5 -54.5t68.5 -163.5q0 -112 -73.5 -166t-190.5 -54h-54zM166 530v-270h30q41 0 72.5 5t62.5 18.5t48 42.5t17 72q0 42 -18 70t-51 40.5t-64 17t-72 4.5h-25z" />
<glyph glyph-name="germandbls" unicode="&#xdf;" horiz-adv-x="580"
d="M282 -16v84q78 0 136.5 56t58.5 134q0 84 -54.5 131.5t-140.5 53.5v88q57 -1 96 39.5t39 98.5q0 55 -38 91t-92 36q-27 0 -48.5 -9t-35 -20.5t-22.5 -34.5t-13.5 -38.5t-7 -46.5t-2.5 -43.5v-44.5v-559h-90v386h-40v84h40v148q0 262 222 262q93 0 155 -61t62 -155
q0 -111 -96 -167q72 -23 114 -91.5t42 -147.5q0 -117 -84.5 -198t-200.5 -76z" />
<glyph glyph-name="agrave" unicode="&#xe0;" horiz-adv-x="556"
d="M264 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM501 468v-468h-90v73h-2q-60 -89 -159 -89q-103 0 -163.5 73.5t-60.5 179.5q0 100 61 172.5t160 72.5q101 0 162 -92h2v78h90zM159 690l83 44l125 -166
l-44 -27z" />
<glyph glyph-name="aacute" unicode="&#xe1;" horiz-adv-x="556"
d="M264 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM501 468v-468h-90v73h-2q-60 -89 -159 -89q-103 0 -163.5 73.5t-60.5 179.5q0 100 61 172.5t160 72.5q101 0 162 -92h2v78h90zM339 734l83 -44
l-164 -149l-44 27z" />
<glyph glyph-name="acircumflex" unicode="&#xe2;" horiz-adv-x="556"
d="M264 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM501 468v-468h-90v73h-2q-60 -89 -159 -89q-103 0 -163.5 73.5t-60.5 179.5q0 100 61 172.5t160 72.5q101 0 162 -92h2v78h90zM118 589l159 145
l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="atilde" unicode="&#xe3;" horiz-adv-x="556"
d="M264 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM501 468v-468h-90v73h-2q-60 -89 -159 -89q-103 0 -163.5 73.5t-60.5 179.5q0 100 61 172.5t160 72.5q101 0 162 -92h2v78h90zM134 573l-47 40l3 5
q17 24 29 38t33 26t46 12q41 0 89 -26q50 -27 72 -27q35 0 64 48l47 -39q-40 -82 -118 -82q-29 0 -83 26q-54 25 -78 25q-17 0 -32.5 -14t-24.5 -32z" />
<glyph glyph-name="adieresis" unicode="&#xe4;" horiz-adv-x="556"
d="M264 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM501 468v-468h-90v73h-2q-60 -89 -159 -89q-103 0 -163.5 73.5t-60.5 179.5q0 100 61 172.5t160 72.5q101 0 162 -92h2v78h90zM173 694
q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 17.5t-18 43.5q0 25 18 42.5t43 17.5zM384 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 17.5t-17.5 43.5q0 25 18 42.5t43 17.5z" />
<glyph glyph-name="aring" unicode="&#xe5;" horiz-adv-x="556"
d="M264 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50zM501 468v-468h-90v73h-2q-60 -89 -159 -89q-103 0 -163.5 73.5t-60.5 179.5q0 100 61 172.5t160 72.5q101 0 162 -92h2v78h90zM278 734
q38 0 64.5 -26.5t26.5 -64.5t-26.5 -64t-64.5 -26t-64 26.5t-26 63.5q0 38 26.5 64.5t63.5 26.5zM278 598q19 0 32.5 13t13.5 32t-13.5 32.5t-32.5 13.5q-18 0 -31.5 -13.5t-13.5 -32.5t13.5 -32t31.5 -13z" />
<glyph glyph-name="ae" unicode="&#xe6;" horiz-adv-x="807"
d="M442 287h262q-8 54 -42 85.5t-87 31.5q-52 0 -88.5 -33t-44.5 -84zM221 218q-41 0 -76 -20.5t-35 -58.5t36 -56.5t78 -18.5q43 0 79.5 19.5t36.5 58.5q0 38 -38 57t-81 19zM792 219h-357q1 -63 40 -109t101 -46q49 0 80.5 22.5t59.5 68.5l76 -43q-33 -60 -90.5 -94
t-126.5 -34q-105 0 -180 87q-28 -42 -76.5 -64.5t-102.5 -22.5q-76 0 -133 39.5t-57 113.5q0 73 51 115t126 42q90 0 142 -43v32q0 121 -123 121q-81 0 -128 -15v80q66 13 141 13q48 0 93.5 -19.5t66.5 -57.5q62 77 178 77q107 0 163 -69.5t56 -179.5v-14z" />
<glyph glyph-name="ccedilla" unicode="&#xe7;" horiz-adv-x="441"
d="M406 451v-116q-55 63 -134 63q-65 0 -110.5 -49t-45.5 -115q0 -72 45.5 -119t116.5 -47q73 0 128 62v-115q-58 -31 -129 -31q-104 0 -177.5 71t-73.5 175q0 108 73.5 180t182.5 72q71 0 124 -31zM300 -46l-105 -135l-53 27l87 137z" />
<glyph glyph-name="egrave" unicode="&#xe8;" horiz-adv-x="488"
d="M473 219h-357q1 -63 40 -109t101 -46q49 0 80.5 22.5t59.5 68.5l76 -43q-33 -60 -90.5 -94t-126.5 -34q-105 0 -167.5 70t-62.5 176q0 112 59 182t169 70q107 0 163 -69.5t56 -179.5v-14zM121 287h262q-8 54 -42 85.5t-87 31.5q-52 0 -88.5 -33t-44.5 -84zM125 690l83 44
l125 -166l-44 -27z" />
<glyph glyph-name="eacute" unicode="&#xe9;" horiz-adv-x="488"
d="M473 219h-357q1 -63 40 -109t101 -46q49 0 80.5 22.5t59.5 68.5l76 -43q-33 -60 -90.5 -94t-126.5 -34q-105 0 -167.5 70t-62.5 176q0 112 59 182t169 70q107 0 163 -69.5t56 -179.5v-14zM121 287h262q-8 54 -42 85.5t-87 31.5q-52 0 -88.5 -33t-44.5 -84zM305 734
l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="ecircumflex" unicode="&#xea;" horiz-adv-x="488"
d="M473 219h-357q1 -63 40 -109t101 -46q49 0 80.5 22.5t59.5 68.5l76 -43q-33 -60 -90.5 -94t-126.5 -34q-105 0 -167.5 70t-62.5 176q0 112 59 182t169 70q107 0 163 -69.5t56 -179.5v-14zM121 287h262q-8 54 -42 85.5t-87 31.5q-52 0 -88.5 -33t-44.5 -84zM84 589
l159 145l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="edieresis" unicode="&#xeb;" horiz-adv-x="488"
d="M473 219h-357q1 -63 40 -109t101 -46q49 0 80.5 22.5t59.5 68.5l76 -43q-33 -60 -90.5 -94t-126.5 -34q-105 0 -167.5 70t-62.5 176q0 112 59 182t169 70q107 0 163 -69.5t56 -179.5v-14zM121 287h262q-8 54 -42 85.5t-87 31.5q-52 0 -88.5 -33t-44.5 -84zM139 694
q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 17.5t-18 43.5q0 25 18 42.5t43 17.5zM350 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 17.5t-17.5 43.5q0 25 18 42.5t43 17.5z" />
<glyph glyph-name="igrave" unicode="&#xec;" horiz-adv-x="254"
d="M172 468v-468h-90v468h90zM-7 690l83 44l125 -166l-44 -27z" />
<glyph glyph-name="iacute" unicode="&#xed;" horiz-adv-x="254"
d="M172 468v-468h-90v468h90zM178 734l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="icircumflex" unicode="&#xee;" horiz-adv-x="254"
d="M172 468v-468h-90v468h90zM-33 589l159 145l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="idieresis" unicode="&#xef;" horiz-adv-x="254"
d="M172 468v-468h-90v468h90zM22 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 17.5t-17.5 43.5q0 25 18 42.5t43 17.5zM233 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 17.5t-18 43.5q0 25 18 42.5t43 17.5z" />
<glyph glyph-name="eth" unicode="&#xf0;" horiz-adv-x="540"
d="M270 396q-66 0 -113 -48t-47 -115q0 -66 47 -114.5t113 -48.5t113 48.5t47 114.5q0 67 -47 115t-113 48zM46 638l145 83q-54 60 -111 105l57 51q62 -43 129 -113l145 83l42 -55l-141 -81q91 -107 149.5 -229.5t58.5 -229.5q0 -124 -71 -196t-179 -72q-105 0 -177.5 72
t-72.5 177t72.5 177t177.5 72q10 0 19.5 -1t17 -2.5t15.5 -4t13 -4.5t12.5 -6t10 -5.5t10 -5.5t8.5 -5q-58 119 -139 220l-147 -84z" />
<glyph glyph-name="ntilde" unicode="&#xf1;" horiz-adv-x="523"
d="M152 468v-63h2q20 37 58.5 57t82.5 20q92 0 129 -54t37 -149v-279h-90v268q0 69 -19.5 101.5t-83.5 32.5q-28 0 -49 -7t-33 -23t-19.5 -30.5t-10.5 -41t-3.5 -41.5t-0.5 -44v-215h-90v468h90zM118 573l-47 40l3 5q17 24 29 38t33 26t46 12q41 0 89 -26q50 -27 72 -27
q35 0 64 48l47 -39q-40 -82 -118 -82q-29 0 -83 26q-54 25 -78 25q-17 0 -32.5 -14t-24.5 -32z" />
<glyph glyph-name="ograve" unicode="&#xf2;" horiz-adv-x="540"
d="M270 482q105 0 177.5 -72t72.5 -177t-72.5 -177t-177.5 -72t-177.5 72t-72.5 177t72.5 177t177.5 72zM270 396q-66 0 -113 -48t-47 -115q0 -66 47 -114.5t113 -48.5t113 48.5t47 114.5q0 67 -47 115t-113 48zM126 690l83 44l125 -166l-44 -27z" />
<glyph glyph-name="oacute" unicode="&#xf3;" horiz-adv-x="540"
d="M270 482q105 0 177.5 -72t72.5 -177t-72.5 -177t-177.5 -72t-177.5 72t-72.5 177t72.5 177t177.5 72zM270 396q-66 0 -113 -48t-47 -115q0 -66 47 -114.5t113 -48.5t113 48.5t47 114.5q0 67 -47 115t-113 48zM331 734l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="ocircumflex" unicode="&#xf4;" horiz-adv-x="540"
d="M270 482q105 0 177.5 -72t72.5 -177t-72.5 -177t-177.5 -72t-177.5 72t-72.5 177t72.5 177t177.5 72zM270 396q-66 0 -113 -48t-47 -115q0 -66 47 -114.5t113 -48.5t113 48.5t47 114.5q0 67 -47 115t-113 48zM110 589l159 145l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="otilde" unicode="&#xf5;" horiz-adv-x="540"
d="M270 482q105 0 177.5 -72t72.5 -177t-72.5 -177t-177.5 -72t-177.5 72t-72.5 177t72.5 177t177.5 72zM270 396q-66 0 -113 -48t-47 -115q0 -66 47 -114.5t113 -48.5t113 48.5t47 114.5q0 67 -47 115t-113 48zM126 573l-47 40l3 5q17 24 29 38t33 26t46 12q41 0 89 -26
q50 -27 72 -27q35 0 64 48l47 -39q-40 -82 -118 -82q-29 0 -83 26q-54 25 -78 25q-17 0 -32.5 -14t-24.5 -32z" />
<glyph glyph-name="odieresis" unicode="&#xf6;" horiz-adv-x="540"
d="M270 482q105 0 177.5 -72t72.5 -177t-72.5 -177t-177.5 -72t-177.5 72t-72.5 177t72.5 177t177.5 72zM270 396q-66 0 -113 -48t-47 -115q0 -66 47 -114.5t113 -48.5t113 48.5t47 114.5q0 67 -47 115t-113 48zM165 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18
t-43 17.5t-18 43.5q0 25 18 42.5t43 17.5zM376 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 17.5t-17.5 43.5q0 25 18 42.5t43 17.5z" />
<glyph glyph-name="divide" unicode="&#xf7;"
d="M33 213v86h512v-86h-512zM289 124q26 0 44 -18.5t18 -44.5q0 -25 -18 -43t-44 -18t-44 18t-18 43q0 26 18 44.5t44 18.5zM289 512q26 0 44 -18.5t18 -44.5q0 -25 -18 -43t-44 -18t-44 18t-18 43q0 26 18 44.5t44 18.5z" />
<glyph glyph-name="oslash" unicode="&#xf8;" horiz-adv-x="540"
d="M139 141l223 225q-42 30 -92 30q-66 0 -113 -48t-47 -115q0 -50 29 -92zM405 319l-221 -223q38 -26 86 -26q66 0 113 48.5t47 114.5q0 49 -25 86zM8 9l67 67q-55 66 -55 157q0 105 72.5 177t177.5 72q87 0 155 -52l61 61l46 -43l-62 -63q50 -66 50 -152
q0 -105 -72.5 -177t-177.5 -72q-85 0 -149 48l-69 -70z" />
<glyph glyph-name="ugrave" unicode="&#xf9;" horiz-adv-x="512"
d="M58 468h90v-259q0 -65 23.5 -103t84.5 -38t84.5 38t23.5 103v259h90v-269q0 -100 -49 -157.5t-149 -57.5t-149 57.5t-49 157.5v269zM112 690l83 44l125 -166l-44 -27z" />
<glyph glyph-name="uacute" unicode="&#xfa;" horiz-adv-x="512"
d="M58 468h90v-259q0 -65 23.5 -103t84.5 -38t84.5 38t23.5 103v259h90v-269q0 -100 -49 -157.5t-149 -57.5t-149 57.5t-49 157.5v269zM317 734l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="ucircumflex" unicode="&#xfb;" horiz-adv-x="512"
d="M58 468h90v-259q0 -65 23.5 -103t84.5 -38t84.5 38t23.5 103v259h90v-269q0 -100 -49 -157.5t-149 -57.5t-149 57.5t-49 157.5v269zM96 589l159 145l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="udieresis" unicode="&#xfc;" horiz-adv-x="512"
d="M58 468h90v-259q0 -65 23.5 -103t84.5 -38t84.5 38t23.5 103v259h90v-269q0 -100 -49 -157.5t-149 -57.5t-149 57.5t-49 157.5v269zM151 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 17.5t-18 43.5q0 25 18 42.5t43 17.5zM362 694q25 0 42.5 -17.5
t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 17.5t-17.5 43.5q0 25 18 42.5t43 17.5z" />
<glyph glyph-name="yacute" unicode="&#xfd;" horiz-adv-x="484"
d="M201 80l-214 388h105l158 -297l147 297h101l-379 -736h-102zM323 734l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="thorn" unicode="&#xfe;" horiz-adv-x="556"
d="M145 868v-478h2q61 92 163 92q98 0 159 -72.5t61 -172.5q0 -106 -60 -179.5t-164 -73.5q-48 0 -89.5 24t-69.5 65h-2v-341h-90v1136h90zM288 64q71 0 111.5 49t40.5 121q0 71 -41 119.5t-111 48.5q-67 0 -107.5 -49.5t-40.5 -118.5q0 -70 40 -120t108 -50z" />
<glyph glyph-name="ydieresis" unicode="&#xff;" horiz-adv-x="484"
d="M201 80l-214 388h105l158 -297l147 297h101l-379 -736h-102zM147 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 17.5t-18 43.5q0 25 18 42.5t43 17.5zM358 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 17.5t-17.5 43.5q0 25 18 42.5
t43 17.5z" />
<glyph glyph-name="dotlessi" unicode="&#x131;" horiz-adv-x="254"
d="M172 468v-468h-90v468h90z" />
<glyph glyph-name="Lslash" unicode="&#x141;" horiz-adv-x="385"
d="M166 754v-288l118 83v-90l-118 -79v-294h229v-86h-323v322l-81 -58v91l81 54v345h94z" />
<glyph glyph-name="lslash" unicode="&#x142;" horiz-adv-x="255"
d="M82 0v412l-81 -55v81l81 55v375h90v-314l82 56v-82l-82 -55v-473h-90z" />
<glyph glyph-name="OE" unicode="&#x152;" horiz-adv-x="1143"
d="M718 0v126h-2q-51 -68 -130.5 -105.5t-171.5 -36.5q-165 0 -280 113t-115 280q0 162 116.5 277.5t278.5 115.5q90 -3 172 -41t130 -107h2v132h395v-86h-310v-211h301v-86h-301v-285h310v-86h-395zM414 72q123 0 212 88.5t89 216.5q0 127 -85.5 216t-215.5 89t-215.5 -89
t-85.5 -216q0 -128 89 -216.5t212 -88.5z" />
<glyph glyph-name="oe" unicode="&#x153;" horiz-adv-x="897"
d="M529 287h262q-8 54 -42 85.5t-87 31.5q-52 0 -88.5 -33t-44.5 -84zM270 396q-66 0 -113 -48t-47 -115q0 -66 47 -114.5t113 -48.5t113 48.5t47 114.5q0 67 -47 115t-113 48zM882 219h-357q1 -63 40 -109t101 -46q49 0 80.5 22.5t59.5 68.5l76 -43q-33 -60 -90.5 -94
t-126.5 -34q-60 -1 -113 26.5t-82 76.5q-33 -49 -87 -76.5t-113 -26.5q-105 0 -177.5 72t-72.5 177t72.5 177t177.5 72q58 -2 113 -30t87 -75q64 101 193 105q107 0 163 -69.5t56 -179.5v-14z" />
<glyph glyph-name="Scaron" unicode="&#x160;" horiz-adv-x="537"
d="M482 656l-75 -45q-42 71 -121 71q-48 0 -87 -30t-39 -77q0 -68 105 -108l54 -21q90 -35 138.5 -87t48.5 -140q0 -102 -69.5 -168.5t-171.5 -66.5q-91 0 -156 59.5t-77 151.5l95 20q-1 -61 41.5 -102t104.5 -41q60 0 99.5 43.5t39.5 103.5q0 55 -34.5 86.5t-95.5 56.5
l-52 22q-77 33 -120.5 76t-43.5 115q0 88 66 141.5t156 53.5q130 0 194 -114zM119 949l58 46l101 -96l102 96l59 -46l-161 -145z" />
<glyph glyph-name="scaron" unicode="&#x161;" horiz-adv-x="384"
d="M323 400l-73 -39q-20 41 -60 41q-19 0 -34 -13.5t-15 -32.5q0 -9 2.5 -16.5t10 -14t13 -11.5t18 -11.5t19.5 -10t23.5 -10.5t22.5 -10q50 -23 79 -53t29 -80q0 -66 -47.5 -110.5t-113.5 -44.5q-53 0 -98.5 28.5t-63.5 76.5l77 35q33 -60 85 -60q29 0 50 18.5t21 47.5
t-33 51l-88 47q-46 25 -68 49.5t-22 68.5q0 57 40.5 96.5t97.5 39.5q88 0 128 -82zM32 688l58 46l101 -96l102 96l59 -46l-161 -145z" />
<glyph glyph-name="Ydieresis" unicode="&#x178;" horiz-adv-x="573"
d="M240 328l-246 426h108l185 -322l185 322h108l-246 -426v-328h-94v328zM194 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18q-26 0 -43.5 18t-17.5 43t18 42.5t43 17.5zM405 955q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 18t-18 43t18 42.5t43 17.5z
" />
<glyph glyph-name="Zcaron" unicode="&#x17d;" horiz-adv-x="552"
d="M162 86h382v-86h-535l382 668h-328v86h481zM131 949l58 46l101 -96l102 96l59 -46l-161 -145z" />
<glyph glyph-name="zcaron" unicode="&#x17e;" horiz-adv-x="495"
d="M177 84h304v-84h-479l317 384h-263v84h438zM103 688l58 46l101 -96l102 96l59 -46l-161 -145z" />
<glyph glyph-name="florin" unicode="&#x192;"
d="M355 505h129l-9 -68h-131l-55 -303q-7 -42 -12.5 -67.5t-16 -59t-22 -53.5t-30 -42t-41.5 -34t-55.5 -19.5t-73.5 -7.5h-24l15 86h19q28 0 49.5 6.5t36.5 22t24.5 29t17 41.5t10.5 43t9 50l53 308h-65l9 68h70l21 124q17 100 60 153.5t137 53.5q33 0 60 -7l-16 -84
q-18 7 -41 7t-41 -8.5t-27.5 -18.5t-18 -32t-11.5 -34.5t-8 -40.5z" />
<glyph glyph-name="circumflex" unicode="&#x2c6;" horiz-adv-x="470"
d="M75 589l159 145l161 -145l-59 -46l-102 96l-101 -96z" />
<glyph glyph-name="caron" unicode="&#x2c7;" horiz-adv-x="472"
d="M76 688l58 46l101 -96l102 96l59 -46l-161 -145z" />
<glyph glyph-name="uni02C9" unicode="&#x2c9;" horiz-adv-x="500"
d="M70 694h361v-68h-361v68z" />
<glyph glyph-name="breve" unicode="&#x2d8;" horiz-adv-x="490"
d="M71 694h72q32 -75 102 -75q39 0 62.5 18.5t40.5 56.5h71q-11 -62 -60.5 -101.5t-113.5 -39.5q-63 0 -112.5 39.5t-61.5 101.5z" />
<glyph glyph-name="dotaccent" unicode="&#x2d9;" horiz-adv-x="360"
d="M181 694q25 0 42.5 -17.5t17.5 -42.5t-17.5 -43t-42.5 -18t-43 17.5t-18 43.5q0 25 18 42.5t43 17.5z" />
<glyph glyph-name="ring" unicode="&#x2da;" horiz-adv-x="360"
d="M180 734q38 0 64.5 -26.5t26.5 -64.5t-26.5 -64t-64.5 -26t-64 26.5t-26 63.5q0 38 26.5 64.5t63.5 26.5zM180 598q19 0 32.5 13t13.5 32t-13.5 32.5t-32.5 13.5q-18 0 -31.5 -13.5t-13.5 -32.5t13.5 -32t31.5 -13z" />
<glyph glyph-name="ogonek" unicode="&#x2db;" horiz-adv-x="340"
d="M165 -16h46v-2q-61 -41 -61 -85q0 -47 56 -47q30 0 50 13l-7 -58q-27 -17 -64 -17q-40 0 -70.5 22t-30.5 60q0 65 81 114z" />
<glyph glyph-name="tilde" unicode="&#x2dc;" horiz-adv-x="510"
d="M111 573l-47 40l3 5q17 24 29 38t33 26t46 12q41 0 89 -26q50 -27 72 -27q35 0 64 48l47 -39q-40 -82 -118 -82q-29 0 -83 26q-54 25 -78 25q-17 0 -32.5 -14t-24.5 -32z" />
<glyph glyph-name="hungarumlaut" unicode="&#x2dd;" horiz-adv-x="470"
d="M349 725l83 -44l-164 -149l-44 27zM163 734l83 -44l-164 -149l-44 27z" />
<glyph glyph-name="uni03A9" unicode="&#x3a9;" horiz-adv-x="745"
d="M204 70v3q-61 57 -100.5 144t-39.5 192q0 158 88.5 259t223.5 101q136 0 220 -105t84 -250q0 -109 -41 -198.5t-100 -142.5v-3h155v-70h-252v51q65 46 109 136t44 211q0 74 -23.5 140.5t-75.5 113t-121 46.5q-102 0 -164 -86.5t-62 -216.5q0 -114 44.5 -207.5
t107.5 -136.5v-51h-251v70h154z" />
<glyph glyph-name="uni03BC" unicode="&#x3bc;" horiz-adv-x="512"
d="M58 468h90v-259q0 -65 23.5 -103t84.5 -38t84.5 38t23.5 103v259h90v-269q0 -100 -49 -157.5t-149 -57.5q-56 0 -108 44v-296h-90v736z" />
<glyph glyph-name="pi" unicode="&#x3c0;" horiz-adv-x="598"
d="M570 491h-83v-333q0 -104 15 -158h-81q-17 31 -17 151v340h-185q-4 -114 -26 -265t-49 -226h-82q29 85 50 230.5t25 260.5q-79 0 -115 -13l-12 57q44 29 152 29h415z" />
<glyph glyph-name="endash" unicode="&#x2013;" horiz-adv-x="500"
d="M0 358h500v-75h-500v75z" />
<glyph glyph-name="emdash" unicode="&#x2014;" horiz-adv-x="1000"
d="M130 358h740v-75h-740v75z" />
<glyph glyph-name="quoteleft" unicode="&#x2018;" horiz-adv-x="277"
d="M139 472l-79 31l133 267l56 -23z" />
<glyph glyph-name="quoteright" unicode="&#x2019;" horiz-adv-x="277"
d="M138 770l79 -31l-133 -267l-56 23z" />
<glyph glyph-name="quotesinglbase" unicode="&#x201a;" horiz-adv-x="277"
d="M164 119l78 -31l-133 -267l-55 23z" />
<glyph glyph-name="quotedblleft" unicode="&#x201c;" horiz-adv-x="439"
d="M305 472l-79 31l133 267l56 -23zM139 472l-79 31l133 267l56 -23z" />
<glyph glyph-name="quotedblright" unicode="&#x201d;" horiz-adv-x="439"
d="M134 770l79 -31l-133 -267l-56 23zM300 770l79 -31l-133 -267l-56 23z" />
<glyph glyph-name="quotedblbase" unicode="&#x201e;" horiz-adv-x="439"
d="M160 119l78 -31l-133 -267l-55 23zM326 119l78 -31l-133 -267l-55 23z" />
<glyph glyph-name="dagger" unicode="&#x2020;"
d="M244 868h90v-275h181v-86h-181v-595h-90v595h-181v86h181v275z" />
<glyph glyph-name="daggerdbl" unicode="&#x2021;"
d="M244 868h90v-239h181v-86h-181v-122h181v-86h-181v-422h-90v422h-181v86h181v122h-181v86h181v239z" />
<glyph glyph-name="bullet" unicode="&#x2022;"
d="M289 189q-78 0 -133 55t-55 133q-1 79 54 134t134 55t134 -55t55 -134q0 -78 -55.5 -133t-133.5 -55z" />
<glyph glyph-name="ellipsis" unicode="&#x2026;" horiz-adv-x="1000"
d="M500 100q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5zM834 100q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5zM166 100q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41
q0 23 17 40.5t41 17.5z" />
<glyph glyph-name="perthousand" unicode="&#x2030;" horiz-adv-x="1110"
d="M198 710q-47 0 -81.5 -33t-34.5 -79q0 -45 34.5 -78t81.5 -33t81.5 33t34.5 78q0 46 -34.5 79t-81.5 33zM557 770l45 -26l-440 -760l-46 25zM521 267q-47 0 -81.5 -33t-34.5 -79q0 -45 34.5 -78t81.5 -33t81.5 33t34.5 78q0 46 -34.5 79t-81.5 33zM198 770
q72 0 124 -50.5t52 -121.5t-52.5 -121t-123.5 -50t-123.5 50t-52.5 121t52 121.5t124 50.5zM521 327q72 0 124 -50.5t52 -121.5t-52.5 -121t-123.5 -50t-123.5 50t-52.5 121t52 121.5t124 50.5zM913 327q72 0 124 -50.5t52 -121.5t-52.5 -121t-123.5 -50t-123.5 50
t-52.5 121t52 121.5t124 50.5zM913 267q-47 0 -81.5 -33t-34.5 -79q0 -45 34.5 -78t81.5 -33t81.5 33t34.5 78q0 46 -34.5 79t-81.5 33z" />
<glyph glyph-name="guilsinglleft" unicode="&#x2039;" horiz-adv-x="336"
d="M111 320l149 -191l-56 -41l-182 232l182 240l56 -41z" />
<glyph glyph-name="guilsinglright" unicode="&#x203a;" horiz-adv-x="336"
d="M76 129l149 191l-149 199l56 41l182 -240l-182 -232z" />
<glyph glyph-name="fraction" unicode="&#x2044;" horiz-adv-x="165"
d="M277 770l51 -26l-440 -760l-51 28z" />
<glyph glyph-name="Euro" unicode="&#x20ac;"
d="M532 723v-87q-57 53 -154 53q-83 0 -129.5 -55t-55.5 -147h295l-23 -69h-281q0 -5 -0.5 -19t-0.5 -20q0 -8 0.5 -22.5t0.5 -18.5h253l-23 -69h-221q11 -101 58.5 -153t127.5 -52q95 0 153 53v-89q-51 -43 -165 -43q-227 0 -262 284h-78l23 69h48q-2 20 -2 41
q0 7 0.5 20.5t0.5 18.5h-70l23 69h53q17 132 81.5 207t182.5 75q109 0 165 -46z" />
<glyph glyph-name="afii61289" unicode="&#x2113;" horiz-adv-x="509"
d="M446 159l39 -36q-68 -134 -196 -134q-86 0 -128.5 56t-45.5 144v14q-10 -8 -30.5 -25t-29.5 -24l-25 48q71 62 84 75v295q0 136 47 198t116 62q64 0 97 -49t33 -127q0 -179 -213 -395v-39q1 -84 32 -125t80 -41q45 0 81 30.5t59 72.5zM194 576v-231q157 180 157 311
q0 112 -73 112q-34 0 -59 -46t-25 -146z" />
<glyph glyph-name="trademark" unicode="&#x2122;" horiz-adv-x="940"
d="M906 754v-421h-64v357h-2l-144 -357h-39l-140 357h-2v-357h-64v421h105l121 -297l125 297h104zM374 754v-64h-138v-357h-64v357h-138v64h340z" />
<glyph glyph-name="Omega" unicode="&#x2126;" horiz-adv-x="745"
d="M204 70v3q-61 57 -100.5 144t-39.5 192q0 158 88.5 259t223.5 101q136 0 220 -105t84 -250q0 -109 -41 -198.5t-100 -142.5v-3h155v-70h-252v51q65 46 109 136t44 211q0 74 -23.5 140.5t-75.5 113t-121 46.5q-102 0 -164 -86.5t-62 -216.5q0 -114 44.5 -207.5
t107.5 -136.5v-51h-251v70h154z" />
<glyph glyph-name="estimated" unicode="&#x212e;" horiz-adv-x="948"
d="M910 366h-707q-6 0 -6 -5v-214q0 -11 9 -24q113 -116 268 -116q83 0 156 34.5t125 95.5h63q-60 -70 -151 -111t-194 -41q-181 0 -308.5 114.5t-127.5 277.5t127.5 278t308.5 115t309 -115t128 -278v-11zM749 394v215q0 16 -10 26q-114 111 -265 111q-154 0 -266 -115
q-11 -11 -11 -27v-210q0 -7 6 -7h542q4 0 4 7z" />
<glyph glyph-name="partialdiff" unicode="&#x2202;" horiz-adv-x="573"
d="M107 725l-28 63q73 60 175 60q111 0 188.5 -105.5t77.5 -304.5q0 -201 -71.5 -325t-202.5 -124q-96 0 -148.5 74t-52.5 176q0 124 65.5 201t157.5 77q62 0 106.5 -32.5t61.5 -66.5h2q1 12 1 46q0 137 -56 225t-138 88q-78 0 -138 -52zM253 60h2q69 0 116 80.5t57 194.5
q-13 41 -53 77t-94 36q-63 0 -108 -61.5t-45 -147.5q0 -79 34.5 -129t90.5 -50z" />
<glyph glyph-name="Delta" unicode="&#x2206;" horiz-adv-x="676"
d="M33 0v57l258 720h97l254 -719v-58h-609zM117 69h436l-147 407q-8 26 -34.5 99.5t-33.5 100.5h-4q-5 -22 -29 -90.5t-32 -93.5z" />
<glyph glyph-name="product" unicode="&#x220f;" horiz-adv-x="731"
d="M703 680h-113v-785h-82v785h-286v-785h-82v785h-112v77h675v-77z" />
<glyph glyph-name="summation" unicode="&#x2211;"
d="M555 -105h-531v57l279 373l-267 373v59h502v-72h-387v-4l247 -343l-269 -359v-4h426v-80z" />
<glyph glyph-name="minus" unicode="&#x2212;"
d="M33 213v86h512v-86h-512z" />
<glyph glyph-name="uni2215" unicode="&#x2215;" horiz-adv-x="165"
d="M277 770l51 -26l-440 -760l-51 28z" />
<glyph glyph-name="uni2219" unicode="&#x2219;" horiz-adv-x="289"
d="M145 314q24 0 41 -17.5t17 -40.5q0 -24 -17 -41t-41 -17t-41 17t-17 41q0 23 17 40.5t41 17.5z" />
<glyph glyph-name="radical" unicode="&#x221a;" horiz-adv-x="601"
d="M601 901l-232 -1062h-73l-166 501l-78 -29l-16 51l146 57l131 -395q2 -11 9 -40t9 -41l2 -1q7 50 14 82l193 877h61z" />
<glyph glyph-name="infinity" unicode="&#x221e;" horiz-adv-x="821"
d="M768 315v-1q0 -75 -48.5 -122.5t-114.5 -47.5q-48 0 -91.5 29.5t-101.5 96.5q-53 -61 -97.5 -93.5t-102.5 -32.5q-65 0 -112 48t-47 118q0 73 47.5 121t119.5 48q54 0 99 -32.5t96 -92.5q3 4 10 11q34 38 54 57t57.5 38t76.5 19q69 0 112 -45.5t43 -118.5zM219 196h2
q14 0 27.5 3t27 11.5t23 14.5t24 19.5t20.5 20t21 23t19 20.5q-26 32 -37.5 45t-35.5 35.5t-47 31.5t-50 9q-48 0 -76.5 -35t-28.5 -85q1 -48 32 -80.5t79 -32.5zM607 429h-1q-25 0 -52 -15t-40.5 -27t-41 -42t-29.5 -32q58 -65 92 -91t74 -26q47 0 75.5 35t28.5 79
q0 55 -29.5 87t-76.5 32z" />
<glyph glyph-name="integral" unicode="&#x222b;" horiz-adv-x="381"
d="M362 912l-13 -59q-17 11 -38 11q-33 0 -53 -26q-35 -43 -35 -193q0 -84 7 -269t7 -275q0 -151 -45 -219q-34 -57 -107 -57q-41 0 -69 17l14 61q27 -12 47 -12q31 0 49 25q34 46 34 185q0 91 -7 278.5t-7 273.5q0 91 13 144t44 86q39 43 101 43q36 0 58 -14z" />
<glyph glyph-name="approxequal" unicode="&#x2248;" horiz-adv-x="588"
d="M506 465l34 -29q-50 -102 -136 -102q-29 0 -53.5 9.5t-68.5 34.5q-61 36 -97 36q-33 0 -56 -20.5t-47 -58.5l-35 29q24 48 62 75.5t83 27.5q15 0 28.5 -2.5t27.5 -9t21.5 -10t22.5 -12.5t17 -10q3 -2 19.5 -11t21 -11t16.5 -7t21 -6.5t20 -1.5q31 0 53.5 19.5t45.5 59.5z
M506 284l34 -30q-50 -101 -136 -101q-29 0 -53.5 9.5t-68.5 34.5q-63 36 -97 36q-33 0 -56 -20.5t-47 -58.5l-35 29q24 47 62 74.5t83 27.5q18 0 37 -5t29 -9.5t29 -15t22 -12.5t14 -8t14.5 -8t12.5 -7t14.5 -6.5t13 -4t15 -3.5t15.5 -1q30 0 52.5 19t45.5 60z" />
<glyph glyph-name="notequal" unicode="&#x2260;" horiz-adv-x="588"
d="M419 541l-47 -103h162v-54h-183l-70 -153h253v-54h-274l-56 -123l-43 19l48 104h-156v54h178l69 153h-247v54h268l55 122z" />
<glyph glyph-name="lessequal" unicode="&#x2264;" horiz-adv-x="588"
d="M531 107l-472 240v57l472 239v-65l-415 -201v-2l415 -203v-65zM535 8h-481v56h481v-56z" />
<glyph glyph-name="greaterequal" unicode="&#x2265;" horiz-adv-x="588"
d="M60 643l472 -240v-56l-471 -240v65l414 202v2l-415 202v65zM534 8h-479v56h479v-56z" />
<glyph glyph-name="lozenge" unicode="&#x25ca;" horiz-adv-x="602"
d="M544 378l-211 -426h-68l-208 426l211 427h68zM468 376l-146 298q-13 31 -20 59h-3q-10 -35 -20 -59l-146 -294l147 -300q13 -33 19 -57h4q6 28 18 56z" />
<hkern u1="T" u2="&#x161;" k="25" />
<hkern u1="T" u2="&#xfc;" k="50" />
<hkern u1="T" u2="&#xf6;" k="50" />
<hkern u1="T" u2="&#xf2;" k="50" />
<hkern u1="T" u2="&#xee;" k="-3" />
<hkern u1="T" u2="&#xed;" k="8" />
<hkern u1="T" u2="&#xec;" k="-8" />
<hkern u1="T" u2="&#xeb;" k="50" />
<hkern u1="T" u2="&#xea;" k="75" />
<hkern u1="T" u2="&#xe8;" k="75" />
<hkern u1="T" u2="&#xe5;" k="50" />
<hkern u1="T" u2="&#xe4;" k="25" />
<hkern u1="T" u2="&#xe3;" k="50" />
<hkern u1="T" u2="&#xe2;" k="50" />
<hkern u1="T" u2="&#xe0;" k="50" />
<hkern u1="V" u2="&#xf6;" k="40" />
<hkern u1="V" u2="&#xf4;" k="60" />
<hkern u1="V" u2="&#xee;" k="-4" />
<hkern u1="V" u2="&#xeb;" k="40" />
<hkern u1="V" u2="&#xea;" k="40" />
<hkern u1="V" u2="&#xe8;" k="40" />
<hkern u1="V" u2="&#xe5;" k="40" />
<hkern u1="V" u2="&#xe4;" k="40" />
<hkern u1="V" u2="&#xe3;" k="40" />
<hkern u1="V" u2="&#xe2;" k="40" />
<hkern u1="V" u2="&#xe0;" k="40" />
<hkern u1="W" u2="&#xfc;" k="30" />
<hkern u1="W" u2="&#xf6;" k="45" />
<hkern u1="W" u2="&#xea;" k="45" />
<hkern u1="W" u2="&#xe4;" k="45" />
<hkern u1="Y" u2="&#xfc;" k="45" />
<hkern u1="Y" u2="&#xf6;" k="75" />
<hkern u1="&#x2018;" u2="&#x2018;" k="111" />
<hkern u1="&#x2019;" u2="&#x2019;" k="111" />
<hkern g1="f,fi,fl"
g2="quoteright"
k="-20" />
<hkern g1="f,fi,fl"
g2="f,germandbls,fi,fl"
k="-20" />
<hkern g1="F"
g2="A,Agrave,Aacute,Acircumflex,Atilde,Adieresis,Aring,AE"
k="60" />
<hkern g1="F"
g2="comma"
k="150" />
<hkern g1="F"
g2="period"
k="150" />
<hkern g1="L,Lslash"
g2="T"
k="30" />
<hkern g1="L,Lslash"
g2="V"
k="40" />
<hkern g1="L,Lslash"
g2="W"
k="30" />
<hkern g1="L,Lslash"
g2="y,yacute,ydieresis"
k="20" />
<hkern g1="L,Lslash"
g2="Y,Yacute,Ydieresis"
k="40" />
<hkern g1="L,Lslash"
g2="quoteright"
k="80" />
<hkern g1="P"
g2="A,Agrave,Aacute,Acircumflex,Atilde,Adieresis,Aring,AE"
k="80" />
<hkern g1="P"
g2="comma"
k="135" />
<hkern g1="P"
g2="period"
k="135" />
<hkern g1="r"
g2="v"
k="-40" />
<hkern g1="r"
g2="w"
k="-40" />
<hkern g1="r"
g2="y,yacute,ydieresis"
k="-40" />
<hkern g1="r"
g2="f,germandbls,fi,fl"
k="-20" />
<hkern g1="r"
g2="comma"
k="100" />
<hkern g1="r"
g2="period"
k="100" />
<hkern g1="r"
g2="m"
k="-8" />
<hkern g1="r"
g2="n,ntilde"
k="-8" />
<hkern g1="r"
g2="q"
k="20" />
<hkern g1="r"
g2="t"
k="-20" />
<hkern g1="r"
g2="x"
k="-40" />
<hkern g1="R"
g2="T"
k="20" />
<hkern g1="R"
g2="Y,Yacute,Ydieresis"
k="20" />
<hkern g1="T"
g2="w"
k="80" />
<hkern g1="T"
g2="y,yacute,ydieresis"
k="80" />
<hkern g1="T"
g2="A,Agrave,Aacute,Acircumflex,Atilde,Adieresis,Aring,AE"
k="80" />
<hkern g1="T"
g2="comma"
k="100" />
<hkern g1="T"
g2="period"
k="100" />
<hkern g1="T"
g2="a,agrave,aacute,acircumflex,atilde,adieresis,aring,ae"
k="100" />
<hkern g1="T"
g2="c,ccedilla"
k="100" />
<hkern g1="T"
g2="e,egrave,eacute,ecircumflex,edieresis"
k="100" />
<hkern g1="T"
g2="i,igrave,iacute,icircumflex,idieresis"
k="15" />
<hkern g1="T"
g2="o,ograve,oacute,ocircumflex,otilde,odieresis,oslash,oe"
k="100" />
<hkern g1="T"
g2="r"
k="80" />
<hkern g1="T"
g2="s,scaron"
k="100" />
<hkern g1="T"
g2="u,ugrave,uacute,ucircumflex,udieresis"
k="100" />
<hkern g1="T"
g2="colon"
k="100" />
<hkern g1="T"
g2="hyphen"
k="80" />
<hkern g1="T"
g2="semicolon"
k="100" />
<hkern g1="v"
g2="comma"
k="80" />
<hkern g1="v"
g2="period"
k="80" />
<hkern g1="V"
g2="y,yacute,ydieresis"
k="20" />
<hkern g1="V"
g2="A,Agrave,Aacute,Acircumflex,Atilde,Adieresis,Aring,AE"
k="100" />
<hkern g1="V"
g2="comma"
k="120" />
<hkern g1="V"
g2="period"
k="120" />
<hkern g1="V"
g2="a,agrave,aacute,acircumflex,atilde,adieresis,aring,ae"
k="80" />
<hkern g1="V"
g2="e,egrave,eacute,ecircumflex,edieresis"
k="80" />
<hkern g1="V"
g2="i,igrave,iacute,icircumflex,idieresis"
k="20" />
<hkern g1="V"
g2="o,ograve,oacute,ocircumflex,otilde,odieresis,oslash,oe"
k="80" />
<hkern g1="V"
g2="r"
k="40" />
<hkern g1="V"
g2="u,ugrave,uacute,ucircumflex,udieresis"
k="60" />
<hkern g1="V"
g2="colon"
k="80" />
<hkern g1="V"
g2="hyphen"
k="30" />
<hkern g1="V"
g2="semicolon"
k="80" />
<hkern g1="w"
g2="comma"
k="60" />
<hkern g1="w"
g2="period"
k="60" />
<hkern g1="W"
g2="A,Agrave,Aacute,Acircumflex,Atilde,Adieresis,Aring,AE"
k="100" />
<hkern g1="W"
g2="comma"
k="80" />
<hkern g1="W"
g2="period"
k="80" />
<hkern g1="W"
g2="a,agrave,aacute,acircumflex,atilde,adieresis,aring,ae"
k="60" />
<hkern g1="W"
g2="e,egrave,eacute,ecircumflex,edieresis"
k="60" />
<hkern g1="W"
g2="o,ograve,oacute,ocircumflex,otilde,odieresis,oslash,oe"
k="60" />
<hkern g1="W"
g2="r"
k="20" />
<hkern g1="W"
g2="u,ugrave,uacute,ucircumflex,udieresis"
k="40" />
<hkern g1="W"
g2="colon"
k="80" />
<hkern g1="W"
g2="semicolon"
k="80" />
<hkern g1="y,yacute,ydieresis"
g2="comma"
k="80" />
<hkern g1="y,yacute,ydieresis"
g2="period"
k="80" />
<hkern g1="Y,Yacute,Ydieresis"
g2="v"
k="40" />
<hkern g1="Y,Yacute,Ydieresis"
g2="A,Agrave,Aacute,Acircumflex,Atilde,Adieresis,Aring,AE"
k="100" />
<hkern g1="Y,Yacute,Ydieresis"
g2="comma"
k="100" />
<hkern g1="Y,Yacute,Ydieresis"
g2="period"
k="100" />
<hkern g1="Y,Yacute,Ydieresis"
g2="q"
k="100" />
<hkern g1="Y,Yacute,Ydieresis"
g2="a,agrave,aacute,acircumflex,atilde,adieresis,aring,ae"
k="100" />
<hkern g1="Y,Yacute,Ydieresis"
g2="e,egrave,eacute,ecircumflex,edieresis"
k="100" />
<hkern g1="Y,Yacute,Ydieresis"
g2="i,igrave,iacute,icircumflex,idieresis"
k="20" />
<hkern g1="Y,Yacute,Ydieresis"
g2="o,ograve,oacute,ocircumflex,otilde,odieresis,oslash,oe"
k="100" />
<hkern g1="Y,Yacute,Ydieresis"
g2="u,ugrave,uacute,ucircumflex,udieresis"
k="60" />
<hkern g1="Y,Yacute,Ydieresis"
g2="colon"
k="100" />
<hkern g1="Y,Yacute,Ydieresis"
g2="hyphen"
k="60" />
<hkern g1="Y,Yacute,Ydieresis"
g2="semicolon"
k="100" />
<hkern g1="Y,Yacute,Ydieresis"
g2="p"
k="80" />
<hkern g1="quoteright"
g2="t"
k="20" />
<hkern g1="quoteright"
g2="s,scaron"
k="100" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -0,0 +1,48 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@ -0,0 +1,14 @@
<html>
<head>
<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
<script src="listener.js" type="text/javascript"></script>
<link rel="stylesheet" href="nui://scoreboard/html/reset.css">
<link rel="stylesheet" href="nui://scoreboard/html/style.css">
</head>
<body>
<div style="display: none;" id="wrap">
<table id="ptbl" width="100%">
</table>
</div>
</body>
</html>

View File

@ -0,0 +1,40 @@
@import url('res/futurastd-medium.css');
html {
color: #fff;
}
#wrap {
width: 500px;
min-height: 185px;
margin-top: 10%;
margin-left: auto;
margin-right: auto;
background-color: #fff;
box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.16), 0px 2px 10px 0px rgba(0, 0, 0, 0.12);
color: rgba(255, 255, 255, 0.9);
}
table {
text-align: left;
}
th, td {
padding-left: 25px;
}
th {
padding-top: 10px;
height: 40px;
}
tr {
font-size: 120%;
font-family: 'Segoe UI';
/*text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);*/
}
tr.heading {
background-color: #43A047;
color: rgba(255, 255, 255, 0.9);
}

View File

@ -0,0 +1,48 @@
local listOn = false
Citizen.CreateThread(function()
listOn = false
while true do
Wait(0)
if IsControlPressed(0, 27)--[[ INPUT_PHONE ]] then
if not listOn then
local players = {}
ptable = GetPlayers()
for _, i in ipairs(ptable) do
local wantedLevel = GetPlayerWantedLevel(i)
r, g, b = GetPlayerRgbColour(i)
table.insert(players,
'<tr style=\"color: rgb(' .. r .. ', ' .. g .. ', ' .. b .. ')\"><td>' .. GetPlayerServerId(i) .. '</td><td>' .. GetPlayerName(i) .. '</td><td>' .. (wantedLevel and wantedLevel or tostring(0)) .. '</td></tr>'
)
end
SendNUIMessage({ text = table.concat(players) })
listOn = true
while listOn do
Wait(0)
if(IsControlPressed(0, 27) == false) then
listOn = false
SendNUIMessage({
meta = 'close'
})
break
end
end
end
end
end
end)
function GetPlayers()
local players = {}
for i = 0, 31 do
if NetworkIsPlayerActive(i) then
table.insert(players, i)
end
end
return players
end

View File

@ -0,0 +1,11 @@
client_scripts {
'client/initial.lua',
'client/leavehandler.lua',
'client/activationhandler.lua',
'client/hostservice.lua',
'client/sessionstarter.lua'
}
server_script 'server/host_lock.lua'
export 'serviceHostStuff'

View File

@ -0,0 +1,27 @@
-- triggers an event when the local network player becomes active
AddEventHandler('sessionInitialized', function()
local playerId = GetPlayerId()
-- create a looping thread
CreateThread(function()
-- wait until the player becomes active
while not IsNetworkPlayerActive(playerId) do
Wait(0)
end
-- set some defaults
AllowGameToPauseForStreaming(true)
SetMaxWantedLevel(6)
SetWantedMultiplier(0.9999999)
SetCreateRandomCops(true)
SetDitchPoliceModels(false)
DisplayPlayerNames(true)
NetworkSetHealthReticuleOption(true)
-- trigger an event on both the local client and the server
TriggerEvent('playerActivated')
TriggerServerEvent('playerActivated')
end)
end)

View File

@ -0,0 +1,55 @@
-- serving the duties of the office of the host
-- two functions from GTA script; they do 'something lock-ish'
local function acquireHostLock()
if IsThisMachineTheServer() then
SetThisMachineRunningServerScript(true)
return true
end
return false
end
local function releaseHostLock()
SetThisMachineRunningServerScript(false)
end
-- handle msgGetReadyToStartPlaying sending
function serviceHostStuff()
-- acquire the host lock
if acquireHostLock() then
-- check if players want to join
for i = 0, 31 do
-- does this index?
if PlayerWantsToJoinNetworkGame(i) then
-- well, get ready to start playing!
TellNetPlayerToStartPlaying(i, 0)
TriggerServerEvent('playerJoining', i)
end
end
-- release the host lock
releaseHostLock()
end
end
-- host service loop
CreateThread(function()
NetworkSetScriptLobbyState(false)
SwitchArrowAboveBlippedPickups(true)
UsePlayerColourInsteadOfTeamColour(true)
LoadAllPathNodes(true)
SetSyncWeatherAndGameTime(true)
while true do
Wait(0)
serviceHostStuff()
-- launch the local player, for the initial host scenario
if LocalPlayerIsReadyToStartPlaying() then
LaunchLocalPlayerInNetworkGame()
end
end
end)

View File

@ -0,0 +1,124 @@
-- state variable for session host lock
local sessionHostPending = false
local sessionHostResult
AddEventHandler('sessionHostResult', function(result)
if not sessionHostPending then
return
end
sessionHostResult = result
sessionHostPending = false
end)
local attempts = 0
-- allow early script to create the player
AddEventHandler('playerInfoCreated', function()
CreateThread(function()
-- so that the game won't trigger the citizen disconnect handler
SafeguardDisconnect(true)
-- loop for 3 times
while attempts < 3 do
-- 'find' games (this will store the host session in memory, or if no host exists, tell us later)
NetworkFindGame(16, false, 0, 0)
-- we don't have to wait for the finding to complete; TestSessionFind.cpp in hooks_ny will instantly return
local gamesFound = NetworkGetNumberOfGames(_r)
-- if we found at least one game (if the game isn't hooked, this can be any amount; but
-- we can't trust the implementation in that case anyway)
local needsToHost = true -- whether we need to host after completing a possible join
if gamesFound > 0 then
-- join the game
NetworkJoinGame(0)
SetLoadingText('Entering session') -- status text
-- wait for the join to complete
while NetworkJoinGamePending() do
Wait(0)
end
-- if we succeeded, we're now a session member, and will not need to host
if NetworkJoinGameSucceeded() then
needsToHost = false
break
end
end
-- if we didn't find any games, or a join timed out, we'll *consider* hosting
if needsToHost then
-- make sure we don't have an actual other host waiting for us
sessionHostPending = true -- to trigger a wait loop below
TriggerServerEvent('hostingSession')
SetLoadingText('Initializing session') -- some vague status text
-- wait for the server to respond to our request
while sessionHostPending do
Wait(0)
end
if sessionHostResult == 'wait' then
-- TODO: not implemented yet: wait for a message from the server, then attempt finding a game/joining a game again
sessionHostPending = true
while sessionHostPending do
Wait(0)
end
if sessionHostResult == 'free' then
goto endLoop
end
end
if sessionHostResult == 'conflict' and gamesFound > 0 then
-- there's already a host which is working perfectly fine; show a message to the player
--error('session creation conflict: could not connect to original host')
echo("session creation conflict\n")
goto endLoop
end
-- we got a green light to host; start hosting
if not NetworkHostGameE1(16, false, 32, false, 0, 0) then
echo("session creation failure from NetworkHostGameE1\n")
error('failed to initialize session')
end
-- wait for internal processing to complete
while NetworkHostGamePending() do
Wait(0)
end
-- another failure check
if not NetworkHostGameSucceeded() then
echo("session creation failure from NetworkHostGameSucceeded\n")
error('failed to initialize session')
end
TriggerServerEvent('hostedSession')
break
end
::endLoop::
attempts = attempts + 1
end
SafeguardDisconnect(false)
if attempts >= 3 then
error("Could not connect to session provider.")
end
SetLoadingText('Look at that!')
-- signal local game-specific resources to start
TriggerEvent('sessionInitialized')
TriggerServerEvent('sessionInitialized')
end)
end)

View File

@ -0,0 +1,31 @@
-- handles the script end of the flag the 'leave game' option in the pause menu sets
CreateThread(function()
while true do
Wait(0)
-- if the flag is set
if DoesGameCodeWantToLeaveNetworkSession() then
-- if we're part of a started session; end it first (FIXME: will this break others when we're host?)
if NetworkIsSessionStarted() then
NetworkEndSession()
-- wait for the session to be ended
while NetworkEndSessionPending() do
Wait(0)
end
end
-- attempt to leave the game
NetworkLeaveGame()
-- while we're waiting to leave...
while NetworkLeaveGamePending() do
Wait(0)
end
-- reinitialize the game as a network game (TODO: call into citigame for UI/NetLibrary leaving)
--ShutdownAndLaunchNetworkGame(0) -- episode id is arg
ShutdownNetworkCit('Left');
end
end
end)

View File

@ -0,0 +1,26 @@
-- more rline stuff, this does some late-term session management (which I think has some race condition with launching the network player?)
AddEventHandler('sessionInitialized', function()
if IsThisMachineTheServer() then
-- unknown stuff, seems needed though
NetworkChangeExtendedGameConfigCit()
CreateThread(function()
Wait(1500)
if not NetworkIsSessionStarted() then
NetworkStartSession()
while NetworkStartSessionPending() do
Wait(0)
end
if not NetworkStartSessionSucceeded() then
ForceLoadingScreen(0)
SetMsgForLoadingScreen("MO_SNI")
return
end
end
end)
end
end)

View File

@ -0,0 +1,67 @@
-- whitelist c2s events
RegisterServerEvent('hostingSession')
RegisterServerEvent('hostedSession')
-- event handler for pre-session 'acquire'
local currentHosting
local hostReleaseCallbacks = {}
-- TODO: add a timeout for the hosting lock to be held
-- TODO: add checks for 'fraudulent' conflict cases of hosting attempts (typically whenever the host can not be reached)
AddEventHandler('hostingSession', function()
-- if the lock is currently held, tell the client to await further instruction
if currentHosting then
TriggerClientEvent('sessionHostResult', source, 'wait')
-- register a callback for when the lock is freed
table.insert(hostReleaseCallbacks, function()
TriggerClientEvent('sessionHostResult', source, 'free')
end)
return
end
-- if the current host was last contacted less than a second ago
if GetHostId() >= 1 then
if GetPlayerLastMsg(GetHostId()) < 1000 then
TriggerClientEvent('sessionHostResult', source, 'conflict')
return
end
end
hostReleaseCallbacks = {}
currentHosting = source
TriggerClientEvent('sessionHostResult', source, 'go')
-- set a timeout of 5 seconds
SetTimeout(5000, function()
if not currentHosting then
return
end
currentHosting = nil
for _, cb in ipairs(hostReleaseCallbacks) do
cb()
end
end)
end)
AddEventHandler('hostedSession', function()
-- check if the client is the original locker
if currentHosting ~= source then
-- TODO: drop client as they're clearly lying
print(currentHosting, '~=', source)
return
end
-- free the host lock (call callbacks and remove the lock value)
for _, cb in ipairs(hostReleaseCallbacks) do
cb()
end
currentHosting = nil
end)

View File

@ -0,0 +1,9 @@
client_script 'spawnmanager.lua'
export 'getRandomSpawnPoint'
export 'spawnPlayer'
export 'addSpawnPoint'
export 'loadSpawns'
export 'setAutoSpawn'
export 'setAutoSpawnCallback'
export 'forceRespawn'

View File

@ -0,0 +1,350 @@
-- in-memory spawnpoint array for this script execution instance
local spawnPoints = {}
-- auto-spawn enabled flag
local autoSpawnEnabled = false
local autoSpawnCallback
-- support for mapmanager maps
AddEventHandler('getMapDirectives', function(add)
-- call the remote callback
add('spawnpoint', function(state, model)
-- return another callback to pass coordinates and so on (as such syntax would be [spawnpoint 'model' { options/coords }])
return function(opts)
local x, y, z, heading
local s, e = pcall(function()
-- is this a map or an array?
if opts.x then
x = opts.x
y = opts.y
z = opts.z
else
x = opts[1]
y = opts[2]
z = opts[3]
end
x = x + 0.0001
y = y + 0.0001
z = z + 0.0001
-- get a heading and force it to a float, or just default to null
heading = opts.heading and (opts.heading + 0.01) or 0
-- add the spawnpoint
addSpawnPoint({
x = x, y = y, z = z,
heading = heading,
model = model
})
-- recalculate the model for storage
if not tonumber(model) then
model = GetHashKey(model, _r)
end
-- store the spawn data in the state so we can erase it later on
state.add('xyz', { x, y, z })
state.add('model', model)
end)
if not s then
Citizen.Trace(e .. "\n")
end
end
-- delete callback follows on the next line
end, function(state, arg)
-- loop through all spawn points to find one with our state
for i, sp in ipairs(spawnPoints) do
-- if it matches...
if sp.x == state.xyz[1] and sp.y == state.xyz[2] and sp.z == state.xyz[3] and sp.model == state.model then
-- remove it.
table.remove(spawnPoints, i)
return
end
end
end)
end)
-- loads a set of spawn points from a JSON string
function loadSpawns(spawnString)
-- decode the JSON string
local data = json.decode(spawnString)
-- do we have a 'spawns' field?
if not data.spawns then
error("no 'spawns' in JSON data")
end
-- loop through the spawns
for i, spawn in ipairs(data.spawns) do
-- and add it to the list (validating as we go)
addSpawnPoint(spawn)
end
end
function addSpawnPoint(spawn)
-- validate the spawn (position)
if not tonumber(spawn.x) or not tonumber(spawn.y) or not tonumber(spawn.z) then
error("invalid spawn position")
end
-- heading
if not tonumber(spawn.heading) then
error("invalid spawn heading")
end
-- model (try integer first, if not, hash it)
local model = spawn.model
if not tonumber(spawn.model) then
model = GetHashKey(spawn.model)
end
-- is the model actually a model?
if not IsModelInCdimage(model) then
error("invalid spawn model")
end
-- is is even a ped?
-- not in V?
--[[if not IsThisModelAPed(model) then
error("this model ain't a ped!")
end]]
-- overwrite the model in case we hashed it
spawn.model = model
-- all OK, add the spawn entry to the list
table.insert(spawnPoints, spawn)
end
-- changes the auto-spawn flag
function setAutoSpawn(enabled)
autoSpawnEnabled = enabled
end
-- sets a callback to execute instead of 'native' spawning when trying to auto-spawn
function setAutoSpawnCallback(cb)
autoSpawnCallback = cb
autoSpawnEnabled = true
end
-- function as existing in original R* scripts
local function freezePlayer(id, freeze)
local player = id
SetPlayerControl(player, not freeze, false)
local ped = GetPlayerPed(player)
if not freeze then
if not IsEntityVisible(ped) then
SetEntityVisible(ped, true)
end
if not IsPedInAnyVehicle(ped) then
SetEntityCollision(ped, true)
end
FreezeEntityPosition(ped, false)
--SetCharNeverTargetted(ped, false)
SetPlayerInvincible(player, false)
else
if IsEntityVisible(ped) then
SetEntityVisible(ped, false)
end
SetEntityCollision(ped, false)
FreezeEntityPosition(ped, true)
--SetCharNeverTargetted(ped, true)
SetPlayerInvincible(player, true)
--RemovePtfxFromPed(ped)
if not IsPedFatallyInjured(ped) then
ClearPedTasksImmediately(ped)
end
end
end
function loadScene(x, y, z)
NewLoadSceneStart(x, y, z, 0.0, 0.0, 0.0, 20.0, 0)
while IsNewLoadSceneActive() do
networkTimer = GetNetworkTimer()
NetworkUpdateLoadScene()
end
end
-- to prevent trying to spawn multiple times
local spawnLock = false
-- spawns the current player at a certain spawn point index (or a random one, for that matter)
function spawnPlayer(spawnIdx, cb)
if spawnLock then
return
end
spawnLock = true
Citizen.CreateThread(function()
DoScreenFadeOut(500)
while IsScreenFadingOut() do
Citizen.Wait(0)
end
-- if the spawn isn't set, select a random one
if not spawnIdx then
spawnIdx = GetRandomIntInRange(1, #spawnPoints + 1)
end
-- get the spawn from the array
local spawn
if type(spawnIdx) == 'table' then
spawn = spawnIdx
else
spawn = spawnPoints[spawnIdx]
end
-- validate the index
if not spawn then
Citizen.Trace("tried to spawn at an invalid spawn index\n")
spawnLock = false
return
end
-- freeze the local player
freezePlayer(PlayerId(), true)
-- if the spawn has a model set
if spawn.model then
RequestModel(spawn.model)
-- load the model for this spawn
while not HasModelLoaded(spawn.model) do
RequestModel(spawn.model)
Wait(0)
end
-- change the player model
SetPlayerModel(PlayerId(), spawn.model)
-- release the player model
SetModelAsNoLongerNeeded(spawn.model)
end
-- preload collisions for the spawnpoint
RequestCollisionAtCoord(spawn.x, spawn.y, spawn.z)
-- spawn the player
--ResurrectNetworkPlayer(GetPlayerId(), spawn.x, spawn.y, spawn.z, spawn.heading)
local ped = GetPlayerPed(-1)
-- V requires setting coords as well
SetEntityCoordsNoOffset(ped, spawn.x, spawn.y, spawn.z, false, false, false, true)
NetworkResurrectLocalPlayer(spawn.x, spawn.y, spawn.z, spawn.heading, true, true, false)
-- gamelogic-style cleanup stuff
ClearPedTasksImmediately(ped)
--SetEntityHealth(ped, 300) -- TODO: allow configuration of this?
RemoveAllPedWeapons(ped) -- TODO: make configurable (V behavior?)
ClearPlayerWantedLevel(PlayerId())
-- why is this even a flag?
--SetCharWillFlyThroughWindscreen(ped, false)
-- set primary camera heading
--SetGameCamHeading(spawn.heading)
--CamRestoreJumpcut(GetGameCam())
-- load the scene; streaming expects us to do it
--ForceLoadingScreen(true)
--loadScene(spawn.x, spawn.y, spawn.z)
--ForceLoadingScreen(false)
ShutdownLoadingScreen()
DoScreenFadeIn(500)
while IsScreenFadingIn() do
Citizen.Wait(0)
end
-- and unfreeze the player
freezePlayer(PlayerId(), false)
TriggerEvent('playerSpawned', spawn)
if cb then
cb(spawn)
end
spawnLock = false
end)
end
-- automatic spawning monitor thread, too
local respawnForced
local diedAt
Citizen.CreateThread(function()
-- main loop thing
while true do
Citizen.Wait(50)
local playerPed = GetPlayerPed(-1)
if playerPed and playerPed ~= -1 then
-- check if we want to autospawn
if autoSpawnEnabled then
if NetworkIsPlayerActive(PlayerId()) then
if (diedAt and (GetTimeDifference(GetGameTimer(), diedAt) > 2000)) or respawnForced then
Citizen.Trace("forcin' respawn\n")
if autoSpawnCallback then
autoSpawnCallback()
else
spawnPlayer()
end
respawnForced = false
end
end
end
if IsEntityDead(playerPed) then
if not diedAt then
diedAt = GetGameTimer()
end
else
diedAt = nil
end
end
end
end)
function forceRespawn()
spawnLock = false
respawnForced = true
end
--[[AddEventHandler('playerInfoCreated', function()
loadSpawns(json.encode({
spawns = {
{ x = -238.511, y = 954.025, z = 11.0803, heading = 90.0, model = 'ig_brucie' },
{ x = -310.001, y = 945.603, z = 14.3728, heading = 90.0, model = 'ig_bulgarin' },
}
}))
end)
AddEventHandler('playerActivated', function()
respawnForced = true
end)]]

View File

@ -0,0 +1,2 @@
client_script 'client.lua'
server_script 'server.lua'

View File

@ -0,0 +1,208 @@
local function getPickupType(i)
if i == 2 then
return 30
elseif i == 1 then
return 31
end
local w = GenerateRandomIntInRange(5, 17, _i)
if w == 8 or w == 6 then
w = 4
end
return w
end
local function createPickup(ptype, etype, unk, x, y, z)
if ptype == 30 then
CreatePickupWithAmmo(0x972daa10, etype, 0, x, y, z, _i)
elseif ptype == 31 then
CreatePickupWithAmmo(0x3fc62578, etype, 0, x, y, z, _i)
else
CreatePickupWithAmmo(GetWeapontypeModel(ptype, _i), etype, 60, x, y, z, _i)
end
end
local pickupSeed
local function createPickups()
echo("creating algo pickups\n")
SetRandomSeed(pickupSeed)
createPickup( getPickupType( 2 ), 23, 200, -563.10640000, 293.52680000, 5.65930000 )
createPickup( getPickupType( 2 ), 23, 200, 79.41570000, -839.53680000, 3.99560000 )
createPickup( getPickupType( 2 ), 23, 200, -277.35550000, -533.76340000, 3.92420000 )
createPickup( getPickupType( 2 ), 23, 200, -491.51540000, -173.97790000, 6.90340000 )
createPickup( getPickupType( 2 ), 23, 200, -235.68930000, 739.30850000, 6.12510000 )
createPickup( getPickupType( 2 ), 23, 200, -539.49120000, 1362.38800000, 16.47050000 )
createPickup( getPickupType( 2 ), 23, 200, -180.02360000, -823.41240000, 4.11750000 )
createPickup( getPickupType( 2 ), 23, 200, 173.60920000, 236.49170000, 13.76010000 )
createPickup( getPickupType( 2 ), 23, 200, 89.24590000, 1152.34900000, 13.57080000 )
createPickup( getPickupType( 2 ), 23, 200, 63.60470000, -439.60590000, 13.75830000 )
createPickup( getPickupType( 2 ), 23, 200, -226.95040000, 1714.70300000, 14.75500000 )
createPickup( getPickupType( 2 ), 23, 200, 130.44570000, 467.39240000, 13.91780000 )
createPickup( getPickupType( 2 ), 23, 200, -529.52310000, -339.29980000, 5.04460000 )
createPickup( getPickupType( 2 ), 23, 200, -477.98870000, 1707.35300000, 7.46380000 )
createPickup( getPickupType( 2 ), 23, 200, -636.54130000, -45.71210000, 3.81230000 )
createPickup( getPickupType( 2 ), 23, 200, 140.68720000, -857.79680000, 3.77320000 )
--createPickup( getPickupType( 2 ), 23, 200, -108.89000000, 64499, 4.11910000 )
createPickup( getPickupType( 2 ), 23, 200, 348.54010000, -431.52940000, 3.54320000 )
createPickup( getPickupType( 2 ), 23, 200, 166.63900000, 1080.60900000, 13.62470000 )
createPickup( getPickupType( 2 ), 23, 200, -145.57280000, 1694.71300000, 15.72350000 )
createPickup( getPickupType( 2 ), 23, 200, 64.54370000, 261.20720000, 14.53200000 )
createPickup( getPickupType( 2 ), 23, 200, -507.19360000, 533.97330000, 5.67160000 )
createPickup( getPickupType( 2 ), 23, 200, -410.23560000, -141.84080000, 11.61790000 )
createPickup( getPickupType( 2 ), 23, 200, -248.26890000, -589.95000000, 3.78540000 )
createPickup( getPickupType( 2 ), 23, 200, 115.38710000, 741.87240000, 13.56160000 )
createPickup( getPickupType( 2 ), 23, 200, 49.21290000, 1350.85200000, 15.25260000 )
createPickup( getPickupType( 2 ), 23, 200, 332.02520000, -158.35070000, 8.06910000 )
createPickup( getPickupType( 1 ), 23, 200, -462.60650000, 775.56370000, 8.98430000 )
createPickup( getPickupType( 1 ), 23, 200, -66.39730000, 1550.17700000, 17.64730000 )
createPickup( getPickupType( 1 ), 23, 200, -47.94850000, 35.91300000, 13.84780000 )
createPickup( getPickupType( 1 ), 23, 200, -210.80500000, 1410.40400000, 19.35510000 )
createPickup( getPickupType( 1 ), 23, 200, 136.81580000, 387.45690000, 14.02680000 )
createPickup( getPickupType( 1 ), 23, 200, -604.36200000, 339.06450000, 3.67190000 )
createPickup( getPickupType( 1 ), 23, 200, -135.90700000, 819.94900000, 17.62560000 )
createPickup( getPickupType( 1 ), 23, 200, -437.64390000, 430.90700000, 8.93740000 )
createPickup( getPickupType( 1 ), 23, 200, -522.79810000, 1018.30500000, 8.79210000 )
createPickup( getPickupType( 1 ), 23, 200, -593.54960000, 1165.60900000, 8.94090000 )
createPickup( getPickupType( 1 ), 23, 200, 89.78390000, 1251.53900000, 14.86610000 )
createPickup( getPickupType( 1 ), 23, 200, -108.15450000, 1271.20900000, 19.43000000 )
createPickup( getPickupType( 1 ), 23, 200, -5.26000000, -447.87000000, 13.75820000 )
createPickup( getPickupType( 1 ), 23, 200, 171.83730000, -807.45750000, 3.97040000 )
createPickup( getPickupType( 1 ), 23, 200, 0.32430000, -761.24270000, 4.08570000 )
createPickup( getPickupType( 1 ), 23, 200, -526.37620000, 593.51290000, 12.12300000 )
createPickup( getPickupType( 1 ), 23, 200, -554.97370000, 806.93090000, 8.05520000 )
createPickup( getPickupType( 1 ), 23, 200, 13.89740000, 1147.71300000, 13.24760000 )
createPickup( getPickupType( 1 ), 23, 200, 179.53490000, 691.26530000, 7.18630000 )
createPickup( getPickupType( 1 ), 23, 200, -463.63800000, 899.77910000, 8.96270000 )
createPickup( getPickupType( 1 ), 23, 200, -467.32180000, 1556.19000000, 17.47570000 )
createPickup( getPickupType( 1 ), 23, 200, -284.66330000, 1600.64600000, 19.41570000 )
createPickup( getPickupType( 1 ), 23, 200, -311.56230000, 1733.49700000, 12.12580000 )
createPickup( getPickupType( 1 ), 23, 200, -99.43640000, 1350.29900000, 19.41500000 )
createPickup( getPickupType( 1 ), 23, 200, -534.05160000, 1610.99600000, 8.39809000 )
createPickup( getPickupType( 1 ), 23, 200, 91.99830000, -318.91000000, 13.61250000 )
createPickup( getPickupType( 1 ), 23, 200, -619.61000000, -115.38000000, 5.59590000 )
createPickup( getPickupType( 1 ), 23, 200, 361.06920000, -477.77790000, 4.81800000 )
createPickup( getPickupType( 1 ), 23, 200, -404.86420000, 1487.26800000, 17.86060000 )
createPickup( getPickupType( 1 ), 23, 200, -572.86970000, 227.56950000, 3.66220000 )
createPickup( getPickupType( 0 ), 23, 200, 150.65500000, 913.75690000, 7.35240000 )
createPickup( getPickupType( 0 ), 23, 200, -151.58120000, 1004.30900000, 5.22660000 )
createPickup( getPickupType( 0 ), 23, 200, -126.16370000, 554.53360000, 13.76430000 )
createPickup( getPickupType( 0 ), 23, 200, -389.27630000, 1763.59200000, 8.23320000 )
createPickup( getPickupType( 0 ), 23, 200, -414.94510000, 376.06220000, 11.07520000 )
createPickup( getPickupType( 0 ), 23, 200, -348.11940000, 631.42010000, 13.58580000 )
createPickup( getPickupType( 0 ), 23, 200, -561.26700000, 1457.39500000, 16.53680000 )
createPickup( getPickupType( 0 ), 23, 200, -656.75510000, 1140.68700000, 8.81430000 )
createPickup( getPickupType( 0 ), 23, 200, 286.89990000, -392.37890000, 3.97690000 )
createPickup( getPickupType( 0 ), 23, 200, 267.28000000, -686.88580000, 3.87500000 )
createPickup( getPickupType( 0 ), 23, 200, 185.85650000, 801.42330000, 7.45320000 )
createPickup( getPickupType( 0 ), 23, 200, -33.85220000, 772.73390000, 13.64890000 )
createPickup( getPickupType( 0 ), 23, 200, -658.17000000, 809.31000000, 3.10420000 )
--createPickup( getPickupType( 0 ), 23, 200, 65123, 1658.10000000, 20.08190000 )
--createPickup( getPickupType( 0 ), 23, 200, 65307, 1445.20000000, 19.45000000 )
createPickup( getPickupType( 0 ), 23, 200, -579.01340000, 1414.69400000, 14.47110000 )
createPickup( getPickupType( 0 ), 23, 200, -570.93210000, 158.32300000, 3.66220000 )
createPickup( getPickupType( 0 ), 23, 200, -641.65510000, -195.11170000, 3.94450000 )
createPickup( getPickupType( 0 ), 23, 200, -373.43770000, 1563.55700000, 19.15690000 )
createPickup( getPickupType( 0 ), 23, 200, -242.26720000, -515.22510000, 3.93780000 )
createPickup( getPickupType( 0 ), 23, 200, 83.27290000, 128.63830000, 13.74580000 )
createPickup( getPickupType( 0 ), 23, 200, 100.85700000, -751.07600000, 3.95820000 )
createPickup( getPickupType( 0 ), 23, 200, 148.27850000, -520.31800000, 13.76100000 )
createPickup( getPickupType( 0 ), 23, 200, -145.85800000, -436.54300000, 13.71600000 )
createPickup( getPickupType( 0 ), 23, 200, 30.52840000, -319.98200000, 13.72060000 )
createPickup( getPickupType( 0 ), 23, 200, -121.35400000, -765.42500000, 4.20210000 )
createPickup( getPickupType( 0 ), 23, 200, -301.78400000, -408.61900000, 3.82400000 )
createPickup( getPickupType( 0 ), 23, 200, -221.12500000, -244.63100000, 13.55080000 )
createPickup( getPickupType( 0 ), 23, 200, 345.52040000, -409.60800000, 3.69260000 )
createPickup( getPickupType( 0 ), 23, 200, -187.78400000, -104.23300000, 13.59230000 )
createPickup( getPickupType( 0 ), 23, 200, 23.03970000, -41.08220000, 13.81190000 )
createPickup( getPickupType( 0 ), 23, 200, -105.90000000, 129.42250000, 13.72260000 )
createPickup( getPickupType( 0 ), 23, 200, -470.49600000, 190.20460000, 8.85820000 )
createPickup( getPickupType( 0 ), 23, 200, -108.92700000, 371.07960000, 13.80730000 )
createPickup( getPickupType( 0 ), 23, 200, -308.23960000, 455.43910000, 13.69960000 )
createPickup( getPickupType( 0 ), 23, 200, 113.34910000, 650.53870000, 13.71280000 )
createPickup( getPickupType( 0 ), 23, 200, -69.89160000, 1147.73100000, 13.76710000 )
createPickup( getPickupType( 0 ), 23, 200, 29.31370000, 761.22520000, 13.50620000 )
createPickup( getPickupType( 0 ), 23, 200, 52.12710000, 889.81030000, 13.65160000 )
createPickup( getPickupType( 0 ), 23, 200, -616.57000000, 1001.96400000, 8.91920000 )
createPickup( getPickupType( 0 ), 23, 200, -491.81600000, 949.22980000, 8.96670000 )
createPickup( getPickupType( 0 ), 23, 200, 5.79550000, 1028.96500000, 13.72000000 )
createPickup( getPickupType( 0 ), 23, 200, -542.94400000, 1303.59300000, 16.25890000 )
createPickup( getPickupType( 0 ), 23, 200, -273.10860000, 1211.38200000, 17.78520000 )
createPickup( getPickupType( 0 ), 23, 200, -292.14300000, 1331.30300000, 23.60140000 )
createPickup( getPickupType( 0 ), 23, 200, -364.25800000, 1371.32500000, 14.19140000 )
createPickup( getPickupType( 0 ), 23, 200, -34.57900000, 1410.33300000, 19.42230000 )
createPickup( getPickupType( 0 ), 23, 200, -161.42200000, 1555.53300000, 17.37360000 )
createPickup( getPickupType( 0 ), 23, 200, 210.82320000, -105.36900000, 13.76120000 )
createPickup( getPickupType( 0 ), 23, 200, -124.28630000, -530.18220000, 13.76020000 )
createPickup( getPickupType( 0 ), 23, 200, -220.20000000, -883.72000000, 3.67810000 )
createPickup( getPickupType( 0 ), 23, 200, -107.78000000, -821.86000000, 4.12670000 )
createPickup( getPickupType( 0 ), 23, 200, 78.03000000, -670.74000000, 13.76770000 )
createPickup( getPickupType( 0 ), 23, 200, 151.18900000, -613.04700000, 9.63030000 )
createPickup( getPickupType( 0 ), 23, 200, -27.54000000, -823.69000000, 4.45430000 )
createPickup( getPickupType( 0 ), 23, 200, 200.28920000, -698.77010000, 3.95350000 )
createPickup( getPickupType( 0 ), 23, 200, -195.15000000, -711.21000000, 3.96790000 )
createPickup( getPickupType( 0 ), 23, 200, 100.96000000, -512.62000000, 15.08830000 )
createPickup( getPickupType( 0 ), 23, 200, 306.47000000, -623.30000000, 4.19430000 )
createPickup( getPickupType( 0 ), 23, 200, -79.41310000, 614.20590000, 13.76610000 )
createPickup( getPickupType( 0 ), 23, 200, -385.48000000, 738.49000000, 13.76610000 )
createPickup( getPickupType( 0 ), 23, 200, -434.99950000, 1101.79400000, 9.24650000 )
createPickup( getPickupType( 0 ), 23, 200, -31.37680000, 959.19130000, 13.92130000 )
createPickup( getPickupType( 0 ), 23, 200, -268.25000000, 751.37000000, 10.86610000 )
createPickup( getPickupType( 0 ), 23, 200, -199.04800000, 880.55260000, 5.15900000 )
createPickup( getPickupType( 0 ), 23, 200, -330.31000000, 1134.31000000, 12.49350000 )
createPickup( getPickupType( 0 ), 23, 200, -174.81230000, 938.15850000, 10.64700000 )
createPickup( getPickupType( 0 ), 23, 200, -115.90590000, 1043.57100000, 5.15920000 )
createPickup( getPickupType( 0 ), 23, 200, -315.16000000, 867.71000000, 8.89900000 )
createPickup( getPickupType( 0 ), 23, 200, -564.60000000, 1183.60000000, 9.01900000 )
createPickup( getPickupType( 0 ), 23, 200, -498.02150000, 1183.31100000, 13.21080000 )
createPickup( getPickupType( 0 ), 23, 200, -414.29530000, 1365.34600000, 15.55880000 )
createPickup( getPickupType( 0 ), 23, 200, -468.98060000, 1468.96400000, 17.86100000 )
createPickup( getPickupType( 0 ), 23, 200, -112.28410000, 1672.74500000, 17.61140000 )
createPickup( getPickupType( 0 ), 23, 200, -219.91810000, 1277.23200000, 22.09290000 )
createPickup( getPickupType( 0 ), 23, 200, 2.40000000, 1197.70000000, 16.47760000 )
createPickup( getPickupType( 0 ), 23, 200, -25.70000000, 1250.90000000, 19.43250000 )
createPickup( getPickupType( 0 ), 23, 200, -65.74770000, 1498.05800000, 17.44880000 )
createPickup( getPickupType( 0 ), 23, 200, -383.30600000, 319.06300000, 13.75090000 )
--createPickup( getPickupType( 0 ), 23, 200, 65250, 344.20000000, 13.66590000 )
createPickup( getPickupType( 0 ), 23, 200, -212.60000000, 346.70000000, 14.03540000 )
createPickup( getPickupType( 0 ), 23, 200, -66.26470000, 278.22370000, 13.76360000 )
createPickup( getPickupType( 0 ), 23, 200, -181.14000000, 491.28420000, 13.71490000 )
createPickup( getPickupType( 0 ), 23, 200, -24.70000000, 405.20000000, 14.76350000 )
createPickup( getPickupType( 0 ), 23, 200, 51.61110000, 464.46720000, 13.69600000 )
createPickup( getPickupType( 0 ), 23, 200, 27.60000000, 374.20000000, 13.70190000 )
createPickup( getPickupType( 0 ), 23, 200, -603.98900000, 612.11540000, 3.85550000 )
createPickup( getPickupType( 0 ), 23, 200, -337.70000000, 215.40000000, 13.74920000 )
createPickup( getPickupType( 0 ), 23, 200, -383.50000000, 556.30000000, 13.77870000 )
createPickup( getPickupType( 0 ), 23, 200, -442.96920000, 590.37180000, 10.25190000 )
createPickup( getPickupType( 0 ), 23, 200, 141.80000000, 211.20000000, 13.76310000 )
createPickup( getPickupType( 0 ), 23, 200, -192.30000000, 162.40000000, 13.98940000 )
createPickup( getPickupType( 0 ), 23, 200, -348.60300000, -188.71300000, 13.64900000 )
createPickup( getPickupType( 0 ), 23, 200, -273.48200000, -157.81400000, 13.88300000 )
createPickup( getPickupType( 0 ), 23, 200, -117.97000000, -335.54000000, 13.73490000 )
createPickup( getPickupType( 0 ), 23, 200, -12.45000000, -218.40000000, 13.63990000 )
createPickup( getPickupType( 0 ), 23, 200, 179.94720000, -254.52090000, 11.85560000 )
createPickup( getPickupType( 0 ), 23, 200, 264.98180000, -302.83180000, 5.59270000 )
createPickup( getPickupType( 0 ), 23, 200, 162.58500000, -158.31150000, 13.92630000 )
createPickup( getPickupType( 0 ), 23, 200, 113.02140000, -39.66420000, 13.76250000 )
createPickup( getPickupType( 0 ), 23, 200, -126.60700000, -117.37200000, 13.81500000 )
createPickup( getPickupType( 0 ), 23, 200, 207.01740000, 20.70740000, 13.71320000 )
createPickup( getPickupType( 0 ), 23, 200, -254.45000000, -43.88000000, 13.76330000 )
createPickup( getPickupType( 0 ), 23, 200, -347.84500000, 105.27390000, 13.81310000 )
createPickup( getPickupType( 0 ), 23, 200, -345.03400000, -100.46700000, 13.70210000 )
createPickup( getPickupType( 0 ), 23, 200, -445.05100000, 131.98950000, 8.83120000 )
createPickup( getPickupType( 0 ), 23, 200, -490.37520000, 25.33320000, 6.86600000 )
createPickup( getPickupType( 0 ), 23, 200, -572.51200000, 86.31020000, 3.81230000 )
createPickup( getPickupType( 0 ), 23, 200, 29.85000000, -601.28000000, 13.69580000 )
createPickup( getPickupType( 0 ), 23, 200, -184.29000000, 102.09000000, 13.76770000 )
end
AddEventHandler('createGunPickups', function(seed)
pickupSeed = seed
RemoveAllPickupsOfType(23)
createPickups()
end)

View File

@ -0,0 +1,9 @@
math.randomseed(GetInstanceId())
local randomBase = math.random()
RegisterServerEvent('playerActivated')
AddEventHandler('playerActivated', function()
TriggerClientEvent('createGunPickups', source, randomBase)
end)

View File

@ -0,0 +1,4 @@
description 'early init for game script'
client_script 'init.lua'
server_script 'server.lua'

View File

@ -0,0 +1,42 @@
CreateThread(function()
local bit = function()
return math.random()
end
local function freezePlayer(id, freeze)
local player = ConvertIntToPlayerindex(id)
SetPlayerControlForNetwork(player, not freeze, false)
local ped = GetPlayerChar(player, _i)
if not freeze then
if not IsCharVisible(ped) then
SetCharVisible(ped, true)
end
if not IsCharInAnyCar(ped) then
SetCharCollision(ped, true)
end
FreezeCharPosition(ped, false)
SetCharNeverTargetted(ped, false)
SetPlayerInvincible(player, false)
else
FreezeCharPosition(ped, true)
SetCharNeverTargetted(ped, true)
SetPlayerInvincible(player, true)
if not IsCharFatallyInjured(ped) then
--ClearCharTasksImmediately(ped)
end
end
end
local player = CreatePlayer(0, -2000.5 + bit(), -2000.5 + bit(), 240.5 + bit(), _i)
freezePlayer(GetPlayerId(), true)
SetLoadingText("this is too lovely")
TriggerEvent('playerInfoCreated')
end)

View File

@ -0,0 +1,4 @@
-- prevent stopping gameInit on the server
AddEventHandler('onResourceStop', function(name)
if name == 'gameInit' then CancelEvent() end
end)

View File

@ -0,0 +1,6 @@
files {
'index.html',
'keks.css',
'bankgothic.ttf',
'loadscreen.jpg'
}

Binary file not shown.

View File

@ -0,0 +1,41 @@
<html>
<head>
<link href="keks.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="backdrop">
<div class="top">
<h1 title="Free Mode">Free Mode</h1>
<h2 title="Algonquin">Algonquin</h2>
</div>
<div class="letni">
<h2 title="INTEL">Intel</h2>
<div class="loadbar"><div class="thingy"></div></div>
<p>The Statue of Happiness has a heart. Have one too!</p>
</div>
<div class="bottom">
<div id="gradient">
</div>
</div>
</div>
<script type="text/javascript">
var left = -10;
var self = function()
{
var elem = document.querySelector('.thingy');
left += (0.15 / 60) * 100;
if (left >= 100)
{
left = -10;
}
elem.style.left = left + '%';
requestAnimationFrame(self);
};
requestAnimationFrame(self);
</script>
</body>
</html>

View File

@ -0,0 +1,147 @@
body
{
margin: 0px;
padding: 0px;
}
.backdrop
{
position: relative;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background-image: url(loadscreen.jpg);
background-size: 100% 100%;
}
.bottom
{
position: absolute;
bottom: 0px;
width: 100%;
height: 100%;
}
#gradient
{
position: absolute;
bottom: 0px;
width: 100%;
height: 25%;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%);
}
@font-face {
font-family: 'BankGothic';
src: url('bankgothic.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
h1, h2 {
position: relative;
background: transparent;
z-index: 0;
}
/* add a single stroke */
h1:before, h2:before {
content: attr(title);
position: absolute;
-webkit-text-stroke: 0.1em #000;
left: 0;
z-index: -1;
}
.letni
{
position: absolute;
left: 5%;
right: 5%;
bottom: 10%;
z-index: 5;
color: #fff;
font-family: "Segoe UI";
}
.letni p
{
font-size: 22px;
margin-left: 3px;
margin-top: 0px;
}
.letni h2
{
font-family: BankGothic;
text-transform: uppercase;
font-size: 50px;
margin: 0px;
}
.top
{
color: #fff;
position: absolute;
top: 7%;
left: 5%;
right: 5%;
}
.top h1
{
font-family: BankGothic;
font-size: 60px;
margin: 0px;
}
.top h2
{
font-family: BankGothic;
font-size: 40px;
margin: 0px;
color: #ddd;
}
.loadbar
{
width: 100%;
background-color: rgba(140, 140, 140, .9);
height: 20px;
margin-left: 2px;
margin-right: 3px;
margin-top: 5px;
margin-bottom: 5px;
overflow: hidden;
position: relative;
}
.thingy
{
width: 10%;
background-color: #eee;
height: 20px;
position: absolute;
left: 10%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

View File

@ -0,0 +1,2 @@
client_script 'omg.lua'
server_script 'srv.lua'

View File

@ -0,0 +1,78 @@
Citizen.Trace("OMG FINALLY FIVEM SCRIPTING FROM SERVER-SIDE STUFF WOWOWOWOWOW-zers\n")
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
local playerPed = GetPlayerPed(-1)
if playerPed and playerPed ~= -1 then
--local pos = GetEntityCoords(playerPed)
local is, pos = GetPedLastWeaponImpactCoord(playerPed)
if is then
SetNotificationTextEntry('STRING')
AddTextComponentString(tostring(pos))
DrawNotification(false, false)
end
end
end
end)
Citizen.CreateThread(function()
while true do
Citizen.Wait(50)
local playerPed = GetPlayerPed(-1)
if playerPed and playerPed ~= -1 then
if IsControlPressed(2, 18) then
SetEntityHeading(playerPed, GetEntityHeading(playerPed) + 15.0)
end
end
end
end)
Citizen.CreateThread(function()
while true do
Citizen.Wait(250)
local playerPed = GetPlayerPed(-1)
if playerPed and playerPed ~= -1 then
if IsControlPressed(0, 11) then
RequestModel(0x2B6DC64A)
while not HasModelLoaded(0x2B6DC64A) do
Citizen.Wait(0)
end
local playerCoords = GetEntityCoords(playerPed)
playerCoords = playerCoords + vector3(0, 2, 0)
local car = CreateVehicle(0x2B6DC64A, playerCoords, 0.0, true, false)
SetNotificationTextEntry('STRING')
AddTextComponentString('car: ' .. tostring(car))
DrawNotification(false, false)
TriggerEvent('isogram', 'a', function(b)
Citizen.Trace('in isogram ' .. tostring(b.a) .. "\n")
return b.a + 2
end)
end
end
end
end)
AddEventHandler('isogram', function(i, s)
Citizen.Trace('in isogram_0 ' .. tostring(i) .. "\n")
Citizen.Trace('out of isogram_0 ' .. tostring(s({ a = 50 })) .. "\n")
end)
AddEventHandler('onPlayerJoining', function(netId, name)
TriggerServerEvent('yepThatsMe', netId, name, { a = 'b' })
end)

View File

@ -0,0 +1,5 @@
RegisterServerEvent('yepThatsMe')
AddEventHandler('yepThatsMe', function(id, name, tab)
print('ytm ', id, name, tab.a)
end)

View File

@ -0,0 +1,3 @@
resource_type 'map' { gameTypes = { fivem = true } }
map 'map.lua'

View File

@ -0,0 +1,64 @@
vehicle_generator "airtug" { -54.26639938354492, -1679.548828125, 28.4414, heading = 228.2736053466797 }
spawnpoint 'a_m_y_hipster_01' { x = -802.311, y = 175.056, z = 72.8446 }
spawnpoint 'a_m_y_hipster_02' { x = -9.96562, y = -1438.54, z = 31.1015 }
spawnpoint 'a_m_y_hipster_01' { x = 0.916756, y = 528.485, z = 174.628 }
spawnpoint 'a_m_y_hipster_02' { x = 1975.86, y = 3821.03, z = 33.4501 }
spawnpoint 'a_m_y_hipster_01' { x = -181.615, y = 852.8, z = 232.701 }
spawnpoint 'a_m_y_hipster_02' { x = 657.723, y = 457.342, z = 144.641 }
spawnpoint 'a_m_y_hipster_01' { x = 134.387, y = 1150.31, z = 231.594 }
spawnpoint 'a_m_y_hipster_02' { x = 726.14, y = 1196.91, z = 326.262 }
spawnpoint 'a_m_y_hipster_01' { x = 740.792, y = 1283.62, z = 360.297 }
spawnpoint 'a_m_y_hipster_02' { x = -437.009, y = 1059.59, z = 327.331 }
spawnpoint 'a_m_y_hipster_01' { x = -428.771, y = 1596.8, z = 356.338 }
spawnpoint 'a_m_y_hipster_02' { x = -1348.78, y = 723.87, z = 186.45 }
spawnpoint 'a_m_y_hipster_01' { x = -1543.24, y = 830.069, z = 182.132 }
spawnpoint 'a_m_y_hipster_02' { x = -2150.48, y = 222.019, z = 184.602 }
spawnpoint 'a_m_y_hipster_01' { x = -3032.13, y = 22.2157, z = 10.1184 }
spawnpoint 'a_m_y_hipster_02' { x = 3063.97, y = 5608.88, z = 209.245 }
spawnpoint 'a_m_y_hipster_01' { x = -2614.35, y = 1872.49, z = 167.32 }
spawnpoint 'a_m_y_hipster_02' { x = -1873.94, y = 2088.73, z = 140.994 }
spawnpoint 'a_m_y_hipster_01' { x = -597.177, y = 2092.16, z = 131.413 }
spawnpoint 'a_m_y_hipster_02' { x = 967.126, y = 2226.99, z = 54.0588 }
spawnpoint 'a_m_y_hipster_01' { x = -338.043, y = 2829, z = 56.0871 }
spawnpoint 'a_m_y_hipster_02' { x = 1082.25, y = -696.921, z = 58.0099 }
spawnpoint 'a_m_y_hipster_01' { x = 1658.31, y = -13.9234, z = 169.992 }
spawnpoint 'a_m_y_hipster_02' { x = 2522.98, y = -384.436, z = 92.9928 }
spawnpoint 'a_m_y_hipster_01' { x = 2826.27, y = -656.489, z = 1.87841 }
spawnpoint 'a_m_y_hipster_02' { x = 2851.12, y = 1467.5, z = 24.5554 }
spawnpoint 'a_m_y_hipster_01' { x = 2336.33, y = 2535.39, z = 46.5177 }
spawnpoint 'a_m_y_hipster_02' { x = 2410.46, y = 3077.88, z = 48.1529 }
spawnpoint 'a_m_y_hipster_01' { x = 2451.15, y = 3768.37, z = 41.3477 }
spawnpoint 'a_m_y_hipster_02' { x = 3337.78, y = 5174.8, z = 18.2108 }
spawnpoint 'a_m_y_hipster_01' { x = -1119.33, y = 4978.52, z = 186.26 }
spawnpoint 'a_m_y_hipster_02' { x = 2877.3, y = 5911.57, z = 369.618 }
spawnpoint 'a_m_y_hipster_01' { x = 2942.1, y = 5306.73, z = 101.52 }
spawnpoint 'a_m_y_hipster_02' { x = 2211.29, y = 5577.94, z = 53.872 }
spawnpoint 'a_m_y_hipster_01' { x = 1602.39, y = 6623.02, z = 15.8417 }
spawnpoint 'a_m_y_hipster_02' { x = 66.0113, y = 7203.58, z = 3.16 }
spawnpoint 'a_m_y_hipster_01' { x = -219.201, y = 6562.82, z = 10.9706 }
spawnpoint 'a_m_y_hipster_02' { x = -45.1562, y = 6301.64, z = 31.6114 }
spawnpoint 'a_m_y_hipster_01' { x = -1004.77, y = 4854.32, z = 274.606 }
spawnpoint 'a_m_y_hipster_02' { x = -1580.01, y = 5173.3, z = 19.5813 }
spawnpoint 'a_m_y_hipster_01' { x = -1467.95, y = 5416.2, z = 23.5959 }
spawnpoint 'a_m_y_hipster_02' { x = -2359.31, y = 3243.83, z = 92.9037 }
spawnpoint 'a_m_y_hipster_01' { x = -2612.96, y = 3555.03, z = 4.85649 }
spawnpoint 'a_m_y_hipster_02' { x = -2083.27, y = 2616.94, z = 3.08396 }
spawnpoint 'a_m_y_hipster_01' { x = -524.471, y = 4195, z = 193.731 }
spawnpoint 'a_m_y_hipster_02' { x = -840.713, y = 4183.18, z = 215.29 }
spawnpoint 'a_m_y_hipster_01' { x = -1576.24, y = 2103.87, z = 67.576 }
spawnpoint 'a_m_y_hipster_02' { x = -1634.37, y = 209.816, z = 60.6413 }
spawnpoint 'a_m_y_hipster_01' { x = -1495.07, y = 142.697, z = 55.6527 }
spawnpoint 'a_m_y_hipster_02' { x = -1715.41, y = -197.722, z = 57.698 }
spawnpoint 'a_m_y_hipster_01' { x = -1181.07, y = -505.544, z = 35.5661 }
spawnpoint 'a_m_y_hipster_02' { x = -1712.37, y = -1082.91, z = 13.0801 }
spawnpoint 'a_m_y_hipster_01' { x = -1352.43, y = -1542.75, z = 4.42268 }
spawnpoint 'a_m_y_hipster_02' { x = -1756.89, y = 427.531, z = 127.685 }
spawnpoint 'a_m_y_hipster_01' { x = 3060.2, y = 2113.2, z = 1.6613 }
spawnpoint 'a_m_y_hipster_02' { x = 501.646, y = 5604.53, z = 797.91 }
spawnpoint 'a_m_y_hipster_01' { x = 714.109, y = 4151.15, z = 35.7792 }
spawnpoint 'a_m_y_hipster_02' { x = -103.651, y = -967.93, z = 296.52 }
spawnpoint 'a_m_y_hipster_01' { x = -265.333, y = -2419.35, z = 122.366 }
spawnpoint 'a_m_y_hipster_02' { x = 1788.25, y = 3890.34, z = 34.3849 }
--

View File

@ -0,0 +1,3 @@
resource_type 'map' { gameTypes = { fivem = true } }
map 'map.lua'

View File

@ -0,0 +1,62 @@
spawnpoint 'a_m_y_skater_01' { x = -802.311, y = 175.056, z = 72.8446 }
spawnpoint 'a_m_y_skater_02' { x = -9.96562, y = -1438.54, z = 31.1015 }
spawnpoint 'a_m_y_skater_01' { x = 0.916756, y = 528.485, z = 174.628 }
spawnpoint 'a_m_y_skater_02' { x = 1975.86, y = 3821.03, z = 33.4501 }
spawnpoint 'a_m_y_skater_01' { x = -181.615, y = 852.8, z = 232.701 }
spawnpoint 'a_m_y_skater_02' { x = 657.723, y = 457.342, z = 144.641 }
spawnpoint 'a_m_y_skater_01' { x = 134.387, y = 1150.31, z = 231.594 }
spawnpoint 'a_m_y_skater_02' { x = 726.14, y = 1196.91, z = 326.262 }
spawnpoint 'a_m_y_skater_01' { x = 740.792, y = 1283.62, z = 360.297 }
spawnpoint 'a_m_y_skater_02' { x = -437.009, y = 1059.59, z = 327.331 }
spawnpoint 'a_m_y_skater_01' { x = -428.771, y = 1596.8, z = 356.338 }
spawnpoint 'a_m_y_skater_02' { x = -1348.78, y = 723.87, z = 186.45 }
spawnpoint 'a_m_y_skater_01' { x = -1543.24, y = 830.069, z = 182.132 }
spawnpoint 'a_m_y_skater_02' { x = -2150.48, y = 222.019, z = 184.602 }
spawnpoint 'a_m_y_skater_01' { x = -3032.13, y = 22.2157, z = 10.1184 }
spawnpoint 'a_m_y_skater_02' { x = 3063.97, y = 5608.88, z = 209.245 }
spawnpoint 'a_m_y_skater_01' { x = -2614.35, y = 1872.49, z = 167.32 }
spawnpoint 'a_m_y_skater_02' { x = -1873.94, y = 2088.73, z = 140.994 }
spawnpoint 'a_m_y_skater_01' { x = -597.177, y = 2092.16, z = 131.413 }
spawnpoint 'a_m_y_skater_02' { x = 967.126, y = 2226.99, z = 54.0588 }
spawnpoint 'a_m_y_skater_01' { x = -338.043, y = 2829, z = 56.0871 }
spawnpoint 'a_m_y_skater_02' { x = 1082.25, y = -696.921, z = 58.0099 }
spawnpoint 'a_m_y_skater_01' { x = 1658.31, y = -13.9234, z = 169.992 }
spawnpoint 'a_m_y_skater_02' { x = 2522.98, y = -384.436, z = 92.9928 }
spawnpoint 'a_m_y_skater_01' { x = 2826.27, y = -656.489, z = 1.87841 }
spawnpoint 'a_m_y_skater_02' { x = 2851.12, y = 1467.5, z = 24.5554 }
spawnpoint 'a_m_y_skater_01' { x = 2336.33, y = 2535.39, z = 46.5177 }
spawnpoint 'a_m_y_skater_02' { x = 2410.46, y = 3077.88, z = 48.1529 }
spawnpoint 'a_m_y_skater_01' { x = 2451.15, y = 3768.37, z = 41.3477 }
spawnpoint 'a_m_y_skater_02' { x = 3337.78, y = 5174.8, z = 18.2108 }
spawnpoint 'a_m_y_skater_01' { x = -1119.33, y = 4978.52, z = 186.26 }
spawnpoint 'a_m_y_skater_02' { x = 2877.3, y = 5911.57, z = 369.618 }
spawnpoint 'a_m_y_skater_01' { x = 2942.1, y = 5306.73, z = 101.52 }
spawnpoint 'a_m_y_skater_02' { x = 2211.29, y = 5577.94, z = 53.872 }
spawnpoint 'a_m_y_skater_01' { x = 1602.39, y = 6623.02, z = 15.8417 }
spawnpoint 'a_m_y_skater_02' { x = 66.0113, y = 7203.58, z = 3.16 }
spawnpoint 'a_m_y_skater_01' { x = -219.201, y = 6562.82, z = 10.9706 }
spawnpoint 'a_m_y_skater_02' { x = -45.1562, y = 6301.64, z = 31.6114 }
spawnpoint 'a_m_y_skater_01' { x = -1004.77, y = 4854.32, z = 274.606 }
spawnpoint 'a_m_y_skater_02' { x = -1580.01, y = 5173.3, z = 19.5813 }
spawnpoint 'a_m_y_skater_01' { x = -1467.95, y = 5416.2, z = 23.5959 }
spawnpoint 'a_m_y_skater_02' { x = -2359.31, y = 3243.83, z = 92.9037 }
spawnpoint 'a_m_y_skater_01' { x = -2612.96, y = 3555.03, z = 4.85649 }
spawnpoint 'a_m_y_skater_02' { x = -2083.27, y = 2616.94, z = 3.08396 }
spawnpoint 'a_m_y_skater_01' { x = -524.471, y = 4195, z = 193.731 }
spawnpoint 'a_m_y_skater_02' { x = -840.713, y = 4183.18, z = 215.29 }
spawnpoint 'a_m_y_skater_01' { x = -1576.24, y = 2103.87, z = 67.576 }
spawnpoint 'a_m_y_skater_02' { x = -1634.37, y = 209.816, z = 60.6413 }
spawnpoint 'a_m_y_skater_01' { x = -1495.07, y = 142.697, z = 55.6527 }
spawnpoint 'a_m_y_skater_02' { x = -1715.41, y = -197.722, z = 57.698 }
spawnpoint 'a_m_y_skater_01' { x = -1181.07, y = -505.544, z = 35.5661 }
spawnpoint 'a_m_y_skater_02' { x = -1712.37, y = -1082.91, z = 13.0801 }
spawnpoint 'a_m_y_skater_01' { x = -1352.43, y = -1542.75, z = 4.42268 }
spawnpoint 'a_m_y_skater_02' { x = -1756.89, y = 427.531, z = 127.685 }
spawnpoint 'a_m_y_skater_01' { x = 3060.2, y = 2113.2, z = 1.6613 }
spawnpoint 'a_m_y_skater_02' { x = 501.646, y = 5604.53, z = 797.91 }
spawnpoint 'a_m_y_skater_01' { x = 714.109, y = 4151.15, z = 35.7792 }
spawnpoint 'a_m_y_skater_02' { x = -103.651, y = -967.93, z = 296.52 }
spawnpoint 'a_m_y_skater_01' { x = -265.333, y = -2419.35, z = 122.366 }
spawnpoint 'a_m_y_skater_02' { x = 1788.25, y = 3890.34, z = 34.3849 }
--

View File

@ -0,0 +1,3 @@
resource_type 'gametype' { name = 'Freeroam' }
client_script 'fivem_client.lua'

View File

@ -0,0 +1,9 @@
AddEventHandler('onClientMapStart', function()
Citizen.Trace("ocms fivem\n")
exports.spawnmanager:setAutoSpawn(true)
exports.spawnmanager:forceRespawn()
SetClockTime(24, 0, 0)
PauseClock(true)
Citizen.Trace("ocms fivem end\n")
end)

View File

@ -0,0 +1,85 @@
local function launchGame()
-- TODO: replace with the actual game mode the joined session is running
--StartResource('citizen')
TriggerEvent('gameModeStarted')
--StopResource('initial')
end
local function showError(err)
ForceLoadingScreen(0)
SetMsgForLoadingScreen(err)
echo(err .. "\n")
return "exit"
end
CreateThread(function()
Wait(50)
AllowThisScriptToBePaused(false)
SetNoResprays(false)
ThisScriptIsSafeForNetworkGame()
if IsPlayerPlaying(GetPlayerIndex()) then
SetPlayerControl(GetPlayerIndex(), false)
end
-- setup default callbacks
exports.session:reset()
AddEventHandler('sessionStateChanged', function(state)
if state == 'find' then
SetLoadingText('Finding games...')
elseif state == 'host' then
SetLoadingText('Creating game...')
end
end)
AddEventHandler('sessionJoining', function(cur, max, hostName)
SetLoadingText('Joining game ' .. cur .. ' of ' .. max .. '... (' .. hostName .. ')')
end)
AddEventHandler('sessionJoined', launchGame)
AddEventHandler('sessionHosted', launchGame)
AddEventHandler('sessionHostFailed', function(err)
echo("hosting game failed: " .. err .. "\n")
showError("NICON_MT")
ShutdownAndLaunchSinglePlayerGame()
end)
local sessionList
local curJoinSession = 0
local joinFailed = function()
exports.session:hostSession(16, 32)
end
AddEventHandler('sessionJoinFailed', function()
curJoinSession = curJoinSession + 1
if curJoinSession > #sessionList then
joinFailed()
return
end
exports.session:joinSession(sessionList[curJoinSession])
end)
AddEventHandler('sessionsFound', function(sessions)
if #sessions == 0 then
joinFailed()
return
end
sessionList = sessions
curJoinSession = 1
exports.session:joinSession(sessionList[curJoinSession])
end)
exports.session:findSessions(16)
end)

2
run.bat Normal file
View File

@ -0,0 +1,2 @@
@echo off
start CitizenMP.Server.exe %*

4
run.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/bash
fx_root=`dirname "$(readlink -f "$0")"`
MONO_PATH=$fx_root/mono/ mono $fx_root/CitizenMP.Server.exe $*

1205
system/MessagePack.lua Normal file

File diff suppressed because it is too large Load Diff

709
system/dkjson.lua Normal file
View File

@ -0,0 +1,709 @@
-- Module options:
local always_try_using_lpeg = true
local register_global_module_table = true
local global_module_name = 'json'
--[==[
David Kolf's JSON module for Lua 5.1/5.2
Version 2.5
For the documentation see the corresponding readme.txt or visit
<http://dkolf.de/src/dkjson-lua.fsl/>.
You can contact the author by sending an e-mail to 'david' at the
domain 'dkolf.de'.
Copyright (C) 2010-2013 David Heiko Kolf
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]==]
-- global dependencies:
--local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
-- pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
--local error, require, pcall, select = error, require, pcall, select
local floor, huge = math.floor, math.huge
local strrep, gsub, gsubf, strsub, strbyte, strchar, strfind, strlen, strformat =
string.rep, gsub, gsubf, ssub, string.byte, string.char,
sfind, string.len, string.format
local strmatch = string.match
local concat = table.concat
local json = { version = "dkjson 2.5" }
if register_global_module_table then
_G[global_module_name] = json
end
local _ENV = nil -- blocking globals in Lua 5.2
pcall (function()
-- Enable access to blocked metatables.
-- Don't worry, this module doesn't change anything in them.
local debmeta = require "debug".getmetatable
if debmeta then getmetatable = debmeta end
end)
json.null = setmetatable ({}, {
__tojson = function () return "null" end
})
local function isarray (tbl)
local max, n, arraylen = 0, 0, 0
for k,v in pairs (tbl) do
if k == 'n' and type(v) == 'number' then
arraylen = v
if v > max then
max = v
end
else
if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
return false
end
if k > max then
max = k
end
n = n + 1
end
end
if max > 10 and max > arraylen and max > n * 2 then
return false -- don't create an array with too many holes
end
return true, max
end
local escapecodes = {
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
}
local function escapeutf8 (uchar)
local value = escapecodes[uchar]
if value then
return value
end
local a, b, c, d = strbyte (uchar, 1, 4)
a, b, c, d = a or 0, b or 0, c or 0, d or 0
if a <= 0x7f then
value = a
elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
value = (a - 0xc0) * 0x40 + b - 0x80
elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
else
return ""
end
if value <= 0xffff then
return strformat ("\\u%.4x", value)
elseif value <= 0x10ffff then
-- encode as UTF-16 surrogate pair
value = value - 0x10000
local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
else
return ""
end
end
local function fsub (str, pattern, repl)
-- gsub always builds a new string in a buffer, even when no match
-- exists. First using find should be more efficient when most strings
-- don't contain the pattern.
if strfind (str, pattern) then
if type(repl) == 'function' then
return gsubf(str, pattern, repl)
else
return gsub (str, pattern, repl)
end
else
return str
end
end
local function quotestring (value)
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
if strfind (value, "[\194\216\220\225\226\239]") then
value = fsub (value, "\194[\128-\159\173]", escapeutf8)
value = fsub (value, "\216[\128-\132]", escapeutf8)
value = fsub (value, "\220\143", escapeutf8)
value = fsub (value, "\225\158[\180\181]", escapeutf8)
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
value = fsub (value, "\226\129[\160-\175]", escapeutf8)
value = fsub (value, "\239\187\191", escapeutf8)
value = fsub (value, "\239\191[\176-\191]", escapeutf8)
end
return "\"" .. value .. "\""
end
json.quotestring = quotestring
local function replace(str, o, n)
local i, j = strfind (str, o, 1, true)
if i then
return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
else
return str
end
end
-- locale independent num2str and str2num functions
local decpoint, numfilter
local function updatedecpoint ()
decpoint = strmatch(tostring(0.5), "([^05+])")
-- build a filter that can be used to remove group separators
numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
end
updatedecpoint()
local function num2str (num)
return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
end
local function str2num (str)
local num = tonumber(replace(str, ".", decpoint))
if not num then
updatedecpoint()
num = tonumber(replace(str, ".", decpoint))
end
return num
end
local function addnewline2 (level, buffer, buflen)
buffer[buflen+1] = "\n"
buffer[buflen+2] = strrep (" ", level)
buflen = buflen + 2
return buflen
end
function json.addnewline (state)
if state.indent then
state.bufferlen = addnewline2 (state.level or 0,
state.buffer, state.bufferlen or #(state.buffer))
end
end
local encode2 -- forward declaration
local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
local kt = type (key)
if kt ~= 'string' and kt ~= 'number' then
return nil, "type '" .. kt .. "' is not supported as a key by JSON."
end
if prev then
buflen = buflen + 1
buffer[buflen] = ","
end
if indent then
buflen = addnewline2 (level, buffer, buflen)
end
buffer[buflen+1] = quotestring (key)
buffer[buflen+2] = ":"
return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
end
local function appendcustom(res, buffer, state)
local buflen = state.bufferlen
if type (res) == 'string' then
buflen = buflen + 1
buffer[buflen] = res
end
return buflen
end
local function exception(reason, value, state, buffer, buflen, defaultmessage)
defaultmessage = defaultmessage or reason
local handler = state.exception
if not handler then
return nil, defaultmessage
else
state.bufferlen = buflen
local ret, msg = handler (reason, value, state, defaultmessage)
if not ret then return nil, msg or defaultmessage end
return appendcustom(ret, buffer, state)
end
end
function json.encodeexception(reason, value, state, defaultmessage)
return quotestring("<" .. defaultmessage .. ">")
end
encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
local valtype = type (value)
local valmeta = getmetatable (value)
valmeta = type (valmeta) == 'table' and valmeta -- only tables
local valtojson = valmeta and valmeta.__tojson
if valtojson then
if tables[value] then
return exception('reference cycle', value, state, buffer, buflen)
end
tables[value] = true
state.bufferlen = buflen
local ret, msg = valtojson (value, state)
if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
tables[value] = nil
buflen = appendcustom(ret, buffer, state)
elseif valtype == 'nil' then
buflen = buflen + 1
buffer[buflen] = "null"
elseif valtype == 'number' then
local s
if value ~= value or value >= huge or -value >= huge then
-- This is the behaviour of the original JSON implementation.
s = "null"
else
s = num2str (value)
end
buflen = buflen + 1
buffer[buflen] = s
elseif valtype == 'boolean' then
buflen = buflen + 1
buffer[buflen] = value and "true" or "false"
elseif valtype == 'string' then
buflen = buflen + 1
buffer[buflen] = quotestring (value)
elseif valtype == 'table' then
--[[if tables[value] then
return exception('reference cycle', value, state, buffer, buflen)
end
tables[value] = true]]
level = level + 1
local isa, n = isarray (value)
if n == 0 and valmeta and valmeta.__jsontype == 'object' then
isa = false
end
local msg
if isa then -- JSON array
buflen = buflen + 1
buffer[buflen] = "["
for i = 1, n do
buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
if i < n then
buflen = buflen + 1
buffer[buflen] = ","
end
end
buflen = buflen + 1
buffer[buflen] = "]"
else -- JSON object
local prev = false
buflen = buflen + 1
buffer[buflen] = "{"
local order = valmeta and valmeta.__jsonorder or globalorder
if order then
local used = {}
n = #order
for i = 1, n do
local k = order[i]
local v = value[k]
if v then
used[k] = true
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
prev = true -- add a seperator before the next element
end
end
for k,v in pairs (value) do
if not used[k] then
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
prev = true -- add a seperator before the next element
end
end
else -- unordered
for k,v in pairs (value) do
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
prev = true -- add a seperator before the next element
end
end
if indent then
buflen = addnewline2 (level - 1, buffer, buflen)
end
buflen = buflen + 1
buffer[buflen] = "}"
end
--tables[value] = nil
else
return exception ('unsupported type', value, state, buffer, buflen,
"type '" .. valtype .. "' is not supported by JSON.")
end
return buflen
end
function json.encode (value, state)
state = state or {}
local oldbuffer = state.buffer
local buffer = oldbuffer or {}
state.buffer = buffer
updatedecpoint()
local ret, msg = encode2 (value, state.indent, state.level or 0,
buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
if not ret then
error (msg, 2)
elseif oldbuffer == buffer then
state.bufferlen = ret
return true
else
state.bufferlen = nil
state.buffer = nil
return concat (buffer)
end
end
local function loc (str, where)
local line, pos, linepos = 1, 1, 0
while true do
pos = strfind (str, "\n", pos, true)
if pos and pos < where then
line = line + 1
linepos = pos
pos = pos + 1
else
break
end
end
return "line " .. line .. ", column " .. (where - linepos)
end
local function unterminated (str, what, where)
return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
end
local function scanwhite (str, pos)
while true do
pos = strfind (str, "%S", pos)
if not pos then return nil end
local sub2 = strsub (str, pos, pos + 1)
if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
-- UTF-8 Byte Order Mark
pos = pos + 3
elseif sub2 == "//" then
pos = strfind (str, "[\n\r]", pos + 2)
if not pos then return nil end
elseif sub2 == "/*" then
pos = strfind (str, "*/", pos + 2)
if not pos then return nil end
pos = pos + 2
else
return pos
end
end
end
local escapechars = {
["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
}
local function unichar (value)
if value < 0 then
return nil
elseif value <= 0x007f then
return strchar (value)
elseif value <= 0x07ff then
return strchar (0xc0 + floor(value/0x40),
0x80 + (floor(value) % 0x40))
elseif value <= 0xffff then
return strchar (0xe0 + floor(value/0x1000),
0x80 + (floor(value/0x40) % 0x40),
0x80 + (floor(value) % 0x40))
elseif value <= 0x10ffff then
return strchar (0xf0 + floor(value/0x40000),
0x80 + (floor(value/0x1000) % 0x40),
0x80 + (floor(value/0x40) % 0x40),
0x80 + (floor(value) % 0x40))
else
return nil
end
end
local function scanstring (str, pos)
local lastpos = pos + 1
local buffer, n = {}, 0
while true do
local nextpos = strfind (str, "[\"\\]", lastpos)
if not nextpos then
return unterminated (str, "string", pos)
end
if nextpos > lastpos then
n = n + 1
buffer[n] = strsub (str, lastpos, nextpos - 1)
end
if strsub (str, nextpos, nextpos) == "\"" then
lastpos = nextpos + 1
break
else
local escchar = strsub (str, nextpos + 1, nextpos + 1)
local value
if escchar == "u" then
value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
if value then
local value2
if 0xD800 <= value and value <= 0xDBff then
-- we have the high surrogate of UTF-16. Check if there is a
-- low surrogate escaped nearby to combine them.
if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
else
value2 = nil -- in case it was out of range for a low surrogate
end
end
end
value = value and unichar (value)
if value then
if value2 then
lastpos = nextpos + 12
else
lastpos = nextpos + 6
end
end
end
end
if not value then
value = escapechars[escchar] or escchar
lastpos = nextpos + 2
end
n = n + 1
buffer[n] = value
end
end
if n == 1 then
return buffer[1], lastpos
elseif n > 1 then
return concat (buffer), lastpos
else
return "", lastpos
end
end
local scanvalue -- forward declaration
local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
local len = strlen (str)
local tbl, n = {}, 0
local pos = startpos + 1
if what == 'object' then
setmetatable (tbl, objectmeta)
else
setmetatable (tbl, arraymeta)
end
while true do
pos = scanwhite (str, pos)
if not pos then return unterminated (str, what, startpos) end
local char = strsub (str, pos, pos)
if char == closechar then
return tbl, pos + 1
end
local val1, err
val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end
pos = scanwhite (str, pos)
if not pos then return unterminated (str, what, startpos) end
char = strsub (str, pos, pos)
if char == ":" then
if val1 == nil then
return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
end
pos = scanwhite (str, pos + 1)
if not pos then return unterminated (str, what, startpos) end
local val2
val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end
tbl[val1] = val2
pos = scanwhite (str, pos)
if not pos then return unterminated (str, what, startpos) end
char = strsub (str, pos, pos)
else
n = n + 1
tbl[n] = val1
end
if char == "," then
pos = pos + 1
end
end
end
local level = 0
scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
pos = pos or 1
pos = scanwhite (str, pos)
if not pos then
return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
end
local char = strsub (str, pos, pos)
if char == "{" then
level = level + 1
return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
elseif char == "[" then
return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
elseif char == "\"" then
return scanstring (str, pos)
else
local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
if pstart then
local number = str2num (strsub (str, pstart, pend))
if type(number) == 'number' then -- FIXME: change to 'if number then' when neolua bug is fixed
return number, pend + 1
end
end
pstart, pend = strfind (str, "^%a%w*", pos)
if pstart then
local name = strsub (str, pstart, pend)
if name == "true" then
return true, pend + 1
elseif name == "false" then
return false, pend + 1
elseif name == "null" then
return nullval, pend + 1
end
end
return nil, pos, "no valid JSON value at " .. loc (str, pos)
end
end
function json.decode (str, pos, nullval, ...)
local objectmeta, arraymeta = {__jsontype = 'object'}, {__jsontype = 'array'}
return scanvalue (str, pos, nullval, objectmeta, arraymeta)
end
function json.use_lpeg ()
local g = require ("lpeg")
if g.version() == "0.11" then
error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
end
local pegmatch = g.match
local P, S, R = g.P, g.S, g.R
local function ErrorCall (str, pos, msg, state)
if not state.msg then
state.msg = msg .. " at " .. loc (str, pos)
state.pos = pos
end
return false
end
local function Err (msg)
return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
end
local SingleLineComment = P"//" * (1 - S"\n\r")^0
local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
local PlainChar = 1 - S"\"\\\n\r"
local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
local HexDigit = R("09", "af", "AF")
local function UTF16Surrogate (match, pos, high, low)
high, low = tonumber (high, 16), tonumber (low, 16)
if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
else
return false
end
end
local function UTF16BMP (hex)
return unichar (tonumber (hex, 16))
end
local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
local Char = UnicodeEscape + EscapeSequence + PlainChar
local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
local Fractal = P"." * R"09"^0
local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
local SimpleValue = Number + String + Constant
local ArrayContent, ObjectContent
-- The functions parsearray and parseobject parse only a single value/pair
-- at a time and store them directly to avoid hitting the LPeg limits.
local function parsearray (str, pos, nullval, state)
local obj, cont
local npos
local t, nt = {}, 0
repeat
obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
if not npos then break end
pos = npos
nt = nt + 1
t[nt] = obj
until cont == 'last'
return pos, setmetatable (t, state.arraymeta)
end
local function parseobject (str, pos, nullval, state)
local obj, key, cont
local npos
local t = {}
repeat
key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
if not npos then break end
pos = npos
t[key] = obj
until cont == 'last'
return pos, setmetatable (t, state.objectmeta)
end
local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
local Value = Space * (Array + Object + SimpleValue)
local ExpectedValue = Value + Space * Err "value expected"
ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
local DecodeValue = ExpectedValue * g.Cp ()
function json.decode (str, pos, nullval, ...)
local state = {}
state.objectmeta, state.arraymeta = optionalmetatables(...)
local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
if state.msg then
return nil, state.pos, state.msg
else
return obj, retpos
end
end
-- use this function only once:
json.use_lpeg = function () return json end
json.using_lpeg = true
return json -- so you can get the module using json = require "dkjson".use_lpeg()
end
return json

289
system/resource_init.lua Normal file
View File

@ -0,0 +1,289 @@
-- local resource init stuff (similar to client resource_init)
RegisterInitHandler(function(initScript, isPreParse)
local env = {
_VERSION = _VERSION,
assert = assert,
error = error,
getmetatable = getmetatable,
ipairs = ipairs,
next = next,
pairs = pairs,
pcall = pcall,
print = print,
rawequal = rawequal,
rawget = rawget,
rawlen = rawlen,
rawset = rawset,
select = select,
setmetatable = setmetatable,
tonumber = tonumber,
tostring = tostring,
type = type,
xpcall = xpcall,
bit32 = {
arshift = bit32.arshift,
band = bit32.band,
bnot = bit32.bnot,
bor = bit32.bor,
btest = bit32.btest,
bxor = bit32.bxor,
extract = bit32.extract,
lrotate = bit32.lrotate,
lshift = bit32.lshift,
replace = bit32.replace,
rrotate = bit32.rrotate,
rshift = bit32.rshift
},
coroutine = {
create = coroutine.create,
resume = coroutine.resume,
running = coroutine.running,
status = coroutine.status,
wrap = coroutine.wrap,
yield = coroutine.yield
},
math = {
abs = math.abs,
acos = math.acos,
asin = math.asin,
atan = math.atan,
atan2 = math.atan2,
ceil = math.ceil,
cos = math.cos,
cosh = math.cosh,
deg = math.deg,
exp = math.exp,
floor = math.floor,
fmod = math.fmod,
frexp = math.frexp,
huge = math.huge,
ldexp = math.ldexp,
log = math.log,
max = math.max,
min = math.min,
modf = math.modf,
pi = math.pi,
pow = math.pow,
rad = math.rad,
random = math.random,
randomseed = math.randomseed,
sin = math.sin,
sinh = math.sinh,
sqrt = math.sqrt,
tan = math.tan,
tanh = math.tanh
},
string = {
byte = string.byte,
char = string.char,
dump = string.dump,
find = string.find,
format = string.format,
gmatch = string.gmatch,
gsub = string.gsub,
len = string.len,
lower = string.lower,
match = string.match,
rep = string.rep,
reverse = string.reverse,
sub = string.sub,
upper = string.upper
},
table = {
concat = table.concat,
insert = table.insert,
pack = table.pack,
remove = table.remove,
sort = table.sort,
unpack = table.unpack
}
}
TriggerEvent('getResourceInitFuncs', isPreParse, function(key, cb)
env[key] = cb
end)
local pr = print
if not isPreParse then
env.server_scripts = function(n)
if type(n) == 'string' then
n = { n }
end
for _, d in ipairs(n) do
AddServerScript(d)
end
end
env.server_script = env.server_scripts
else
-- and add our native items
env.solution = function(n)
SetResourceInfo('clr_solution', n)
end
env.description = function(n)
SetResourceInfo('description', n)
end
env.version = function(n)
SetResourceInfo('version', n)
end
env.client_scripts = function(n)
if type(n) == 'string' then
n = { n }
end
for _, d in ipairs(n) do
AddClientScript(d)
end
end
env.client_script = env.client_scripts
env.files = function(n)
if type(n) == 'string' then
n = { n }
end
for _, d in ipairs(n) do
AddAuxFile(d)
end
end
env.file = env.files
env.dependencies = function(n)
if type(n) == 'string' then
n = { n }
end
for _, d in ipairs(n) do
AddResourceDependency(d)
end
end
env.dependency = env.dependencies
end
local rawget_ = rawget
local print_ = print
local mt = {
__index = function(t, k) : object
if env[k] ~= nil then
return env[k]
end
if rawget_(t, k) ~= nil then
return rawget_(t, k)
end
-- as we're not going to return nothing here (to allow unknown directives to be ignored)
local f = function()
return f
end
return function() return f end
end
}
for k, v in pairs(env) do
if type(v) == 'function' then
env[k] = function(...)
_G.__metatable = nil
local rv = v(...)
_G.__metatable = mt
return rv
end
end
end
_G.__metatable = mt
--setmetatable(env, mt)
--setfenv(initScript, env)
initScript()
--env = nil
--setfenv(initScript, _G)
_G.__metatable = nil
-- print('rc', findallpaths(rt))
end)
-- nothing, yet
-- TODO: cleanup RPC environment stuff on coroutine end/error
local function RunRPCFunction(f, env)
local co = coroutine.create(f)
env.__co = client
local success, err = coroutine.resume(co)
if success then
env.SendEvents()
else
print(err)
end
end
local rpcIdx = 1
local rpcEnvironments = {}
function CreateRPCContext(cl, f)
local idx = rpcIdx
rpcIdx = rpcIdx + 1
local key = cl .. '_' .. idx
local env = {
getIdx = function()
return idx
end,
getSource = function()
return cl
end
}
local lastEnv = _ENV
setmetatable(env, {__index = _G})
local _ENV = env
rpcEnvironments[key] = env
setfenv(f, env)
local fRun = f()
local virtenv_init = loadfile('system/virtenv_init.lua', 't', env)
virtenv_init()
_ENV = lastEnv
RunRPCFunction(fRun, env)
end
RegisterServerEvent('svRpc:results')
AddEventHandler('svRpc:results', function(results)
if not results.idx then
return
end
local key = source .. '_' .. results.idx
if not rpcEnvironments[key] then
return
end
rpcEnvironments[key].HandleResults(results)
end)

99
system/virtenv_init.lua Normal file
View File

@ -0,0 +1,99 @@
local execQueue = {}
local execQueueArgNum = 1
local execResults = {}
local curRoutine
_i = { _a = '_i' }
_f = { _a = '_f' }
function GetResult(argNum)
if not execResults[argNum] then
if #execQueue > 0 then
execQueue.idx = getIdx()
curRoutine = coroutine.running()
coroutine.yield()
execQueue = {}
end
end
local r = execResults[argNum]
execResults[argNum] = nil
return r
end
function HandleResults(results)
for k, v in pairs(results) do
execResults[k] = v
end
if coroutine.status(curRoutine) == 'dead' then
return
end
local success, err = coroutine.resume(curRoutine)
if success then
SendEvents({ getSource = getSource })
else
print(err)
end
end
function SendEvents(env)
TriggerClientEvent('svRpc:run', getSource(), 10, execQueue)
end
function CallNative(hash, ...)
local arguments = {}
local returns = {}
local arg = {...}
for i, v in ipairs(arg) do
local a = v
if type(v) == 'table' then
if v._a then
if v._a == '_i' or v._a == '_f' then
a._i = execQueueArgNum
execQueueArgNum = execQueueArgNum + 1
local fakeRetVal = {
_a = '_z',
_i = a._i
}
-- this will only work in Lua 5.2+; as metamethod yielding got added there
setmetatable(fakeRetVal, {
__call = function()
if not fakeRetVal._value then
fakeRetVal._value = GetResult(fakeRetVal._i)
end
return fakeRetVal._value
end
})
table.insert(returns, fakeRetVal)
end
end
end
table.insert(arguments, a)
end
table.insert(execQueue, {
h = hash,
a = arguments
})
return table.unpack(returns)
end
function PrintStringWithLiteralString(...) return CallNative(0x3F89280B, ...) end
function PrintStringWithLiteralStringNow(...) return CallNative(0xCA539D6, ...) end
function GetCharCoordinates(...) return CallNative(0x2B5C06E6, ...) end
function GetPlayerChar(...) return CallNative(0x511454A9, ...) end