| 
					| Nanotech_ua | Дата: Четверг, 08.12.2011, 15:19 | Сообщение # 1 |  |  Майор Группа: Администраторы Сообщений: 95 Статус:   | В этом уроке, мы создадим торнадо, прям у себя на сервере!! 
 Для начала, давайте создадим новую папку с названием "265_tornado".
 
 Далее что нам надо сделать:
 
 1) Создать файл "meta.xml", в него вставить следующий код:
 
 
 Code <meta> <info author="norby89" version="1.0.1" type="script" name="Tornado"/>
 <config src="help.xml" type="client"/>
 <script src="tornado_s.lua" />
 <script src="gui.lua" type="client" />
 <script src="tornado.lua" type="client" />
 </meta>
 2) Создать "help.xml", и в него код:
 
 
 Code <help popup="yes"> This resource will spawn all players at the farm where the tornado is at coordinates 0,0,0. The tornado control menu can be brought back up with the "M" key. Note that this is a clientside script.
 
 NOTE: The tornado is NOT synced. When tornado settings are changed on the GUI they will only affect you. When someone joins the server the tornado will recreate. It seems difficult to fix this due to the way it was structured.
 
 Currently it has no purpose. It is just for demonstration. Concept and original scripting by norby89. The final version with the GUI was lost and rebuilt by Ransom.
 </help>
 3) Создать "gui.lua", и в него код:
 
 
 Code local resourceRoot = getResourceRootElement ( getThisResource() ) local root = getRootElement()
 local scrollFields = { "height", "width", "thickness", "fog", "count" }
 local elementData = {}
 local guiElements = {}
 
 function setLocalElementData ( element, field, value )
 if ( not elementData[element] ) then
 elementData[element] = {}
 end
 elementData[element][field] = value
 end
 
 function getLocalElementData ( element, field )
 return elementData[element][field]
 end
 
 function getRange ( field )
 if field == "height" then
 return 1, 30
 elseif field == "width" then
 return 1, 20
 elseif field == "thickness" then
 return 0.1, 2
 elseif field == "fog" then
 return 0, 1
 elseif field == "count" then
 return 1, 1000
 end
 end
 
 function getOption ( field )
 if field == "height" then
 return 20
 elseif field == "width" then
 return 10
 elseif field == "thickness" then
 return 0.1
 elseif field == "fog" then
 return 0.05
 elseif field == "count" then
 return 100
 end
 end
 
 --Whole naming system is interlinked so I'm just injecting hax here with the below table and function
 labelName = { "Height", "Cone Shape", "Diameter", "Fog Object %", "Total Objects" }
 
 function crossReference(field)
 for k,v in pairs(scrollFields) do
 if field == scrollFields[k] then
 return k
 end
 end
 end
 -----------------------------------------------------------------------------------------------------
 
 function createScroll ( x, y, width, height, maxLength, space, window, field )
 local begin, finish = getRange ( field )
 local default = getOption ( field )
 local scrollBar = guiCreateScrollBar ( x, y, width, height, true, true, window )
 
 guiSetProperty ( scrollBar, "StepSize", ".01" )
 local scrollBox = guiCreateEdit ( 0.8, y, 0.16, height, tostring ( default ) , true, window )
 local percentage = getNewPercentage ( field, default )
 guiScrollBarSetScrollPosition ( scrollBar, percentage )
 guiEditSetMaxLength ( scrollBox, maxLength )
 addEventHandler ( "onClientGUIScroll", scrollBar, checkBar, false )
 addEventHandler ( "onClientGUIChanged", scrollBox, checkBox, false )
 local name = guiCreateLabel ( x + 0.05, y - ( space / 2 ), 0.3, height, labelName[crossReference(field)], true, window )
 local label_01 = guiCreateLabel ( x - 0.1, y, 0.09, height, tostring ( begin ), true, window )
 local label_02 = guiCreateLabel ( x + width, y, 0.09, height, tostring ( finish ), true, window )
 guiLabelSetVerticalAlign ( name, "center" )
 guiLabelSetVerticalAlign ( label_01, "center" )
 guiLabelSetVerticalAlign ( label_02, "center" )
 guiLabelSetHorizontalAlign ( name, "left" )
 guiLabelSetHorizontalAlign ( label_01, "right" )
 guiLabelSetHorizontalAlign ( label_02, "right" )
 setLocalElementData ( scrollBar, "field", field )
 setLocalElementData ( scrollBar, "box", scrollBox )
 setLocalElementData ( scrollBar, "name", label_02 )
 setLocalElementData ( scrollBar, "label_01", label_01 )
 setLocalElementData ( scrollBar, "label_02", label_02 )
 return scrollBar
 end
 
 function createWindow()
 local window = guiCreateWindow ( 0.62, 0.25, 0.35, 0.55, "Tornado Options", true )
 showCursor ( true )
 toggleAllControls ( false, false, true )
 guiWindowSetMovable ( window, true )
 guiWindowSetSizable ( window, false )
 bindKey ( "m", "down", toggleWindow )
 guiElements.window = window
 guiElements.isWindowActive = true
 
 -- local editBox = guiCreateEdit ( 0.3, 0.085, 0.4, 0.08, "", true, window )
 -- guiCreateLabel ( 0.07, 0.1, 0.3, 0.2, "Name: ", true, window )
 
 guiEditSetMaxLength ( editBox, 24 )
 guiElements.editBox = editBox
 
 local closeButton = guiCreateButton ( 0.89, 0.085, 0.08, 0.08, "x", true, window )
 addEventHandler ( "onClientGUIClick", closeButton, hideWindow, false )
 guiElements.closeButton = closeButton
 
 local scrollTable = {}
 local scrolls = 5
 local space = 0.8 / ( scrolls + 1 )
 for i=1, scrolls do
 local y = 0.1 + i * space
 local scroll = createScroll ( 0.1, y, 0.55, 0.06, 6, space, window, scrollFields[i] )
 table.insert ( scrollTable, scroll )
 end
 guiElements.scrollTable = scrollTable
 end
 
 function getNewPosition ( field, percentage )
 local begin, finish = getRange ( field )
 local newPosition = begin + ( finish - begin ) * percentage / 100
 return ( field == "count" ) and math.floor ( newPosition ) or newPosition
 end
 
 function getNewPercentage ( field, position )
 local begin, finish = getRange ( field )
 local newPercentage = ( position - begin ) * 100 / ( finish - begin )
 return newPercentage
 end
 
 function getScrollBar ( scrollBox )
 local scrollBar = nil
 for i, v in ipairs ( guiElements.scrollTable ) do
 local box = getLocalElementData ( v, "box" )
 if ( scrollBox == box ) then
 scrollBar = v
 break
 end
 end
 return scrollBar
 end
 
 -- string.format( "%.4f", 0.023232323 ) -- 4 places
 function roundToString ( num, places )
 num = tostring ( num )
 if num:match ( '%.' ) then
 num = num:gsub ( '(%.' .. ( '%d' ):rep ( places ) .. ')%d+', '%1' )
 end
 return num
 end
 
 function checkBar ( scrollBar )
 local field = getLocalElementData ( scrollBar, "field" )
 if field == "fog" or field == "count" then
 if ( not guiElements.isInUse ) then
 local scrollBox = getLocalElementData ( scrollBar, "box" )
 local field = getLocalElementData ( scrollBar, "field" )
 local percentage = guiScrollBarGetScrollPosition ( scrollBar )
 local position = getNewPosition ( field, percentage )
 
 guiElements.isInUse = true
 guiSetText ( scrollBox, roundToString ( position, 2 ) )
 setOption ( field, position )
 guiElements.isInUse = false
 end
 
 if not regenerateDelay then
 destroyTornado()
 if pieces then
 if pieces.count then
 for i=1, pieces.count do
 if pieces.createPieceDelay then
 killTimer ( pieces.createPieceDelay )
 outputChatBox ( "got it." )
 end
 end
 end
 end
 regenerateDelay = setTimer ( function ()
 onStart()
 regenerateDelay = nil
 -- outputChatBox ( "regenerateDelay ENDED" ) --DEBUG
 end, 500, 1 )
 end
 else
 if ( not guiElements.isInUse ) then
 local scrollBox = getLocalElementData ( scrollBar, "box" )
 local field = getLocalElementData ( scrollBar, "field" )
 local percentage = guiScrollBarGetScrollPosition ( scrollBar )
 local position = getNewPosition ( field, percentage )
 
 guiElements.isInUse = true
 guiSetText ( scrollBox, roundToString ( position, 2 ) )
 setOption ( field, position )
 guiElements.isInUse = false
 end
 end
 end
 
 function checkBox ( scrollBox )
 
 if ( not guiElements.isInUse ) then
 local scrollBar = getScrollBar ( scrollBox )
 local field = getLocalElementData ( scrollBar, "field" )
 local percentage = guiScrollBarGetScrollPosition ( scrollBar )
 local position = tonumber ( guiGetText ( scrollBox ) )
 
 guiElements.isInUse = true
 if ( position ) then
 local begin, finish = getRange ( field )
 if ( position >= begin ) and ( position <= finish ) then
 percentage = getNewPercentage ( field, position )
 guiScrollBarSetScrollPosition ( scrollBar, percentage )
 setOption ( field, position )
 else
 position = getNewPosition ( field, percentage )
 guiSetText ( scrollBox, roundToString ( position, 2 ) )
 end
 else
 position = getNewPosition ( field, percentage )
 guiSetText ( scrollBox, roundToString ( position, 2 ) )
 end
 guiElements.isInUse = false
 end
 end
 
 function toggleWindow()
 local active = guiElements.isWindowActive
 if ( active ) then
 hideWindow ( "left" )
 else
 showWindow()
 end
 end
 
 function hideWindow ( button )
 if ( button == "left" ) then
 local window = guiElements.window
 showCursor ( false )
 guiSetVisible ( window, false )
 toggleAllControls ( true )
 guiElements.isWindowActive = false
 end
 end
 
 function showWindow()
 local window = guiElements.window
 showCursor ( true )
 guiSetVisible ( window, true )
 toggleAllControls ( false, false, true )
 guiElements.isWindowActive = true
 end
 
 addEvent ( "onClientWindowReady" )
 addEventHandler ( "onClientWindowReady", root, createWindow )
 
 createWindow()
 4) Создать "tornado.lua", и в него код:
 
 
 Code -- tits = 33 % 2232 -- outputChatBox ( tits )
 
 local root = getRootElement()
 local ids = { 2780, 701, 702 }    -- fog machine, tumbleweed 1/2
 local pieces = { height = 20,  -- shouldn't be 0
 width = 10,   -- top radius
 thickness = 0.1,    -- 0 < * ( 1 being the width )
 fog = .75,   -- between 0 and 1
 count = 100 }  -- including fogmachines
 -- local previous = { fog = pieces.fog,
 -- count = pieces.count }
 
 function setOption ( field, value )
 pieces[field] = value
 end
 
 function getOption ( field )
 return pieces[field]
 end
 
 function randomObject ( spacing, majorityIsFogMachines )
 if majorityIsFogMachines == false then
 if spaceCount == spacing then
 spaceCount = 0
 -- fogCount = fogCount + 1 --debug
 -- outputChatBox ( "fogCount = "..fogCount ) --debug
 return ids[1]
 else
 spaceCount = spaceCount + 1
 -- tumbleCount = tumbleCount + 1 --debug
 -- outputChatBox ( "tumbleCount = "..tumbleCount ) --debug
 return ids[math.random ( 2, #ids )]
 end
 elseif majorityIsFogMachines == true then --When over fifty, tumble weed becomes what is spaced, not fog machines
 if spaceCount == spacing then
 spaceCount = 0
 -- tumbleCount = tumbleCount + 1 --debug
 -- outputChatBox ( "tumbleCountB = "..tumbleCount ) --debug
 return ids[math.random ( 2, #ids )]
 else
 spaceCount = spaceCount + 1
 -- fogCount = fogCount + 1 --debug
 -- outputChatBox ( "fogCountB = "..fogCount ) --debug
 return ids[1]
 end
 end
 end
 
 function getRandomPositionOffsets ( x, y, z )
 local a, b = -1, 1
 x, y, z = x + randFloat ( a, b ), y + randFloat ( a, b ), z + randFloat ( a, b )
 return x, y, z
 end
 
 function getRandomRotationOffsets()
 local rx, ry, rz = math.random ( 0, 10 ), math.random ( 0 , 10 ), math.random ( 0 , 5 )
 return rx, ry, rz
 end
 
 function getRandomAngleOffsets()
 local angle1, angle2 = randFloat ( 0.005, 0.1 ), randFloat ( 0.01, 0.03 )
 return angle1, angle2
 end
 
 function randFloat ( a, b )
 return a + math.random() * ( b - a )
 end
 
 function updateElementsPosition()
 local count = #pieces
 if ( count > 0 ) then
 for i=1, count do
 local piece = pieces[i]
 local object = piece.object
 
 local oldPosX, oldPosY, oldPosZ = getElementPosition ( object )
 local oldRotX, oldRotY, oldRotZ = getElementRotation ( object )
 local posXOffset, posYOffset, posZOffset = piece.posXOffset, piece.posYOffset, piece.posZOffset
 local tx, ty, tz = getElementPosition ( pieces.dummyTornado )
 local height, width, thickness = pieces.height, pieces.width, pieces.thickness
 
 local newRotX, newRotY, newRotZ = oldRotX + piece.rotXOffset, oldRotY + piece.rotYOffset, oldRotZ + piece.rotZOffset
 local newAngle1, newAngle2 = piece.angle1 + piece.angle1Offset, piece.angle2 + piece.angle2Offset
 
 local newWidth = width * ( 1 + thickness - math.cos ( math.asin ( ( oldPosZ - posZOffset - tz ) / ( height * 1.05 ) ) ) )
 local newPosX = tx + posXOffset + newWidth * ( math.cos ( newAngle1 ) )
 local newPosY = ty + posYOffset + newWidth * ( math.sin ( newAngle1 ) )
 local newPosZ = tz + posZOffset + ( height / 2 ) * ( 1 + math.sin ( newAngle2 ) )
 
 piece.angle1 = ( newAngle1 > 2 * math.pi ) and ( newAngle1 - 2 * math.pi ) or newAngle1
 piece.angle2 = ( newAngle2 > 2 * math.pi ) and ( newAngle2 - 2 * math.pi ) or newAngle2
 
 setElementPosition ( object, newPosX, newPosY, newPosZ )
 setElementRotation ( object, newRotX, newRotY, newRotZ )
 end
 end
 end
 
 function createTornadoPiece ( i, spacing, majorityIsFogMachines )
 if ( i ) then
 local tx, ty, tz = getElementPosition ( pieces.dummyTornado )
 local piece = {}
 local model = randomObject ( spacing, majorityIsFogMachines )
 piece.object = createObject ( model, tx, ty, tz, rx, ry, rz )
 piece.posXOffset, piece.posYOffset, piece.posZOffset = getRandomPositionOffsets ( tx, ty, tz )
 piece.rotXOffset, piece.rotYOffset, piece.rotZOffset = getRandomRotationOffsets()
 piece.angle1Offset, piece.angle2Offset = getRandomAngleOffsets()
 piece.angle1, piece.angle2 = piece.angle1Offset, - math.pi / 2
 pieces[i] = piece
 if model == 2780 then --fog machine
 setTimer ( setElementAlpha, 500, 1, piece.object, 0 )
 end
 setTimer ( setElementCollidableWith, 500, 1, getLocalPlayer(), piece.object, false )
 else
 return false
 end
 end
 
 function createTornado()
 outputChatBox ( "Tornado started." )
 pieces.dummyTornado = source
 onStart() --!!
 end
 
 addEvent ( "onTornado", true )
 addEventHandler ( "onTornado", root, createTornado )
 
 function destroyTornado()
 local timers = getTimers ()
 for k, v in ipairs(timers) do
 killTimer ( v )
 end
 removeEventHandler ( "onClientRender", root, updateElementsPosition )
 for i=1, #pieces do
 local object = pieces[i].object
 destroyElement ( object )
 pieces[i] = nil
 end
 end
 
 addEvent ( "onTornadoStop", true )
 addEventHandler ( "onTornadoStop", root, destroyTornado )
 
 function onStart()
 -- tumbleCount = 0 --debug
 -- fogCount = 0 --debug
 
 tornadoRender = addEventHandler ( "onClientRender", root, updateElementsPosition )
 local fogMachines = math.floor(pieces.count * pieces.fog) --Percentage of objects to be fog machines
 local tumbleWeeds = math.floor(pieces.count * (1-pieces.fog))
 local spacing = math.floor(tumbleWeeds / fogMachines)
 local majorityIsFogMachines = false
 spaceCount = 0
 if spacing < 1 then
 majorityIsFogMachines = true
 spacing = math.floor(fogMachines / tumbleWeeds)
 end
 --debug
 -- outputChatBox ( "pieces.fog = "..pieces.fog )
 -- outputChatBox ( "pieces.count = "..pieces.count )
 -- outputChatBox ( "fogMachines = "..fogMachines )
 -- outputChatBox ( "tumbleWeeds = "..tumbleWeeds )
 -- outputChatBox ( "majorityIsFogMachines == "..tostring(majorityIsFogMachines) )
 -- outputChatBox ( "spacing = "..spacing )
 --debug
 for i=1, pieces.count do
 setTimer ( createTornadoPiece, i * 50, 1, i, spacing, majorityIsFogMachines )
 end
 end
 
 function clientPlayerJoin ()
 setTimer ( function ()
 if not tornadoRender then
 onStart(source)
 end
 end, 1000, 1 )
 end
 addEventHandler ( "onClientResourceStart", getResourceRootElement ( getThisResource() ), clientPlayerJoin )
 
 --addEventHandler ( "onClientResourceStart", getResourceRootElement ( getThisResource() ), onStart )
 --local newPosX = tx + pieces[i].posXOffset + pieces.width * ( 1 + thickness - math.cos ( math.asin ( ( oldPosZ - posZOffset - tz ) / ( height * 1.05 ) ) ) ) * ( math.cos ( pieces[i].angle1 + pieces[i].angle1Offset ) )
 5) Создать "tornado_s.lua", и вставить код:
 
 
 Code local root = getRootElement() local resourceRoot = getResourceRootElement ( getThisResource() )
 local dummy = nil
 --local dummy2 = createObject ( 1337, 0, 10, 4 )
 
 function spawnAllPlayers()
 players = getElementsByType ( "player" )
 for k,v in pairs(players) do
 r = 5
 angle = math.random(0, 359.99) --random angle between 0 and 359.99
 centerX = 38.977
 centerY = -19.282
 spawnX = r*math.cos(angle) + centerX --circle trig math
 spawnY = r*math.sin(angle) + centerY --circle trig math
 spawnAngle = 360 - math.deg( math.atan2 ( (0 - spawnX), (0 - spawnY) ) )
 spawnPlayer ( v, spawnX, spawnY, 2.5, spawnAngle )
 end
 end
 
 function spawnAndBindJoinedPlayer()
 local player = source
 setTimer ( createTornado, 1000, 1 )
 setTimer ( function()
 r = 5
 angle = math.random(0, 359.99) --random angle between 0 and 359.99
 centerX = 38.977
 centerY = -19.282
 spawnX = r*math.cos(angle) + centerX --circle trig math
 spawnY = r*math.sin(angle) + centerY --circle trig math
 spawnAngle = 360 - math.deg( math.atan2 ( (0 - spawnX), (0 - spawnY) ) )
 spawnPlayer ( player, spawnX, spawnY, 2.5, spawnAngle )
 
 bindKey ( player, "num_8", "down", move, "up" )
 bindKey ( player, "num_4", "down", move, "left" )
 bindKey ( player, "num_6", "down", move, "right" )
 bindKey ( player, "num_5", "down", move, "down" )
 end, 1500, 1 )
 end
 
 function createTornado()
 dummy = createObject ( 1337, 0, 0, 2 )
 setElementDimension ( dummy, 69 )
 triggerClientEvent ( "onTornado", dummy )
 -- outputChatBox ( "..." )
 end
 
 -- function lol()
 -- local x, y, z = getElementPosition ( dummy2 )
 -- local rotX, rotY, rotZ = getObjectRotation ( dummy2 )
 -- local x2, y2, z2 = getElementPosition ( getPlayerFromNick ( "norby89" ) )
 -- local newRotZ = math.deg ( math.asin ( ( x - x2 ) / getDistanceBetweenPoints2D ( x, y, x2, y2 ) ) )
 -- outputChatBox ( newRotZ )
 -- setObjectRotation ( dummy2, rotX, rotY, newRotZ )
 
 -- end
 -- setTimer ( lol, 100, 0 )
 
 function move ( player, cmd, state, direction )
 local x, y, z = getElementPosition ( dummy )
 if ( direction == "up" ) then
 moveObject ( dummy, 10000, x, y + 100, z )
 elseif ( direction == "left" ) then
 moveObject ( dummy, 10000, x - 100, y, z )
 elseif ( direction == "right" ) then
 moveObject ( dummy, 10000, x + 100, y, z )
 elseif ( direction == "down" ) then
 moveObject ( dummy, 10000, x, y - 100, z )
 end
 end
 
 function bindKeys()
 spawnAllPlayers()
 setTimer ( createTornado, 1000, 1 )
 for i, v in ipairs ( getElementsByType ( "player" ) ) do
 bindKey ( v, "num_8", "down", move, "up" )
 bindKey ( v, "num_4", "down", move, "left" )
 bindKey ( v, "num_6", "down", move, "right" )
 bindKey ( v, "num_5", "down", move, "down" )
 end
 end
 
 addEventHandler ( "onResourceStart", resourceRoot, bindKeys )
 addEventHandler ( "onPlayerJoin", root, spawnAndBindJoinedPlayer )
 Вот и всё! Урок готово
  . Теперь у вас на сервере будет торнадо. Для того чтоб редактировать его, жмем клавишу "M". 
 Вот ниже сделал скрин, где находится само торнадо. Примечание: При нажатии клавиши "M", вы телепортируетесь на место торнадо!!
   Ссылка на скрин: http://savepic.su/938303.png .
 |  |  |  |  |