ID:264460
 
Code:
mob//Teacher
verb
Modify_House_Points(mob/M in world)
var/points = input("Input the number of points you'd like to add. Put a - infront of the number to take away points.","House Points")
if(M.house=="Ravenclaw")
var/p = text2num(points)
rpoints += p
if(findtext(points,"-"))
points -= "-"
world<<"[M] has caused Ravenclaw to lose [points] points!"


Problem description: I've never done something like this before, but I'm currently trying to remove "-" from a text string. The problem here is that points -= "-" causes a type mismatch and stops the message from being given.

The point of this verb is to make it that to change "House Points" the usr only needs the one verb, where they simply make the number negative to remove some of the points. Unfortunately, when displaying said number, I don't want the players to be wondering about the - that will randomly have appeared there (at least to them, since most games of this type simply feature a remove and add).

Demon_F0rce wrote:
but I'm currently trying to remove "-" from a text string. The problem here is that points -= "-" causes a type mismatch and stops the message from being given.

If you had looked up the -= / - operator, you'd have seen that there's no use of it that involves strings. You just guessed there was.
To remove something from a text string, you need to do it 'manually' with findtext() and copytext(), generally like this:
proc
remove_text(maintext,txt,ignore_case)
var/pos = ignore_case? findtext(maintext,txt) : findText(maintext,txt)
if(pos)
maintext = copytext(maintext,1,pos) + \
copytext(maintext,pos+lentext(txt))
return maintext

You could probably find something similar in various libraries. Of course, in this case, since all you want to remove is the first character of the string (note you haven't actually ever validated "-" was in the beginning, but you should have), it's enough to do something like this:
var/T = "-10"
world << copytext(T,2) //skip the first character

The result is the text string "10", which is output to the world.

However-

to change "House Points" the usr only needs the one verb, where they simply make the number negative to remove some of the points. [...] I don't want the players to be wondering about the - that will [...] have appeared

-to do this, you don't need to worry about string removals at all, because you don't have to ever use strings here in the first place, and it's better not to. Just stick to using numbers throughout all the code there: the as num input type does allow players to input in not only number digits, but also the "-" and "." characters, to allow them to also input negative or fractional numbers (and you very often need to watch out for that!). Then you can just use the simple math operators and the abs() proc to do anything that is needed - I leave it to you to figure it out.

Also, I'll note that the design of...
           if(M.house=="Ravenclaw")
var/p = text2num(points)
rpoints += p
if(findtext(points,"-"))
points -= "-"
world<<"[M] has caused Ravenclaw to lose [points] points!"
if(M.house == "something else...")
//the same thing again but a word or 2 changed

...is weak (and, of course, repetitive). I'd try to come up with a better design (and I don't mean changing to using switch() there, though that would still be a minor improvement), if I were you.
EDIT: typofix
In response to Kaioken
Kaioken wrote:
world << copytext(T,2) //skip the first character

The result is the text string "10", which is output to the world.

This is what I'll probably end up using, thanks.


the as num input type does allow players to input in not only number digits, but also the "-" and "." characters, to allow them to also input negative or fractional numbers ... . Then you can just use the simple math operators and the abs() proc to do anything that is needed - I leave it to you to figure it out.

Never knew of the abs() proc 'till now. Maybe I should start looking up random procs and vars in the DM Reference from now on...

I also find it funny that before now I must have been using as num wrong because I never found it working like that before...


Also, I'll note that the design of...
>            if(M.house=="Ravenclaw")
> var/p = text2num(points)
> rpoints += p
> if(findtext(points,"-"))
> points -= "-"
> world<<"[M] has caused Ravenclaw to lose [points] points!"
> if(M.house == "something else...")
> //the same thing again but a word or 2 changed

...is weak (and, of course, repetitive).

Really? I can see some methods to make it look better and work a little more smoothly (which I'm working on, won't take long...), but could I enquire as to what you think would be a better way to achieve this?
In response to Demon_F0rce
world << "[src] has caused [M.house] to [points>=0?"gain":"lose"] [abs(points)] points."
scores[M.house] += points
In response to Demon_F0rce
Demon_F0rce wrote:
This is what I'll probably end up using, thanks.

Against my recommendation, though! I recommend to use only numbers in that verb, as you don't need to resort to text strings - which also, if you have the player input it as a text string, he could type whatever there (which you'd also need to check for), however it should be limited to a number only.

Never knew of the abs() proc 'till now.

Heh, you could've expected there to be one, since it's a kinda basic math function. You could always get the opposite of a number with 0-number anyway, too.

Maybe I should start looking up random procs and vars in the DM Reference from now on...

Actually, I did recommend to people on some occasions to read through the whole Reference at least once, as if it was a guide. At the very least, read the headers so you have at least an idea of the functions available. It helps to know what you can do with the language and what's built-in to it, and how things work, etc.

I also find it funny that before now I must have been using as num wrong because I never found it working like that before...

I assume you refer to using the as num input type but not checking in case a sneaky player decided to input a negative or fractional number? Kinda a common mistake, which can, of course, have varying, usually exploitable or otherwise undesirable effects depending on the situation.


Really? I can see some methods to make it look better and work a little more smoothly (which I'm working on, won't take long...), but could I enquire as to what you think would be a better way to achieve this?

Well, that naturally depends on the game, and how the concept of houses is implemented, etc. If in your game, the houses are a prominent factor and are complex (e.g. each house can have multiple attributes), then maybe you should implement them through datums. But, if all you care about is how many points each house has and which players are in which house, and you don't really need to do stuff with the 'houses' themselves (rather more in the direction of dealing directly with the players, which may be present in a certain house), and so houses are a simple concept in your game, they could be implemented by just keeping track of the points in a global variable, and houses could be identified by a certain value on the players (you have text strings, it could also be a number, for example). Then a better method to get this verb working could be to keep track of the houses and their points' via a global, associative list. All in all, it could look like this (example intended for illustration only):
var/list/houses = list("Griffindor"=123,"Ravenclaw"=100,...)
//or, the initial initialization could just be with no associated values
var/list/houses = list("Griffindor","Ravenclaw",...)

mob/person
var/house
teacher/verb/Modify_House_Points(mob/person/M in view(src),amount as null|num)
if(!M.house || !(M.house in houses))
/*if he's not in a house, or his house isn't in the
global houses list (the latter is a safety check that
you don't need if you're sure you're doing things right)*/

src << "[M] isn't in a house!"
return
if(!amount) return //(if they input 0 or canceled)
if(amount != round(amount,1)) //if the amount given isn't a whole number
src << "You can't use fractional numbers!" //notify points must be whole
return
houses[M.house] += amount //modify the associated value of the house by the amount
world << "[M] has caused [M.house] to [amount > 0? "gain [amount]" : "lose [abs("amount")]"] points!"

EDIT: Included example of how to handle players inputting fractional numbers.
EDIT2: Fixed it. =D
In response to Kaioken
Modulo is a purely integer operation, so you can't use it to determine if a number has a fractional component. You need to use round().
In response to Kaioken
"lose [abs("amount")]"
Returns zero for numbers. Fixed by taking out the quotation marks around amount =P.
In response to Demon_F0rce
Obviously the quotation marks shouldn't be there. =P I must've been confused from all the syntax mess there and made that slip up.