-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathportal_main.lua
253 lines (214 loc) · 8.34 KB
/
portal_main.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
-- Global variables
PLUGIN = {} -- Reference to own plugin object
-- LOGIC
PORTAL_ACTIVATION_TIME = 2
PLAYER_STATES = {
["NOT_IN_PORTAL"] = "NOT_IN_PORTAL",
["WAITING"] = "WAITING",
["TELEPORTING"] = "TELEPORTING",
["PORTAL_NOT_SETUP"] = "PORTAL_NOT_SETUP",
["IN_DISABLED_PORTAL"] = "IN_DISABLED_PORTAL",
["SELECTING_DEST"] = "SELECTING_DEST",
}
DATA = {}
DATA.players = {}
DATA.portals = {}
DATA.all_portals_disabled = false
PORTALS_INI_NAME = "portals.ini"
PLUGIN_PATH = ''
DATA.portalIniFile = cIniFile()
CSS_STYLES = nil
WORLDS = {}
function Initialize(Plugin)
PLUGIN = Plugin
dofile(cPluginManager:GetPluginsPath() .. "/InfoReg.lua")
Plugin:SetName(g_PluginInfo.Name)
Plugin:SetVersion(3)
PluginManager = cRoot:Get():GetPluginManager()
cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_JOINED, onPlayerJoin)
cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_DESTROYED, onPlayerDestroyed)
cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_LEFT_CLICK, OnPlayerBreakingBlock)
cPluginManager:AddHook(cPluginManager.HOOK_ENTITY_CHANGED_WORLD, OnEntityChangedWorld)
Plugin:AddWebTab("Portals", HandleRequest_Portals)
cRoot:Get():ForEachWorld(function(world) WORLDS[#WORLDS + 1] = world:GetName() end)
RegisterPluginInfoCommands();
PLUGIN_PATH = cPluginManager:GetPluginsPath() .. "/" .. Plugin:GetFolderName() .. "/"
CSS_STYLES = cFile:ReadWholeFile(PLUGIN_PATH .. "portal-styles.css")
-- load ini files into memory or create them.
initINI(PORTALS_INI_NAME, DATA.portalIniFile)
DATA.portals = portalIniToTable(DATA.portalIniFile)
LOG("Initialized " .. PLUGIN:GetName() .. " v" .. g_PluginInfo.Version)
return true
end
function initINI(fileName, iniObject)
if cFile:IsFile(PLUGIN_PATH .. fileName) then
iniObject:ReadFile(PLUGIN_PATH .. fileName)
LOG(PLUGIN:GetName() .. ": loaded " .. fileName)
else
local success, _ = pcall(iniObject.WriteFile, iniObject, PLUGIN_PATH ..fileName)
if success then
LOG("PORTALS PLUGIN " .. fileName .. " created.")
end
end
end
function OnDisable()
portalDataToIni()
DATA.portalIniFile:WriteFile(PLUGIN_PATH .. PORTALS_INI_NAME)
LOG(PLUGIN:GetName() .. " v" .. g_PluginInfo.Version .. " is shutting down...")
end
function teleportPlayer(Player)
local playerData = DATA.players[Player:GetName()]
local portalData = DATA.portals[playerData.targetPortalName]
if (Player:GetWorld():GetName() ~= portalData["world"]) then
playerData.HasTeleportedToWorld = true
Player:MoveToWorld(portalData["world"])
else
Player:TeleportToCoords(portalData["destination_x"], portalData["destination_y"], portalData["destination_z"])
playerData.targetPortalName = ""
Player:SendMessage(cChatColor.Yellow .. "You have been teleported!")
end
end
function OnPlayerMoving(Player)
local playerName = Player:GetName()
local playerData = DATA.players[playerName]
local portalName = playerInAPortal(Player) -- only returns result when player is in portal area
if (portalName) then
local portalData = DATA.portals[portalName]
local targetPortals = portalData.target
-- check if we already set state to PORTAL_NOT_SETUP or IN_DISABLED_PORTAL
if (playerData.state == PLAYER_STATES.PORTAL_NOT_SETUP or
playerData.state == PLAYER_STATES.IN_DISABLED_PORTAL or
playerData.state == PLAYER_STATES.TELEPORTING or
DATA.all_portals_disabled or
playerData.state == PLAYER_STATES.SELECTING_DEST) then
return false
end
if portalData.disabled == true then
Player:SendMessage(cChatColor.Red .. "portal: " .. portalName .. " is disabled")
playerData.state = PLAYER_STATES.IN_DISABLED_PORTAL
return false
end
-- check if the portal is not set up
if #targetPortals == 0 then
Player:SendMessage(cChatColor.Red .. "Portal " .. portalName .. " doesn't lead anywhere!")
playerData.state = PLAYER_STATES.PORTAL_NOT_SETUP
return false
end
if #targetPortals == 1 and targetPortalHasNoDest(DATA.portals[targetPortals[1]]) then
Player:SendMessage(cChatColor.Red .. "Portal " .. targetPortals[1] .. " does not have a destination point set")
playerData.state = PLAYER_STATES.PORTAL_NOT_SETUP
return false
end
if #targetPortals > 1 then
Player:SendMessage(cChatColor.LightBlue .. "portal " .. portalName)
Player:SendMessage(cChatColor.LightBlue .. "Select a destination from: " .. arrayTableToString(targetPortals))
Player:SendMessage(cChatColor.LightBlue .. "use: '/pteleport <destination>'")
playerData.state = PLAYER_STATES.SELECTING_DEST
return false
end
-- check if player just entered
if (playerData.state == PLAYER_STATES.NOT_IN_PORTAL) then
Player:SendMessage(cChatColor.LightBlue .. "portal: " .. portalName)
Player:SendMessage(cChatColor.LightBlue .. "Stand still for a few seconds for teleportation")
playerData.portal_timer = GetTime() + PORTAL_ACTIVATION_TIME
playerData.state = PLAYER_STATES.WAITING
playerData.targetPortalName = targetPortals[1]
end
if playerData.state == PLAYER_STATES.WAITING then
if (GetTime() > playerData.portal_timer) then
playerData.state = PLAYER_STATES.TELEPORTING
teleportPlayer(Player, playerData)
return true
end
end
else
if playerData.state == PLAYER_STATES.WAITING then
Player:SendMessage(cChatColor.Red .. "You have left teleportation zone")
end
playerData.state = PLAYER_STATES.NOT_IN_PORTAL
playerData.targetPortalName = ""
end
return false
end
function targetPortalHasNoDest(targetPortal)
if targetPortal ~= nil and (targetPortal.destination_x == 0 and targetPortal.destination_x == 0 and targetPortal.destination_x == 0) then
return true
end
return false
end
function OnEntityChangedWorld(Entity, World)
-- this will teleport the player to the desired location after changing worlds
if Entity:IsPlayer() then
local playerName = Entity:GetName()
local playerData = DATA.players[playerName]
if playerData.HasTeleportedToWorld then
local portalName = playerData.targetPortalName
local targetPortal = DATA.portals[portalName]
Entity:TeleportToCoords(targetPortal.destination_x,
targetPortal.destination_y,
targetPortal.destination_z)
Entity:SendMessage(cChatColor.Yellow .. "You have been teleported!")
playerData.targetPortalName = ""
playerData.HasTeleportedToWorld = false
end
end
return false
end
function OnPlayerBreakingBlock(Player, IN_x, IN_y, IN_z, BlockFace, Status, OldBlock, OldMeta)
local playerName = Player:GetName()
local playerData = DATA.players[playerName]
if (Player:HasPermission("portal.create") == true and playerData["HasToolEnabled"] == true) then
if playerData.isSelectingPoint2 then
if ItemToString(Player:GetEquippedItem()) == "woodsword" then
if (playerData.point1.x == IN_x and playerData.point1.y == IN_y and playerData.point1.z == IN_z) then
-- on slow connections the server can get two of these events when the player clicks which means point1/point2
-- get selected right after one another and effectively makes it impossible to select point2
return true
end
playerData.point2.x = IN_x
playerData.point2.y = IN_y
playerData.point2.z = IN_z
Player:SendMessage(portalPointSelectMessage("Point 2", IN_x, IN_y, IN_z))
playerData.isSelectingPoint2 = false
return true
end
else
if (ItemToString(Player:GetEquippedItem()) == "woodsword") then
if (playerData.point2.x == IN_x and playerData.point2.y == IN_y and playerData.point2.z == IN_z) then
-- see note above. this is used for the second playerbreaking event when selecting the point2
return true
end
playerData.point1.x = IN_x
playerData.point1.y = IN_y
playerData.point1.z = IN_z
Player:SendMessage(portalPointSelectMessage("Point 1", IN_x, IN_y, IN_z))
Player:SendMessage(cChatColor.LightBlue .. "Now select point 2.")
playerData.isSelectingPoint2 = true
return true
end
end
end
return false
end
function onPlayerJoin(Player)
local playerName = Player:GetName()
if DATA.players[playerName] == nil then
DATA.players[playerName] = {
portal_timer = 0,
targetPortalName = "",
HasToolEnabled = false,
HasTeleportedToWorld = false,
isSelectingPoint2 = false,
point2 = Vector3i(),
point1 = Vector3i(),
state = PLAYER_STATES.NOT_IN_PORTAL,
}
end
end
function onPlayerDestroyed(Player)
local playerName = Player:GetName()
if DATA.players[playerName] then
DATA.players[playerName] = nil
end
end