Jump to content

Welcome to Gaming On Steroids Forums
Register now to gain access to all of our features. Once registered and logged in, you will be able to create topics, post replies to existing threads, give reputation to your fellow members, get your own private messenger, post status updates, manage your profile and so much more. This message will be removed once you have signed in.
Login to Account Create an Account
Photo

Lua and GoS guide! BEGINERS [prt1]

tutorial

  • Please log in to reply
33 replies to this topic

#1
TheFoxy

TheFoxy

    Advanced Member

  • Donator
  • 116 posts
  • LocationRight Here :P

 progui.png

Tiritto thank you for banner I <3 it ^ ^

Hai guys ^ ^
Even doe I'm not offically developer I've been getting a lot of PMs asking me where and how to learn Lua and make scripts (not a bad thing, pls keep PMimg me anytime about anything :) )
I promissed some answers so here I give them!
I'm going to expalin the basic Lua concepts needed for GoS and gonna reverse one of my own scripts I made for demostration/testing purposes. (Part 2)

Unfortunatly It can't get attention it deserves due to my bussy schedule of coffie drinking and swiming ^_^  :P
And traveling.... That's my new occupation ^ ^

>>>USE THIS TO TEST YOUR CODE<<<<
 
>>>OFFICAL GOS API<<<
 
Let's get started!
 
Unlike all many other languages Lua doesn't have datatypes. In C-langs you have int, float, double for numbers (plus few more), strings and chars for texts and ofc custom classes and structs that allow you to create your own datatype. In Lua NOPE!

Only two type which are automaticly implied: >Numbers and Words<. Custom datatypes exist in form of Tables and MetaTables :S

Each variable has local before it. In C-langs this is implied, unless you make it global. Lua is other way around you could say. Not making variable local makes it GLOBAL and accessable from ANYWHERE including Other Scripts :S

Obviously, this can cause problems :S

Global variables you will probably never use, and they come in handy in DataBases and some configurations that apply for your scripts. In that case make sure your variable name is hard to guess by accident, so only you and ppl who want to use it know how to do so : )

So local variables also have range and conflict resolution. In C++ and C# you can see use of "this" keyword (Lua has "self"), and methods that take pointers and references as parametes in order to change the value of variable outside of the method. In Lua this is not neccesay. We will get to methods soon since it's more of methods topic...
 

--how to define a variable?

local ThisIsNumber; -- ";" is not neccesary but I code in C-langs so it's a habit 
local ThisIsAWord --no ";" is fine too 
--Those two are not number nor a word right now. They are >NIL<! nil is not 0. It's a value that is exactly equal to NOTTING AT ALL
--It's undefined value and is used for many diferent purposes. I will expalin later more  so let's give some value to our variables ^ ^
ThisIsNumber = 10;
ThisIsAWord = "Ahri"; --notice the "". It's a signature of a string (word) like in other langs


--variables example 2--

local MyCurrentHealth;  --this variable is visible only in this script

MyCurrentHealthGlobal; --this one is visible outside of it to
--but lets get the value here so we don't leave them empty and sad  This time by a method!

MyCurrentHealth = GetCurrentHP(myHero);
--not nil anymore  I assumed that myHero is already defined so this works fine
--Gona talk about range of variables later :)

 
Soooo... what I did in 2. example is method (or function if you prefer) call.
What is a function?


Functions
 

Function is a piece of code that takes something in, process it and returns the result. Imagine if we have to solve an equasion 4 times in a program... We have to write same code 4 times :o
To avoid this we make a function that does it for us ^ ^ (lazyass)

Simple example: Let's say we give program 4 numbers.

Program adds first tow, substracts last two and multiplies the results. If we need to do that only once, that's fine. But, if we have to do it many times?
 

--so 4 numbers.

local n1;
local n2;
local n3;
local n4;

local theEndResult;

--Let's say they are given some values by the user (gonna show you how later)
--So this is wat user said
n1 = 5;
n2 = 2
n3 = 9
n4 = 4

theEndResult = (5+2) * (9-4) -- this equals 35
print (theEndResult) --prints 35 in the console

--Here you always have to write this theEndResult = [numebrs here]
--Let's do this the smart way



function Calculate(a, b, c, d)
    return (a+b) * (c-d);
end;



--Now we can do this

theEndResult = Calculate(5,2,9,4)

print(theEndResult); --prints 35

--or this

theEndResult = Calculate (n1, n2, n3, n4);

print(theEndResult); --prints 35 again
--EVEN this
print (Calculate (n1, n2, n3, n4));

--We can send any number we want and get right results in a single line 
--This looks easy but imagine if function has 50 lines. It's a life saver 

--##Few functions you might use a lot##
print(whatToPrint) --Prints stuff in on the screen console
io.read() --Gets the input from the user (console too)
math.sqrt(number) --Gets square root. Used in GoS for distance calculation by vector magnitude
--math. has many cool functions 

------GOS------

local myHero = GetMyHero(); --Obvious right?
local MyLocation = GetOrigin(myHero) --Gives your location in 3D in x,z,y coords
local MyMaxHP = GetMaximumHP(myHero) --Obvious? DUUUH
local MyCurrentHP = GetCurrentHP(myHero) --DUUUUUH
--etc... Read API, it's all there

Two more things. Flow control!


If statment and loops
 

Comon concept that is SAME in every programing language. Only diference is syntax. Stll I ll explain anyways ^O^
Let's say we made 2 functions before somewhere in the code. One is GoAllIn(target) and other is GoBak()

GoAllIn() will attack the target with all you got while GoBak() will keep safe distance by running and harrasing ocasionaly. How to know which one to call?

Let's say if our HP is bigger then target's we go all in and if not we keep it safe. Legit right?
(WRONG! legit would be to use % but I'm lazyass)
Let's code! :D
 

---example functions
function GoAllIn(target)
--go all in deffiniton here
end;
function GoBak()--notice it has no params. This is toally ok 
--go back deffiniton here
end;
---

local MyHero = GetMyHero();
local target = GetTarget(); --returns target by GoS logics (quoted lol)
local ourCurrHP = GetCurrentHP(MyHero);
local targetCurrHP = GetCurrentHP(target);
----possible branchings-----
--1st
if ourCurrHP > targetCurrHP then GoAllIn(target)
    else GoBak() end; -- end marks the end of if braching
--2nd
if not ourCurrHP < targetCurr then GoAllIn(target)
    else GoBak() end;
--wat about "=" ?? Let's do this the right way! >_<
function FarmAndHarras()
--Imagine we declare it here
end;

if outCurrHP > targetCurrHP then GoAllIn(target)
elseif ourCurrHP < targetCurrHP then GoBak()
    else FarmAndHarras() end; --If it's not < nor > it's = right?
--end marks end of if branching. Elseif is not same as 2 times if. If we put if insted if elseif like:
if outCurrHP > targetCurrHP then GoAllIn(target) end;
if ourCurrHP < targetCurrHP then GoBak()
else FarmAndHarras() end;
--and first if gives true then second if will be checked anyways. In elseif only 1 if can give ture and it will check as long as it's not true.
--Once it is ture, others wont be checked. Use this for options and branching.
--So double if is WRONG. elseif is rigt

Let's talk about range! (Basic concept, more info here http://www.lua.org/pil/4.2.html)


--##RANGE##--
local hue = 3
do
    local hue= 4
    print(hue);
end;
print(hue);
--what's the output? ^ ^

--try this
local statment = "Oh I get it now!"
function example()
    local statment = "Tricky little fox >_<";
    print (statment);
end;
example();
print(statment);
Some useful functions are:
--Range of a variable goes to it's instance if there is one like loops (while, for, repeat),do block and functions.
--Range of those blocks of code ends with "end;" and after that the block is closed and range of variables is extended to next block
--So if you have do method inside of while and inside of for loop (blockseption!) "end;" will close inside blocks and switch to next one


Loops
 
Outside of tables there are 2 loops main loops: While and For
While Loop
->Does stuff as long as a condition is satisfied. Condition expresion must be true
The syntax of a while loop in Lua programming language is:
 


while(condition) -- checked on begining and after every "end"
do --starts the loop
statement(s);
end; --ends the loop

 
 
 
Example code:
 

a=10 
while( a < 20 )
do
   print("value of a:", a)
   a = a+1 --this is called >>INCREMENT<<, C-langs a++ or ++a. without this line we would have infinite loop :S
end;

Loops are usualy used with tables to print out their members. More on this later : )
 
For loop
  
Used to do stuff given number of times rather than to meet condition. Syntax below:

for init,max/min value, increment
do
statement(s)
end;

Example:

for i=10,1,-1 --i=10 -> start value (refered to as counter sometimes), 1 -> end value, -1 is DECREMENT. It reduces value of counter while INCREMENT increses it 
do --Increment can be skipped if it's obvious, Lua will check for start and end value after that decide for -1 or +1. You can use +2 or any other value too but must do so manualy :)  
   print(i) --gonna print the value
end; --ends the loop and returns to start while counter is not equal to end vaule

--infinite loop example

for i=10, 1, 1
do
      print (i);
end; --I didn't test this tbh :S
 
 
Obviously, condition will never be met here...
 
Tables
  
A table is godly thing in Lua. It's an single/multi dimension array, class and namespace and sometimes with use of metatables it's a object or even an abstract class or interface!
I won't go through all if it, because.....reasions (I'm :lazy: tbh and don't wanna spoil the fun of learning by yourself :P)
I will divide this in few parts:
-->Array
-->Multi Array (2D, example purposes)
-->Table of tables (simple imitation of "class")
-->Table of methods
 

--Single dimension array... Easy thing, put multiple stuff in single variable :)
local array1D = {}; -->This marks empty table
local array1D = {2,4,6,8,10};
--array in Lua starts at index "1", not "0" as in C-langs. "0" will giv you nil, not an error
print(array1D[3]) --prints 6
print(array1D[0]) --prints nill
print(array1D[5]) --print 10
print(array1D[98789]) --BLUE SCREEN OF DEATH INCOMING :O :O :O :O, Kidding, overreaching index gives nil,
--in C-langs this exception will crash the program, here it's juts nil :)
--*sigh of relef*--

--Wat if.... We wanna print all of the members in table? To do that 100% right via simple loop we need 2 conditions:
--->Number of members in table
--->No nil members in table defined by us
--if we meet any of these conditions we don't need to meet other one :) (if not, we need metatable but not gonna go there for now)

-------Let's do dis--------
local array = {1,3,5,7,9,nil,nil,15};
--let's assume we know there are 8 numbers
local i;
for i=1,8,1
do
print(array[i])
end;
--see what we did? "i" changes every time loop hits end and increses by "1". First time it's 1, den 2, den 3 till it's 8.

--What if do not know how many we have BUT there are no nils in array
local array = {1,3,5,7,9,11,13,15};
local i = 1;
while (array[i]~=nil)--or while (array[i]), same thing
do
print (array[i])
i=i+1;
end;

----GoS-like example---
--Let's assume we have list of all players in a table called Players
local Players = GetAllPlayersExampleFunctionWhichIwillAddLater();
--so now we want to get enemy and ally players and find Ahri among them

local AllyPlayers={};
local EnemyPlayers={};
--we know there are 10 players right?
--Let's assume we declared IsAlly() function, I ll show you the acctual code in part 2, this is example function now :)
local counter=10
for i=10,1,-1 --Runing the loop in oposide direction. Wanted to show you it's possible :)
do
    if IsAlly(AllPlayers[i]) then table.insert(AllyPlayers, AllPlayers[i])
else
    table.insert(EnemyPlayers, AllPlayers[i]) end;
end;
--After the loop we should have 5 ally players and 5 enemy players. Let's say we want to find Ahri in our team. Let's use while this time ^ ^
while (GetObjectName(AllyPlayers[i]~="Ahri" or nil))--checks for Ahri, if non of 5 is Ahri then 6th will be nil and that means there is no Ahri in team :(
do
    i=i+1; -- ^ ^
end;
--Let's check if we have Ahri or not now shall we?
if AllyPlayers[i]==nil then print("There is no Ahri in your team")
    else
        print("You have Ahri! You can't loose =^_^=");
    end;
--You do check for enemy players with for loop :P

Smtg extra: Repeat loop

i = 3
while i > 1
do
   print(i.."\n")--"\n" is newline, it like pressing enter
   i = i - 1
end

repeat
   print(i.."\n")
   i = i + 1
until i = 3


--results:
3
2  <-- last output of the WHILE
1  <-- first output of the REPEAT
2

-->2D Arrays
For loop is most comon here. Let's create matrix(rows,columns) 3,4.
Think of it as 3 arrays of 4 members! We will create 3 rows and have them hold 4 members ^ ^


local Matrix = {};
local rows = 3;
local cols = 4;

for i=1,rows do
   Matrix[i]={};
      for j=1,cols
      do
         Matrix[i][j] = i + j; --some value, in this case sum of indexes
         print(Matrix[i][j]);
             end;
     end;
--Not going to expalin too much, if you want to know PM me since it's not very common in GoS and there are
--good explanations online

-->Table Of Tables ! (Tableseption) !
I introduced you with tables on small scale. Array is lame use of tables >_<
Difference betwen Array and a Table is indexing! Array has intiger indexes in ascending order.
In tables you can use string or even variable values as indexes ^ ^


local FoxyTable {"TailNumber"=9,"IsCool"=true};
--or
FoxyTable.AmIAhri=true; --same as FoxyTable["AmIAhri"=true];
--now we can do this:
print(FoxyTable.TailNumber);
print(FoxyTable.AmIAhri);

So this is cool, but just as in variables this values are FIXED. What if the value changes? Like cooldowns and HP in game right? Hp is not same all the time, so we would have to change the HP every frame or every 100ms or smtg :S
Same goes for cooldowns... This is possible but imagine that while game is running you are changing the value all the time... Do I need to say that this will drop FPS?
Workaround: Table of Methods :)

Let's say we have a value that will change every 100ms. I will call this value TrickyValue. Now we need to store that value in SmartTable so that we we call print(smartTable) it get's print at IT'S CURRENT value. Not the old one.

--let's assume this value changes all the time
local trickyValue = ChangeValueInTime(); --Let's assume it's 5 now
local StupidTable = {["Foxy"] = {NumberOfTails = trickyValue, ["IsAhri"] = false}}; --Number of tails is 5 
if StupidTable.Foxy.NumberOfTails == 9 then StupidTable.Foxy.IsAhri=true end; --so we want to check if the fox here is Ahri by cheching 
--her tail numberbut :(.... It's not fixed :S
--Let's assume that at the moment we run this code number is 5, 0.3 sec later it's 4 then 8 etc.
--We can see that we have number 5 stored in NumberOfTails
print (StupidTable.Foxy.NumberOfTails)--prints 5
print (trickyValue)--prints 8
--#Problem#--
--Let's fix
local StupidTable = nil; --Cuz it's stupid >_< So long you stupid table!
local SmartTable = {["Foxy"] = {NumberOfTails = function() return trickyValue end, ["IsAhri"] = false}} --Method!!!
--Nnotice we did not give a name ti method. This is known as Annonymous Method in C# (I think). It's not rlly a delegate doe :S
--This method will get the trickyValue when we ask for it! But how to demand? :S
if FoxyTable.Foxy.NumberOfTails() == 9 then FoxyTable.Foxy.IsAhri=true end; --() is method call! Remeber? We did it before :D
--GOS EXAMPLE--
function CreateSpellBook(myHeroPtr)
local Data = { 
               ["Q"]={ isReady = function() return CanUseSpell(myHeroPtr,_Q) == READY end, lvl =function() return GetCastLevel(myHeroPtr,_Q) end, range = function() return GetCastRange(myHeroPtr,_Q) end, cmana = function() return GetCastMana(myHeroPtr,_Q) end, cd = function() return GetCastCooldown(myHeroPtr,_Q) end, sname = function() return GetCastName(myHeroPtr,_Q) end},
               ["W"]={ isReady = function() return CanUseSpell(myHeroPtr,_W) == READY end, lvl =function() return GetCastLevel(myHeroPtr,_W) end, range = function() return GetCastRange(myHeroPtr,_W) end, cmana = function() return GetCastMana(myHeroPtr,_W) end, cd = function() return GetCastCooldown(myHeroPtr,_W) end, sname = function() return GetCastName(myHeroPtr,_W) end},
               ["E"]={ isReady = function() return CanUseSpell(myHeroPtr,_E) == READY end, lvl =function() return GetCastLevel(myHeroPtr,_E) end, range = function() return GetCastRange(myHeroPtr,_E) end, cmana = function() return GetCastMana(myHeroPtr,_E) end, cd = function() return GetCastCooldown(myHeroPtr,_E) end, sname = function() return GetCastName(myHeroPtr,_E) end},
               ["R"]={ isReady = function() return CanUseSpell(myHeroPtr,_R) == READY end, lvl =function() return GetCastLevel(myHeroPtr,_R) end, range = function() return GetCastRange(myHeroPtr,_R) end, cmana = function() return GetCastMana(myHeroPtr,_Q) end, cd = function() return GetCastCooldown(myHeroPtr,_Q) end, sname = function() return GetCastName(myHeroPtr,_R) end},
             }
             return Data;
         end;

--Taken from my SpellBook method I created for spell database :)
--I could do value updates onLoop() but that would drop the FPS so I made it on demand ^ ^
local myFox = GetMyHero();
local AhriSpellBook = CreateSpellBook(myFox);
--Let's check for cooldown on Q
print (AhriSpellBook.Q.cd());
--TADA! :D

 
Wanted to do it all in one tut but it would be so huge so decided to seperate offical API examples and analysis from Lua introduction
-->Errors are possible, example methods won't run in Lua online compiler! You need to define them! Also, API functions won't run for same reason
CHALLANGE FOR YOU!
 
Whenever I picked one way, you solve the problem other way AND try to code my example functions : )
I will code all of them in PART 2 which will be rlly about GoS and will alow you to code your first assembly ^ ^
I was away for a while and API changed so need to update my assembly before I can reverse it for you guys :S
Part 2 comming soon ^ ^
Usefull stuff! Ask for more if you want I will share! <3 you guys! ^ ^
http://www.tutorials...ua_for_loop.htm
http://www.tutorials...ment_in_lua.htm
http://www.tutorials.../lua_tables.htm -->Read this!
For advanced padawans:
http://www.tutorials..._metatables.htm --> I understand this hueheuheueheue ( ̄ー ̄)
http://www.tutorials...ct_oriented.htm -->For brave ones!
 
Have fun learning nabs! (=^-^=)
If you have questions ask me (PM) or post below <3


  • 14

#2
Cloud

Cloud

    KAPPA

  • Ex-Staff
  • PipPipPip
  • 1,498 posts

pretty good overall. Fix you're title from gude to guide.


  • 0

#3
TheWelder

TheWelder

    Advanced Member

  • Members
  • 195 posts
  • LocationPortugal

Gj man im sure it will answer many ppl questions :)


  • 0

#4
KZSPGE

KZSPGE

    Member

  • Members
  • 10 posts

Definitely my fav user in this community <3 Thanks once again

print("Upvoted");

print("Foxy4eva is my godess <3");


  • 0

#5
WizKalibog

WizKalibog

    Advanced Member

  • Members
  • 174 posts
  • LocationSA PILIPINAS KONG MINAMAHAL

F*cK i Cant Understand o.0


  • 0

#6
TheFoxy

TheFoxy

    Advanced Member

  • Donator
  • 116 posts
  • LocationRight Here :P

F*cK i Cant Understand o.0


What exactly?
If you don't understand anything at all you might need some programing introduction.
PM me so we can talk ;)
  • 0

#7
TheFoxy

TheFoxy

    Advanced Member

  • Donator
  • 116 posts
  • LocationRight Here :P

Definitely my fav user in this community <3 Thanks once again
print("Upvoted");
print("Foxy4eva is my godess <3");


Awwwww thank you! :D
^_^
  • 0

#8
lbmain

lbmain

    Advanced Member

  • Members
  • 297 posts
  • Locationsomewhere over the rainbow

FINNALY someone actually explain this stuff, hope inspired knows that not everyone was born as a GENIUS.

we r just normal people QQ

 

keep it up


  • 0

#9
leozinho23

leozinho23

    Member

  • Members
  • 12 posts

great guide, do you know where I can find GoS API documentation?


  • 0

#10
Asserio

Asserio

    Advanced Member

  • Members
  • 254 posts
  • LocationPortugal

I already do scripts for GoS, but still going to read this guide  :D . GJ! :P


  • 0

#11
ilovesona

ilovesona

    Sona's wife

  • Contributor
  • 1,096 posts

I think we need a new sub forum for guide...


  • 0

#12
TheFoxy

TheFoxy

    Advanced Member

  • Donator
  • 116 posts
  • LocationRight Here :P

great guide, do you know where I can find GoS API documentation?



Here http://gamingonstero...ha-version-009/
I suggest to print it out ^ ^

FINNALY someone actually explain this stuff, hope inspired knows that not everyone was born as a GENIUS.
we r just normal people QQ

keep it up

No one is born with knowledge! Even Einstein had to learn to count to ten... Inspired is not born knowing Lua nor he is a genius. He is excellent programmer I give him that. But while you were playing games and having fun he was learning to program... He gave up fun in order to learn, ofc it paid off :)
My guess is that he probably learned Lua before, probably BoL, otherwise he is just like me and you only more persistent.
Remember, you can learn and do ANYTHING If you decide to! You need :
1) To decide
2) To dedicate time have a strong whish to accomplish that
3) Be ready to make mistakes and go through them. Learn from them... More you make, more you learn ;)
4) Be consistent
5) Intelligence will help you but notice I put it last cuz it's least important. More intelligent people just do things faster but not necessarily better :)
If you get stuck at any point contact me! I'm willing to help out :)
Goes for anyone. I respond to every PM ^_^
Good luck!
  • 0

#13
Nivo

Nivo

    What is script?

  • Ex-Staff
  • PipPipPip
  • 503 posts
  • LocationBadmanville

No idea what I just read.. oh well..


  • 2

#14
Deftsu

Deftsu

    donthackourgames

  • Ex-Core Dev
  • PipPipPip
  • 4,812 posts

No idea what I just read.. oh well..

gj :fappa:


  • 0

#15
Zypyzypyzy

Zypyzypyzy

    Advanced Member

  • Members
  • 34 posts
  • LocationPolen

good job


  • 0

#16
Tiritto

Tiritto

    Script Developer

  • Members
  • 377 posts
  • LocationPoland

What can I say, good job and a great guide for LUA scripting! I'm curious about what you write in the next section.  ^_^

I suggest you put a link to the API documentation somewhere in a visible place your guide, because I myself for some reason had a problem with finding it.

By the way I have a question - can translate your tutorial and put it on our Polish board? Of course, retaining the information that you are the author of this guide.


  • 0

#17
TheFoxy

TheFoxy

    Advanced Member

  • Donator
  • 116 posts
  • LocationRight Here :P

What can I say, good job and a great guide for LUA scripting! I'm curious about what you write in the next section.  ^_^

I suggest you put a link to the API documentation somewhere in a visible place your guide, because I myself for some reason had a problem with finding it.

By the way I have a question - can translate your tutorial and put it on our Polish board? Of course, retaining the information that you are the author of this guide.

Sure :)

I don't speak Polish doe...

Ask Nivo for help, he is very helpful and he was local and global support and ofc he is Polish ;)

Just loves to help out ^_^


  • 1

#18
Tiritto

Tiritto

    Script Developer

  • Members
  • 377 posts
  • LocationPoland

Thank you. Guide has already been translated into Polish and is located here.

I also created an simple banner for your guide. I hope you like it.

It isn't amazing, but I think it's cool enough for now until you find a batter one.

 

progui.png
http://s9.postimg.or...odnj/progui.png


And once again, thank you for your excellent guide.
Btw. There is a small mistake in your 1st loop example. You used "//" to comment the code instead of "--". I see the habit of C-languages.  Keppo


  • 1

#19
Delshire

Delshire

    Advanced Member

  • Members
  • 75 posts

Nice job, good tutorial for begginers!


  • 0

#20
TheFoxy

TheFoxy

    Advanced Member

  • Donator
  • 116 posts
  • LocationRight Here :P

Thank you. Guide has already been translated into Polish and is located here.
I also created an simple banner for your guide. I hope you like it.
It isn't amazing, but I think it's cool enough for now until you find a batter one.
 

progui.png
http://s9.postimg.or...odnj/progui.png


And once again, thank you for your excellent guide.
Btw. There is a small mistake in your 1st loop example. You used "//" to comment the code instead of "--". I see the habit of C-languages.  Keppo


You know what they say, old habbits die hard :)
Gonna fix it ;)
Thank you and thx for banner gonna use it :D

Nice job, good tutorial for begginers!


Some begginers *cough* Nivo *cough* still don't understand so I'm considering making a new and more basic one like part [0] or smtg
Not sure doe... Gonna finish up on part 2 and see reactions :S
Glad you liked it :)
  • 0





Also tagged with one or more of these keywords: tutorial

1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users