ID:700670
 
(See the best response by GhostAnime.)
Code:
        Give_Levels_To_world()
set category = "Admin"
if(GMLockCheck())
usr<<"<font face ='Palatino Linotype' color=Green>Your Admin Powers Are Locked."
return
switch(alert("Give levels to every player logged in?","","Yes","No"))
if("Yes")
var/lvlin=input("How many")as null|num
if(lvlin==null||!lvlin||!usr)return
for(var/mob/PC/M in world)
if(M.loggedin && M.client)
if(!istype(M,/mob/PC))return
M << "[usr] gave you [lvlin] levels. Be patient while they add to your stats."
M.levelgains = 0
while(lvlin>0)
M.exp = M.tnl
M.Level_Up()
lvlin -= 1
sleep(1)
world<<"<b><font face ='Palatino Linotype' color=Green>[usr] has given everyone Levels!</b>"
else
return


Problem description:it gives levels to only 1 player.

it comes up like this
for the first player-
Mystic gave you 100 levels. Be patient while they add to your stats.

for other players -
Mystic gave you 0 levels. Be patient while they add to your stats.

I believe this is happening because your while() loop decreases the value of lvlin, thus by the time it reaches the second user, there are no more 'levels' left to give.
so what is the solution ??
That's up to you to figure out! You'll learn more if you fix it yourself rather than having someone do it for you. =]
i am not understanding what you are saying
i am not good with the while() and for() loops.

thnx for the help
Best response
Hey there,

Here are some future tips and *A* solution to your problem (with programming, there's usually more than one way to complete an item. The question is how efficient and readable they are):

!variable
The ! operator is used in Boolean operation (pretty much universal in most, if not all programming languages). Boolean operations have ONLY two values: true or false.

In DM, false is defined as either: null, "" or 0.
("" being an empty string, it actually is different from null which can be tested through an if() statement)

In programming, most conditional statements (ex: if(), while()) occur if the conditions entered inside is 'true'.
Ex:
if(value == 3)  // this will happen if the value is 3
if(variable) // This will happen if the value is true; in DM, this means any value EXCEPT null, 0 and "" (a reference to an object will evaluate the condition as true).


Now, you might notice a problem... if conditional statement only run if the condition is true, how do we get them to run for false value instead if that's what we are interested in?

It's simple: The ! operator (and the else statement if you are evaluating an if() statement with a true value :P)

The ! operator is a switch. It makes false --> true and vice versa. This includes if(value != 3) <-- could have done if(value == 3) with an else statement but the!= is much more efficient and compact.

Note that if you have more than one operator, be aware of the order of operation. An infamous example is the keyword "in", which has a lower standing than ! (meaning ! is evaluated first than in) so make sure to use brackets!
if(!item in inventory)  ==  if((!item) in inventory) == if((1 or 0) in inventory) === if(0) // because you are looking for a number in an inventory which contains objects.
// This happened because ! > in in the order of operation

if(!(item in inventory)) == if(!(1 or 0)) == if(0 or 1)
// Note the swap now of the 0 and 1. THe parenthesis has a higher operation so everything in the brackets was done first. Think of BEDMAS type of scenario


So when you do if(!lvlin), you will be telling DM to actually do:
if(!lvlin) == if( lvlin == null  || lvlin == 0 || lvlin == "")
Handy little thing isn't it?


Loops
In the loop, you use 'return' when something other than /mob/PC is encountered. The problem with return is that it STOPS the procedure RIGHT THEN AND THERE!

So, how do you make the loop skip the entry when looping through? Several way:
1) You can have a statement saying if(!istype...), as you do
2) Use the keyword 'continue'. This tells DM to skip the current looped entry to the next (so continue == next in some other languages)

Now, if you want the loop to stop when something is satisfied but NOT to stop the procedure (proc), you need to use the keyword 'break'. Simple neh?

Of course, you were looping for all /mob/PC in the for()which means DM looked for all that parent and child, so that is not where your issue resides...


Be aware of what you are telling DM
As Deathguard noted, your problem is that you are decreasing lvlin. So the first person is given all that level and the next person gets nothing because you subtracted all the value to 0!

There are many ways to solve this but I will give you two examples:

1) Use another variable.
So when you are looping through /mob/PC's, have another variable defined using the value in lvlin - that way it replenishes the value every time it loops
for(...)
var lvn = lvlin
while(lvn > 0)
lvn -= 1
...

2) Have another loop
It's actually the same thing as #1 but with a different (and a shorter) way of writing the snippet.

In DM, there are a few different ways to use for(). One of them includes this unique for() list loop:
for(lvn = 1 to lvlin)
...


Note that there is an alternate form of this function as well:
for(variable = min to max)
for(variable in min to max)

If you want to do 100 beers on the wall, you could do:
for(var/i = 1 to 100)
world << "Number of beer on the wall: [100-i]"

OR

for(var/remain in 1 to 100)
world << "Number of beer lost: [i]"


You could do it the old fasioned loop way as well:
for(lvn = lvlup; lvn > 0; lvn -= 1)


Other notes
Though not really an issue in verbs, note that input() and alert() use usr as the source of who to ask by default. In certain procedures (like movement procedures such as Entered()), this will cause a usr abuse - since "usr" may not actually be defined!

Edit: If you want to have a sleep() involved so the world does not freeze up much during the leveling, maybe you should put the sleep(1) when looping through the /mob instead of during the levelling. This will reduce the delay time.

Also, if you want to make the for() loop more efficient, search for all clients then refer to their mobs. That way you are only checking players logged in and no NPCs:
for(var/client/C)  //  note no in world, etc.
var/mob/M = C.mob // get the /client's /mob
if(M.loggedin)
...