Page 2 of 3

Posted: Fri Oct 07, 2011 1:51 am
by pinback
Tdarcos wrote:But the fact of the matter that misspecifying the line as one line instead of two is not flagged by the compiler and causes the game to lock up,
This is the part you're missing, by the way. Having them on one or two lines is perfectly acceptable, but they mean completely different things. One gives you the behavior you expect, and one does not.

"Computers are dumb, they only do what you tell them." - Jeff Goldblum, The Fly

Posted: Fri Oct 07, 2011 5:28 am
by Tdarcos
pinback wrote:
Tdarcos wrote:This is a big problem
I'm glad you agree. Pay up!

I looked at page 48 of the manual. It has two different entries.

Code: Select all

class box
{
    noun "box"
    long_desc
          "It looks like a regular old box."
    is openable, not open
}
Meaning that it has no problem understanding that "box" is the string value for the property noun but that to set the property long_desc it has to be on a separate line, which puts it into an implied block.

So the system is not consistent because some properties can be set to a string value on the same line, and some properties can only be set through an implicit block. That's a bug in the specifications as they aren't consistent. Consider this for a moment: how do you know which properties can be set with a value on the same line and which properties have to have their value go on the next line? I'll stick my neck out and predict that if the value for noun was on the next line, the compiler would throw a flag and not understand it.

It's also a bug for another important reason. No other programming language has an implicit block. Everyone else starts a block explicitly and nobody considers white space relevant for this purpose, same line or next line, a single-line statement can be either (except for single-line statement languages like Basic, where every statement has to complete on one line unless you use a continuation).
  • If you have, say, an if (or for) statement in C, the statement following it or on the next line is a single statement to execute for that if statement unless you explicitly indicate it's a block by using { }.
  • Basic uses the THEN construct, if you have an IF statement, if you use THEN after it, it's a one-line IF, completed on the same line unless you use a continuation to carry it to the next line. If you do not use THEN, this is an if block, the first statement of the block is the next line and it's ended by an END IF statement.
  • Fortran 77 uses the presence of a statement at the end of an IF statement, if the IF statement is followed by an executable instruction, it's a one-line IF, otherwise it's a block IF, and the block ends with an ENDIF statement.
  • Pascal is similar to C, only they use BEGIN and END in place of { and }

Posted: Fri Oct 07, 2011 6:11 am
by Flack
Tdarcos wrote:You didn't even read what I wrote, did you? (This is a big problem with a lot of people.)
Image
Tdarcos wrote:You have no idea what my capacity or capability is and you are not qualified to judge what I can or cannot do.
Image

(That second one is really funny. Pinback me up here.)

Posted: Fri Oct 07, 2011 9:36 am
by Ice Cream Jonsey
You didn't even read what I wrote, did you?
Oh, we read it alright. You make not like the conclusions, but we read it.
Expressing the text on two lines works perfectly (without the use of the backslash) but expressing the text on one line fails without error. This is the exact opposite of what you are referring to.
Paul. PAUL. The compiler, engine and language will let you do a w_to "Some_Object". If you don't have that object defined, that's on you. You could rename "Blah" to "Some_Object" later and it would be fine. I mean, why on earth you want to send your player character into a string I have no idea, but that's not something the compiler should or will stop you from doing.
I am pointing out where a construct causes the run-time library to fail without detecting the error. If the construct is valid the application should not fail; if the construct is invalid the compiler should flag it as erroneous.
You are going to find yourself very frustrated in life if you believe that all languages are buggy if they don't catch real-time exceptions.

Commander, the reason why I said it's going to be you and not the language is because that is how it is EVERY SINGLE TIME a programmer learns a new language.

Where this will all go next is that you'll find something the language doesn't have and call it a bug.
That's got to be the weakest and most stupidly presented example of a strawman argument I've ever seen.
OK, but for the record, when you thought that Hugo couldn't print numbers that were strings, you called it a bug. What if Hugo simply didn't have the ability to print numbers? You would have called it a bug. That's the only reason I said that. If that's not accurate, consider it..... redacted!!!



It is neither an error nor a bug in Fortran, Basic or Java to fail to have pointers. It is neither an error nor a bug in

I understand your analogy except that no Basic written in about the last 20 years has required line numbers. I have FreeBasic installed
So when I say, "BASIC has line numbers" and you say, "FreeBasic doesn't require line numbers" ... I'm not so sure I said something incorrect there.

But this is exactly the behavior Hugo permits in the source, then implements in the executable. If specifying a string to display as the value for a direction property requires it be on the next line, it should raise a flag and throw an error if it is not done that way. If it does accept it, it should not create an executable that basically locks up.
Hugo doesn't care that much about types, like Ruby, so the same thing that lets you go from chars to ints to MY MOTHER easily is going to let you specify a string (in that case) as a valid object to move player characters into.

All I am saying is the Hugo compiler either misidentifies a construct that is not valid as if it is, and then creates a game that crashes/locks up the run-time library, or the compiler is failing to note an error that violates the rules. Either case represents a bug in the compiler and/or run-time system.
Yeah, but programmers can do all sorts of wild and crazy things to lock up their applications, that gets by the compiler. In this case, the Hugo engine is trusting the programmer that he or she has a reason for doing that. That's all.
Don't presume you know what my capabilities are.
I presume... nothing!!!!

I've found other bugs other places. I found a calculation error in the use of disk space in the DOS version of Free Pascal where it misunderstood free space exceeding 4 GB as negative free disk space. I took a look at the sources to the installer and run-time library, and in two hours I was able to make a bug report giving the exact line where the error was and what the correction needed to be.
I do not deny this! This is why I wanted you to test CZK. The next big game I write I will approach you again and I'll see if we can make this work.... financially. (And I'll give you a walkthrough to consult so you can find bugs and move on.)

I had one case, a college student was having a problem with his Pascal program and he'd been trying for four hours to find the error, so he came to me and asked for help. I did a simple strategy. I commented out his program at the half-way point where it would be syntactically correct and recompiled. No error. I tried it at 3/4 and I get an error. I kept splitting his program, and after about three or four minutes I found the problem: he'd failed to close a { comment block, so the next open comment that was closed started the next piece of code, causing a syntax error. I found and fixed an error in a program of about 2,000 lines that I'd never seen before in less than 5 minutes after the author spent four hours.
In his defense, it was Pascal.
You have no idea what my capacity or capability is and you are not qualified to judge what I can or cannot do.
Who's judging? This is a judging-free zone. A judge-free zone, Commander!

Posted: Fri Oct 07, 2011 9:39 am
by Ice Cream Jonsey
Tdarcos wrote:It's also a bug for another important reason. No other programming language has an implicit block.
Well, you see, the thing i---
That's got to be the weakest and most stupidly presented example of a strawman argument I've ever seen. It is neither an error nor a bug in Fortran, Basic or Java to fail to have pointers. It is neither an error nor a bug in Cobol to fail to have functions. It is not an error in C to fail to have virtual functions. None of these features are part of the language and failing to have them is not a bug nor is it an error.
None of these features are part of the language and failing to have them is not a bug nor is it an error.
[quote]None of these features are part of the language and failing to have them is not a bug nor is it an error.[/quote]

JESUS CHRIST MAN

So when I wrote
ICJ wrote:Where this will all go next is that you'll find something the language doesn't have and call it a bug.
I guess I just own a fucking time machine.

Posted: Fri Oct 07, 2011 9:50 am
by pinback
Flack wrote:
Tdarcos wrote:You have no idea what my capacity or capability is and you are not qualified to judge what I can or cannot do.
Image

(That second one is really funny. Pinback me up here.)
It was, in fact, the first thing I thought of when I read that line.

Posted: Fri Oct 07, 2011 9:57 am
by pinback
Why did you want to put the player inside a string, TDR?

Why?

Posted: Fri Oct 07, 2011 11:05 am
by Flack
Hugo's got more bugs than Joe's Apartment!

[youtube][/youtube]

ICJ = PWNED

Posted: Fri Oct 07, 2011 2:36 pm
by AArdvark
Random thoughts related to this thread.

Perhaps trying an example of illogic will make his brains explode like those Mudd's Women androids I seen on Star Trek.

Whose the Aussie guy? I never saw him before.

Will Dr. Tacos Iscariot never get his thirty pieces of silver pork-butt dinners?



THE
AFTER SUPPER
AARDVARK

Posted: Fri Oct 07, 2011 6:56 pm
by Tdarcos
Ice Cream Jonsey wrote:
You didn't even read what I wrote, did you?
Oh, we read it alright.
No, clearly you did not.
Ice Cream Jonsey wrote:You make not like the conclusions, but we read it.
I was talking about a function of the program generating the wrong results by putting a property value on the same line as the property declaration. You were talking about the requirement to split a line by using a \ at the end. That's entirely different and has absolutely no relevance to the question I posted, so clearly you did not read what I wrote and proceeded to say whatever you wanted, the fact it had absolutely zero relevance to the question I posted notwithstanding.
Ice Cream Jonsey wrote:
Expressing the text on two lines works perfectly (without the use of the backslash) but expressing the text on one line fails without error. This is the exact opposite of what you are referring to.
Paul. PAUL. The compiler, engine and language will let you do a w_to "Some_Object". If you don't have that object defined, that's on you.
In a language requiring declaration of items in order to use them, failure to declare is an error of the program writer, and is an obvious bug which the compiler should catch. Since use of an uninitialized object or nonexistent object would cause serious errors this is a bug in the compiler for not catching it.

And actually, you're wrong:

Code: Select all

room W_Past_warehouse "Approaching East of Warehouse area"
{
   
    
   S_to Noplace
   E_to W_of_warehouse
   W_to
      "Not available"
   
   long_desc
      "The path running east leads toward a warehouse."

    
}
The Hugo compiler will throw a flag if "Noplace" is not defined. It will not allow you to reference a nonexistent object.
Ice Cream Jonsey wrote: You could rename "Blah" to "Some_Object" later and it would be fine.
Use of uninitialized or undeclared objects is not a valid purpose and serves no purpose (there is no way to use this as a feature that would allow the program to work), and for the compiler to fail to notice this is an error. There is no conceivable legitimate reason to reference a non-existent object and doing so is an error that even the simplest compiler should catch.

I've seen some applications - Firefox might be one, but Netscape Navigator definitely is one - that when the program referenced a pure virtual function (the template) of a class, instead of an overriding function to handle the particular action needed, the runtime library terminated the application. This is an example where the system protects the programmer from himself by catching obvious and glaring errors.
Ice Cream Jonsey wrote:I mean, why on earth you want to send your player character into a string I have no idea, but that's not something the compiler should or will stop you from doing.
Wrong. A compiler should catch errors that are obvious. A string is not an object, does not work as an object, and can't be used as one, so using one where an object should be present is an error the compiler should catch.
Ice Cream Jonsey wrote:
I am pointing out where a construct causes the run-time library to fail without detecting the error. If the construct is valid the application should not fail; if the construct is invalid the compiler should flag it as erroneous.
You are going to find yourself very frustrated in life if you believe that all languages are buggy if they don't catch real-time exceptions.

I'm not frustrated, I simply know when something is a real compiler or when it's a toy not worthy of serious consideration. And I doubt that you would use a weak toy to design a serious piece of fiction like CryptoZookeeper or the other ones you've used Hugo for. If it was as bad as this implies, people would have discarded Hugo as being worthless and would not have used it.

Error trapping of the obvious is trivial, it improves the code generated because really bad constructs don't go through, and because it makes the writer more careful because a bad construct won't be tolerated.

Older C compilers won't catch this type of error, but good ones will generally throw a flag (which can be overridden by a compiler argument if you need it) if you use the construct

Code: Select all

if ( a=4 ) { 
instead of

Code: Select all

if (a==4) {
in fact, good coders will do their comparisons backward such as

Code: Select all

if  (4==a) {
in case they forget to use == and use = by mistake so the compiler will catch the attempt to assign something to a constant.
Ice Cream Jonsey wrote:Commander, the reason why I said it's going to be you and not the language is because that is how it is EVERY SINGLE TIME a programmer learns a new language.

Where this will all go next is that you'll find something the language doesn't have and call it a bug.
That's got to be the weakest and most stupidly presented example of a strawman argument I've ever seen.
OK, but for the record, when you thought that Hugo couldn't print numbers that were strings, you called it a bug.
Because I knew that it could do so because the status line does so.
Ice Cream Jonsey wrote: What if Hugo simply didn't have the ability to print numbers? You would have called it a bug. That's the only reason I said that. If that's not accurate, consider it..... redacted!!!
Okay, it wouldn't have been a bug. It would have been a design failure so bad and a class of flawed application so horrendous as to make the program a toy not worth considering.

Even the smallest Basic interpreters written in 4K thirty years ago could print numbers. An application development system - a compiler, an interpreter, a spreadsheet - which is designed to allow user applications to make the development system perform actions, and has no capacity to print numbers is not merely defective, it is out and out a toy of absolutely no value and worse than useless.
Ice Cream Jonsey wrote:
It is neither an error nor a bug in Fortran, Basic or Java to fail to have pointers.... I understand your analogy except that no Basic written in about the last 20 years has required line numbers. I have FreeBasic installed
So when I say, "BASIC has line numbers" and you say, "FreeBasic doesn't require line numbers" ... I'm not so sure I said something incorrect there.
I used FreeBasic as an example. But find one. I will reiterate my statement: no commercially released Basic interpreter or compiler in the last 20 years has required line numbers, and where labels are required for branching, the labels can be words. And there is no serious open-source basic that has been released in the last 20 years that required line numbers to be used. Visual Basic, the Basic that is used in Excel or Word, the basic now used in OpenOffice.Org, none of these require line numbers.

But go ahead, prove me wrong, find any serious Basic which has been recently released - meaning one created since 1991 that has a regular following beyond the author and that those who follow the system are using it to create programs they actually use - that requires line numbers on each line and I'll apologize.
Ice Cream Jonsey wrote:Yeah, but programmers can do all sorts of wild and crazy things to lock up their applications, that gets by the compiler. In this case, the Hugo engine is trusting the programmer that he or she has a reason for doing that. That's all.
Ronald Reagan gave one of the greatest statments ever, "Trust, but verify." People make mistakes all of the time; the more things the compiler presumes the programmer can do wrong and catches, the better the code is.

One of the most powerful features of programming languages, that has seriously increased programmer efficiency, is the automation of memory management and garbage collection. This, more than anything else is why so many people moved to Java over C++ because Java does GC and memory management automatically. C++ programmers still have to do their own memory management and garbage collection, and they have commensurately higher error rates.
Ice Cream Jonsey wrote:
I have been programming for decades; that gives me an advantage in that I might push the envelope more than someone else.
I do not deny this! This is why I wanted you to test CZK.
I'll admit I wish I could have done better on it, the thing is that one of the things that bores me too easily are difficult problems I can't reasonably solve, and the second are games that kill me off fairly quickly (or, as related to the above, that I can't figure out how to keep from being killed in a hurry.)
Ice Cream Jonsey wrote:The next big game I write I will approach you again and I'll see if we can make this work.... financially. (And I'll give you a walkthrough to consult so you can find bugs and move on.)
Well, that's nice of you. The real problem is I do try to solve a problem and I'll attack it from a number of angles, but after a while I'll get frustrated because sometimes it seems like the problem can't be solved, or that the person who designed it thinks in such an unusual way that I don't see it from their angle and thus can't figure out what they were thinking.
Ice Cream Jonsey wrote:In his defense, it was Pascal.
With the development of Turbo Pascal, and later Delphi, it made Pascal an excellent environment for the development of serious applications. Pascal is a very good learning tool, and with the addition of object orientation it gave it capacities on par with C++ but with less danger of getting oneself in trouble by use of bad constructs. Pascal's usual one-pass requirement, predeclaration of identifiers, and strict typing force better habits in the development of applications and reduce attack vectors.

Since you have to declare an array or a dynamic structure in advance, you allocate it from a memory area, and going outside the memory you allocated causes the program to fault, this makes buffer overflow attacks - very common in C/C++ applications - impossible in ones written in Pascal. Access unallocated or unauthorized memory, and you don't create an execution vector for an attacker, your program crashes instead.
Ice Cream Jonsey wrote: Who's judging? This is a judging-free zone. A judge-free zone, Commander!
I must respectfully disagree, Your Honor.

Posted: Fri Oct 07, 2011 6:59 pm
by Tdarcos
pinback wrote:Why did you want to put the player inside a string, TDR?

Why?
I wasn't. I use it as an example where I had made an error by not moving the text down to the next line. When it's on the same line, the compiler misinterprets it and causes the game to lock up. Moving it to the next line when I did it, fixed the problem. It was a minor error I made, that I was using it to show where the compiler does the wrong thing.

Posted: Fri Oct 07, 2011 7:34 pm
by pinback
This seems hard for you. I will try to make it simple:
Tdarcos wrote:Since use of an uninitialized object or nonexistent object would cause serious errors this is a bug in the compiler for not catching it.
I'm going to skip past this one, since I spend my life debugging "NullPointerException" Java errors, because even if you reference a null object, IT STILL COMPILES, LIKE EVERY OTHER LANGUAGE IN THE UNIVERSE. So let's move on:
And actually, you're wrong:

Code: Select all

room W_Past_warehouse "Approaching East of Warehouse area"
{
   
    
   S_to Noplace
   E_to W_of_warehouse
   W_to
      "Not available"
   
   long_desc
      "The path running east leads toward a warehouse."

    
}
The Hugo compiler will throw a flag if "Noplace" is not defined. It will not allow you to reference a nonexistent object.
See, I can never tell if you're truly believing what you're typing, or you're just trolling or trying to get your $30. Listen closely, cuz this is the most important part:

"Not available" is NOT a nonexistent object. It is a STRING OBJECT. So if you say:

Code: Select all

W_to "my anus"
...and the player types "w", he does not actually enter my anus, he enters a string object. String objects are not generally ready for guests which is why it makes the game act funny, but the fact is, it's perfectly valid code.

Oh, and just to really drive the point home:
A string is not an object
YES PAUL! YES IT IS! IN LIKE EVERY LANGUAGE INVENTED SINCE 1972!!

Posted: Sat Oct 08, 2011 9:33 am
by Tdarcos
pinback wrote:This seems hard for you. I will try to make it simple:
Tdarcos wrote:Since use of an uninitialized object or nonexistent object would cause serious errors this is a bug in the compiler for not catching it.
I'm going to skip past this one, since I spend my life debugging "NullPointerException" Java errors, because even if you reference a null object, IT STILL COMPILES, LIKE EVERY OTHER LANGUAGE IN THE UNIVERSE. So let's move on:
Your comment proves exactly the point I was making. Java will crash with use of an uninitialized pointer (which I didn't know Java supported, it was my understanding Java didn't allow direct access to pointers). Hugo will allow you to use something other than an object in a construct where only an object makes sense, then blithely continue along, fat, stupid and happy to do so.
pinback wrote:
And actually, you're wrong:

Code: Select all

   S_to Noplace 
The Hugo compiler will throw a flag if "Noplace" is not defined. It will not allow you to reference a nonexistent object.
See, I can never tell if you're truly believing what you're typing, or you're just trolling or trying to get your $30.
I've already realized there is a fundamental disagreement here and you're not going to pay me.

"But where the fuck is the $5 you already promised me, asshole?" :)

I'm discussing this issue because I want to hear your (and others) remarks. I might not convince you of anything, but we can discuss this issue and perhaps we can all learn something. I know I have.
pinback wrote:Listen closely, cuz this is the most important part:

"Not available" is NOT a nonexistent object. It is a STRING OBJECT.
No sir, it is not. It is a string, not a string object. An object has characteristics which are subject to change. You can have an empty object but if the object has any value, property or routine (called a method in Object Pascal and C), the element must have a name. And that's the difference and why a string is not an object, because an object has (or can have) named components. If it has any components, it has attributes, or properties, or routines. These all have names, and the values of attributes and properties can be accessed (and changed) by name.

The string is a constant, not an object.
pinback wrote:So if you say:

Code: Select all

W_to "my anus"
...and the player types "w", he does not actually enter my anus,
I would hope he doesn't! If you're that friendly to some random guy you hardly even know, I gotta wonder what your girlfriend thinks!
pinback wrote:he enters a string object. String objects are not generally ready for guests which is why it makes the game act funny, but the fact is, it's perfectly valid code.
Well, it's not an object (for the reasons I stated above) and whether it's valid code is debatable.

I now understand why, in Hugo that "noun" has no problem with a string constant being specified immediately after it, but other objects have to move down one line. Noun is a bulit-in property that the compiler supports directly so it knows that the string following it is just a string and doesn't pretend it's an object. The other properties are set up by the user's program (or in this case, the libraries supplied with the system), and since they are not standard properties they are subject to different rules.
pinback wrote:Oh, and just to really drive the point home:
You speak about someone being able to "enter my anus" and now you want to "drive the point home." Do you have unresolved homosexual tendencies you might need to address?
pinback wrote:
A string is not an object
YES PAUL! YES IT IS! IN LIKE EVERY LANGUAGE INVENTED SINCE 1972!!
For the reasons I have exhaustively stated above, a string is not an object, it is a constant. It is immutable (you can't change a constant), has no parameters, values, properties or methods/routines. And you cannot add or assign a value, property or method to a constant. It has no name either.

Now, if you have a named string, you simply have a named constant. It's still a constant, not an object, and there is a difference.

If I code in some language the construct

Code: Select all

Constant A = 4;
I can't assign any other value to A (there are exceptions; Turbo Pascal allowed "const" to be used to assign an initial value to a variable but the variable was not protected from change), add a property, or anything else to it. It is immutable, cannot be altered to add or remove elements, and cannot be descended from (the way one can create a new object that descends from an ancestor object).

Posted: Sat Oct 08, 2011 9:55 am
by pinback
Tdarcos wrote:
pinback wrote:Listen closely, cuz this is the most important part:

"Not available" is NOT a nonexistent object. It is a STRING OBJECT.
No sir, it is not. It is a string, not a string object.
Wrong. The quicker you understand that you are wrong, the quicker you will understand the language.
The string is a constant, not an object.
Wrong. The quicker you understand that you are wrong, the quicker you will understand the language.
Well, it's not an object (for the reasons I stated above)
Wrong. The quicker you understand that you are wrong, the quicker you will understand the language.
For the reasons I have exhaustively stated above, a string is not an object, it is a constant.
Wrong. The quicker you understand that you are wrong, the quicker you will understand the language.



CAVEAT: If Hugo actually does not treat strings as objects, then I will just say that "my anus" is, at the very least, a string POINTER, just as object names are object POINTERS, so passing it to the "w_to" routine is just as valid as passing it a room object. It just doesn't make any sense. But the compiler's job is not to tell you that what you're doing doesn't make sense, just whether it's valid or not. Which it is. NO BUG. NO POR-- CHICKEN

Posted: Sun Oct 09, 2011 10:12 am
by pinback
I won this one, right? Guys?

Posted: Sun Oct 09, 2011 11:32 am
by Tdarcos
pinback wrote:
Tdarcos wrote:
pinback wrote:Listen closely, cuz this is the most important part:

"Not available" is NOT a nonexistent object. It is a STRING OBJECT.
No sir, it is not. It is a string, not a string object.
Wrong. The quicker you understand that you are wrong, the quicker you will understand the language.
Okay, fine. Show me how you change the value of the string object to something else. The one characteristic that makes something an object (as opposed to a constant) is that the object can be changed.

Show me how to set a property of that string. Or an attribute. Either is fine. Because you can do that with objects. You can't do it with anything that is not an object.

So, if you can initialize, read or change a property of this string, then it is a string object; show me and I'll apologize and admit you were right, and I was wrong. But if you cannot read or change the value, it's a string constant, not an object.

See if

Code: Select all

 print "hello".name
(or)
 "hello" is static
are acceptable. You can do this with an object in Hugo, print its name property or set the static attribute. Something like this:

Code: Select all

room27 room "Somewhere"
{

  is static
  long_desc
  {
    self.name ="A"
    "Hello there" 
}
If you can't do that with "hello" then quoted strings are not objects, they are constants.

Posted: Sun Oct 09, 2011 12:45 pm
by Flack
pinback wrote:I won this one, right? Guys?
It's like punching quicksand. Can you ever really win?

Posted: Sun Oct 09, 2011 1:59 pm
by AArdvark
What does Tdarcos give you for winning? I never heard that end of the deal.




THE
ONE WAY
AARDVARK

Posted: Sun Oct 09, 2011 3:35 pm
by pinback
AArdvark wrote:What does Tdarcos give you for winning? I never heard that end of the deal.




THE
ONE WAY
AARDVARK
I get nothing but the satisfaction of a job well done.

I feel like I've done a well job.

Posted: Sun Oct 09, 2011 4:37 pm
by AArdvark
Wait a sec, here. If Dr. Tacos wins he get thirty pork butt dinners buy if you win you get nothing. Where's the fair in that? He should at least make a video of your choice if you win, man.



THE
ARBITER
AARDVARK


(not affiliated with the protoss race)