Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - RickJ

#1741
Thanks Strazer, found the explanation.  I guess I just got over-excited.   One remaining question;  is it possible to have static member data and protected member functions?  I'll try some experiments to find out....  :=

CJ, Thanks for the AGS 2.7 Christmas present. 

...  Merry Christmas All ...
#1742
mouse.x, mouse.y
Maybe these should be properties instead of global vars even though it's subtle distinction?

*** Edit ***

Quote

* Added support for static member functions.
* Added support for protected member variables/functions.
How to use these?  Is it documented yet? 


#1743
Quote
Not sure if I understand the question, but if I do, it's selecting a verb in the listbox that triggers the whole works. And the thing that triggers calling the interactions in the editor is the RunHotpotInteraction (or character[].RunInteraction, or whatever) inside the function DoStuff(), called by clicking on the listbox.
Ok, I understand what you're doing now and I think it's pretty clever.  I think you will need a brief explanation of this in the release.   What do you do then if there are more actions than modes or if they are non-standarrd?   

This also explains why my suggestion about the CallRoomScript() didn't make sense to you.  You had already accomplished what I was talking about using this method. 
#1744
Quote
Oh, at the mo I'm not working on it. I'm taking advantage of the break proportioned by the little problem with restart/restore in the latest beta to organize my real life, and am treating this thread as a to-do list which I'll pick up on as soon as the next beta/final is released.
Ok.  As long as youtake my comments as "food for thought" rather than "commandments".   :)

[quoe]
I handle menu clicks in interface_click, yes... what happens in, when the player chooses a verb, the interface_click function calls up the DoStuff() function. That one basically parses the verb the player has chosen (said verb being a string previously defined by getting the name of the listbox item) and runs the MODE_USE interaction for the object/character/hotspot/inventory selected, where a "Said" command is waiting for the parsed verb.
Quote
So then you're saying that the interaction editor can then be used to pickup the
"Said" command and implement the action? 

Quote
I did it like this so as to minimize scripting for the user, as odd as that may sound when considering some things in that template Wink ; the user would only have to open the correct interaction mode (USE) in the interaction editor and add whatever interactions he wanted with several "Said" commands.
If I understand correctly, this accomplishes what I was suggestingwith the CallRoomScript() thingy but with the interactiion editor instead of the room script. If this is so it's quite clever and something I would never have thought of. 

So do you do a ParseText(menuu_text); in the global script  and then do a series of "if (Said("...")) { }s" inthe room script or interaction editor?  Clever!  What triggers the event then?
#1745
Quote
I'm still a bit lost as to your suggestion regarding the room script, sorry...
That's probably because I need to understand/study what you've done a bit more.   Where are you handling the menu click?  I assumed it was in interface_click() in the global script.  I'll keep looking and try to re-explain myself ;)

Quote
And in repeatedly_execute_always I have... well, lots of stuff. A counter for the score, some code to make sure the menu pops up correctly, some code to highlight the cursor when over SOME GUI buttons (not all)... heh. Lots of stuff.
Ok.  That's probably the only sensible way of over-riding the cursor's default behaviour and appearance.  I'm not sure about the other stuff you mention but I will keep looking. 

I you like, I can take a look at whatever progress you are making.  Just let me know when and where I can get an update.

Keep up the good work.



#1746
First of all no one has bothered to define what is meant by multiculturism.  Multiculturalism is not new, it's been around for a long time.  In the US it's been there since the beginning.   What's new is the leftist version, currently in fashion in the US, that is based on some flawed presumptions and I assume that is what we are talking about here.

  • All cultures are exactly equal and cannot be judged by any measure

  • Diversity is a good unto itself and needs no explanation or justification

  • Practice tolerance of all things.

    All cultures are exactly equal
    While it's true that one's own culture influences one's opinion about other cultures,  making objective assements difficult, it is not impossible to make such assements.   For example, one could ask how well does this culture provide for it's members vs another culture.  Which has growing dynamic and growing ecnomonies?  How well or poorly are the sick, young, old, and weak treated?  How are women treated?   How many freedoms are restricted and to what extent.  What is the average life-span,  mortality rates,  frequency and severity of disease, etc.  I could go on and on but I think you get the idea.  One final test I personally use;  I sometimes look at things to judge people actions form other cultures is to use

    Diversity is a good unto itself...
    Why?  Diversity of what?  It certainly is not diversity of opinion, thought, or ideas is it? Anarcho, in his very first post labeled anyone who disagrees with him a cave dweller.  IMHO, diversity, as practiced in the US, is a means by which universities and govermental entities, etc avoid the embarassment of having to admit to their racialy discriminatory policies.

    Practice tolerance of all things...
    Except dissent!  Dissenters and the politically incorrect are not to be tolerated.  Their areguments are not to be listened to nor challenged in a logical manner.  Call them cave dwellers, bigots, idoits, etc.  Attack them personally so as to discredit their ideas. etc...

    Bottom Line
    I think when you visit someone's home you should follow the rules and customs of that person's home.  The same goes when you visit someone's country.   If you don't like the way it is there then just don't go.     


#1747
Quote
... I see your point. It would be much more readable, yes. I'll do it.
It also makes it easier for other people to use your template.  Consider doing the same for the other system event handlers such as interface_click() etc.   

Quote
.. So for instance what's now add_inv should become AddInv? It was on purpose, so people wouldn't mistake it with the already existing function...
To avoid confusion with already existing functions I used a lowercase prefix.  So in the BlueGui it would have been bgAddInv().   Using the new OO stuff this would likely be Bg.AddInv().  So in your case you would have something like l7AddInv() or L7.AddInv().

Quote
...I thought  though it would be easier if I dumped it all in the room script and had it done with - this way the user would only have to mess with the room script.
That's why I asked about CallRoomScript().  I was thinking that interface_click() could just do a CallRoomScript() and pass the item number that was clicked in the action menu.  Then in the room script you would have the following to fill out however one desired.
Code: ags

function on_call(int verb) {
  // called when verb is selected from menu
   if (verb==0) {
   }
   else if (verb==1) {
   } 
   else if (verb==2) {
   }
   else if (verb==3) {
   }
   else if (verb==4) {
   }
   else if (verb==5) {
   }
   else if (verb==6) {
   }
   else if (verb==7) {
   }
   :
   :
   else if (verb==nn) {
   } 
}


I was also wondering about what you are doing in repeatedly_execute_always()?  I haven't yet spent a lot of time on it but in the little time have,  I didn't get  a feel for what was going on there.   Whenever I use  any of the repeatedlys I scrutinize what I am doing.
#1748
Here are a couple of other ideas to make your script more readable.

game_start(), releatedly_execute(), releatedly_execute_always()
I usually don't like to put much code into these system functions.   Instead I all the code into other functions and then call them from these system functions.  In your case I would probably make:
  • l7_start()
  • l7_execute()
  • l7_execute_always().

    Of course you could break thins down further is you wish (i.e. l7_something_start(), l7_anotherthing_start(), etc).

    Global vs Local
    I always like to name things so that I know what is local and what is global.   The way I choose to do it is to use mixed case for global functions and variables and to use all lowercase for local functions and variables.  For example the NoMatch() function above would become l7NoMatch() if were global and l7_no_match() if it were local.  There are of course many other ways of doing this. 

    CallRoomScript()
    Are you famillar with this and have you considered using it to implement actions?  The reason I ask is that this would allow all of the action code for a specific room to be included in that room's script.  This makes things scalable (i.e. No matter how many rooms are added the complexity and size of the global script doesn't increase).  I haven't absorbed your code enough to make a more specific  recommendation.







#1749
Quote
... if "turn key" actually DID something other than just display a message, the relevant code would be places here, right?
I think you would you put the code for "Turn key" in the same place you do now.  Why would it be placed in NoMatch()?  If I understand correctly the code that does the actions would call NoMatch() nothing was defined for the action, isn't this correct?
#1750
Ok, well I think you could do everythig in your NoMatch() function.  I have taken the liberty of dressing it up a bit and modifying the "TURN" verb as I suggested above.   I think you can see how to do this for the rest of the verbs.   

Code: ags

//===================================================================
function NoMatch() {
//
// This function is called if no other actions are defined for the 
// selected item. It displays a message defined for the selected item 
// and verb in the custom properties. If that message is an empty 
// string then a default message is displayed.
//===================================================================
   string name, msg;
   int    type;
  
   // Get the name of the location 
   GetLocationName(mouse.x, mouse.y, name);
   StrToLowerCase(name);

   // Get the type of the location 
   if (GetInvAt(mouse.x, mouse.y)!=-1) type = 4    // Inventory
   else type = GetLocationType(mouse.x, mouse.y);
  
 
   // Swim
   if (Said("swim")) Display("You'd look silly swimming on the %s, don't you think?", temploc);
 
   // Look
   if (Said("look")) Display("What you see is what you get.");
 
   // Examine
   if (Said("examine")) Display("Further examination of the %s reveals nothing new.", temploc);
 
   // Drink
   if (Said("drink")) Display("The %s is not intended for comsumption.", temploc);
 
   // Eat
   if (Said("eat")) Display("The %s is not intended for comsumption.", temploc);
 
   // Open
   if (Said("open")) Display("The %s doesn't seem to open.", temploc);
 
   // Close
   if (Said("close")) Display("The %s doesn't seem to close.", temploc);  
 
   // Read
   if (Said("read")) Display("There's nothing to read on the %s.", temploc);  
 
   // Rip
   if (Said("rip")) Display("Try as you might, you can't rip the %s.", temploc);  
 
   // Smell
   if (Said("smell")) Display("The %s has a farily non-descript smell.", temploc);  
 
   // Press
   if (Said("press")) Display("You press the %s, but nothing seems to happen.", temploc);  
 
   // Take
   if (Said("take")) Display("You can't seem to be able to take the %s.", temploc);  
 
   // Talk
   if (Said("talk")) Display("The %s does not respond.", temploc);  

   // Turn
   if (Said("turn")) {
      if (type==1) {                           // Hotspot
         GetHotspotPropertyText(GetHotspotAt(mouse.x, mouse.y), "TurnMsg",  msg):
         if ((StrComp(msg, "")!=0) Display(msg);
         else Display("You'd be hard pressed to turn the %s.", name); 
      }
      else if (type==2) {                      // Character
         GetCharacterPropertyText(GetCharacterAt(mouse.x, mouse.y), "TurnMsg",  msg):
         if ((StrComp(msg, "")!=0) Display(msg);
         else Display("You'd be hard pressed to turn the %s.", name); 
      }
      else if (type==3) {                      // Object
         GetObjectPropertyText(GetObjectAt(mouse.x, mouse.y), "TurnMsg",  msg):
         if ((StrComp(msg, "")!=0) Display(msg);
         else Display("You'd be hard pressed to turn the %s.", name); 
      }
      else if (type==4) {                      // Inventory
         GetInvPropertyText(GetInvAt(mouse.x, mouse.y), "TurnMsg",  msg):
         if ((StrComp(msg, "")!=0) Display(msg);
         else Display("You'd be hard pressed to turn the %s.", name); 
      }
      else {                                   // Unknown
         Display("Hard as you try you get no satisfaction."); 
      }
   }
}


One additional thought, I would add a check to see if the character was the player character or not.  If it was the PC then have a different default message (i.e. use personal pronouns etc instead of character's name).

#1751
Quote
ListBoxGetItemText: invalid item specified

It means that the "item" parameter, in ListBoxGetItemText (int gui, int object, int item, string buffer),  is pointing to something that doesn't exist.  For example if item is equal to 5 and there are only 3 items in the list you will get this error.  Your program will first need to validate the item number using ListBoxGetNumItems (int gui, int object).

Here is an example of how I did it. 
Code: ags

//=========================================================================
// SAVE GAME DIALOG - The following functions implement the Save Game
// interface. The SAVE GAME dialog is normally activated via a user
// click on the ICON BAR. 
//
// bgSave(state)
// This function opens the dialog box and performs the operations initiated
// by controls within the dialog box. 
//
// state - This parameter determines the behavior of dialog as follows:
//    DIALOG  - Open the Save dialog box
//    CANCEL  - Close dialog box without performing any operation
//    OK      - Save the selected game slot
//    LIST    - Get user selection from listbox
//
//=========================================================================
   string  bg_save_buf;                // text buffer
   int     bg_save_idx;                  // index
   int     bg_save_slot;                // save game id

function bgSave(int state) {
   // SAVE icon was pressed, open dialog
   if (state==DIALOG) {                  
      bgCursor(POINTER); 
      GUIOff(bgICON_BAR);
      GUIOn(bgSAVE_DLG); 
      GUIOff(bgDEBUG_DLG);
      ListBoxSaveGameList(bgSAVE_DLG,bgSAVE_LIST); // Populate listbox with previous saves
      bg_save_idx = ListBoxGetNumItems(bgSAVE_DLG,bgSAVE_LIST); 
      if (bg_save_idx <= 20) {           // Less than max saves
         ListBoxAdd(bgSAVE_DLG,bgSAVE_LIST,"<new>");
      }
      else {                             // Max number of saves exceeded
         bg_save_idx = 0;                // Setup overwrite of existing slot
         ListBoxGetItemText(bgSAVE_DLG,bgSAVE_LIST,bg_save_idx,bg_save_buf);
      }
      ListBoxSetSelected(bgSAVE_DLG,bgSAVE_LIST,bg_save_idx);
      ListBoxGetItemText(bgSAVE_DLG,bgSAVE_LIST,bg_save_idx,bg_save_buf);
      if (StrComp(bg_save_buf,"<new>")==0) StrCopy(bg_save_buf,"");
      SetTextBoxText(bgSAVE_DLG,bgSAVE_TEXT,bg_save_buf); // Setup text entry box
   }

   // List element was clicked, copy selected item's text to the TextBox
   else if (state==LIST) { 
      bg_save_idx = ListBoxGetSelected(bgSAVE_DLG,bgSAVE_LIST);
      ListBoxGetItemText(bgSAVE_DLG,bgSAVE_LIST,bg_save_idx,bg_save_buf);
      if (StrComp(bg_save_buf,"<new>")==0) StrCopy(bg_save_buf,"");
      SetTextBoxText(bgSAVE_DLG,bgSAVE_TEXT,bg_save_buf);
   }

   // SAVE button was pressed, save the game
   else if (state==OK) {
      SetRestartPoint();                 // Restart here
      bg_save_idx=ListBoxGetSelected(bgSAVE_DLG,bgSAVE_LIST); // Save game in new save game slot
      ListBoxGetItemText(bgSAVE_DLG,bgSAVE_LIST,bg_save_idx,bg_save_buf);
      if (StrComp(bg_save_buf,"<new>")==0) {     
         bg_save_slot = ListBoxGetNumItems(bgSAVE_DLG,bgSAVE_LIST);
         GetTextBoxText(bgSAVE_DLG,bgSAVE_TEXT,bg_save_buf);  
         if (StrComp(bg_save_buf,"")==0) StrFormat(bg_save_buf,"Game-%d",bg_save_slot);
      }
      else {                             // Over-write an existing save game
         bg_save_slot=savegameindex[bg_save_idx]; // slot with name from textbox. 
         GetTextBoxText(bgSAVE_DLG,bgSAVE_TEXT,bg_save_buf);  
        if (StrComp(bg_save_buf,"")==0) ListBoxGetItemText(bgSAVE_DLG,bgSAVE_LIST,bg_save_idx,bg_save_buf);
      }
      GUIOff(bgSAVE_DLG);          // Close dialog amd return
      GUIOn(bgICON_BAR);           // to normal interface
      if (bg_debug_flag==1) GUIOn(bgDEBUG_DLG);
      SaveGameSlot(bg_save_slot, bg_save_buf); // Perform save operation last otherwise
      Display("Saved as: %s", bg_save_buf);    // SAVE dialog will be active on restore 
      bgCursor(DEFAULT);                
   }

   // CANCEL button was pressed, cancel operation
   else if (state==CANCEL) {
      GUIOff(bgSAVE_DLG);          // Close dialog and return
      GUIOn(bgICON_BAR);           // to normal interface
      if (bg_debug_flag==1) GUIOn(bgDEBUG_DLG);
      bgCursor(DEFAULT);  
   }
}

//=========================================================================
// RESTORE GAME DIALOG - The following routines implement restore game
// interface. The RESTORE GAME dialog is normally activated via a user
// click on the ICON BAR.  
//
// bgRestore(state)
// This function opens the dialog box and performs the operations initiated
// by controls within the dialog box. 
//
// state - This parameter determines the behavior of dialog as follows:
//    DIALOG  - Open the Restore dialog box
//    CANCEL  - Close dialog box without performin any operation
//    OK      - Restore the selected game slot
//    LIST    - Get user selection from listbox
//
//=========================================================================
   string  bg_restore_buf;             // text buffer
   int       bg_restore_idx;              // index

function bgRestore(int state) {
   // RESTORE icon was pressed, open dialog
   if (state==DIALOG) {
      bgCursor(POINTER);  
      GUIOff(bgICON_BAR);          
      GUIOn(bgRESTORE_DLG);        
      ListBoxSaveGameList(bgRESTORE_DLG,bgRESTORE_LIST);
   }

   // CANCEL button was pressed, cancel operation
   else if (state==CANCEL) {
      GUIOff(bgRESTORE_DLG);       // Close dialog and return
      if (bg_intro_flag==0) GUIOn(bgICON_BAR); // to normal interface
      bgCursor(DEFAULT);
   }

   // RESTORE button was pressed, restore the game
   else if (state==OK) {
      bg_restore_idx=ListBoxGetSelected(bgRESTORE_DLG,bgRESTORE_LIST); // Perform save operation
      if (bg_restore_idx==-1) {          // No selection, nothing to restore
         Display("Please make a slection first...");
      }
      else                               // Ok continue restoring game
      {
         ListBoxGetItemText(bgRESTORE_DLG,bgRESTORE_LIST,bg_restore_idx,bg_restore_buf);
         RestoreGameSlot(savegameindex[bg_restore_idx]);
         Display("Restored from: %s",bg_restore_buf);
         GUIOff(bgRESTORE_DLG); 
         GUIOn(bgICON_BAR);     
         bgCursor(DEFAULT);             
      }
   }

   // LIST box was clicked
   else if (state==LIST) {
      // nothing to do
   }
}

   :
   :

function interface_click(int interface, int object) {
   // Executed when user clicks a GUI object
    
    :
    :
   // SAVE DIALOG 
   else if (interface==bgSAVE_DLG) {      
      if (object==bgSAVE_LIST) bgSave(LIST);    
      else if (object==bgSAVE_TEXT) bgSave(OK);
      else if (object==bgSAVE_OK) bgSave(OK);
      else if (object==bgSAVE_CANCEL) bgSave(CANCEL);   
   }
   // RESTORE DIALOG 
   else if (interface==bgRESTORE_DLG) {      
      if (object==bgRESTORE_LIST) bgRestore(LIST);
      else if (object==bgRESTORE_OK) bgRestore(OK);
      else if (object==bgRESTORE_CANCEL) bgRestore(CANCEL);
   }
   // BROWSE FILES 
   else if (interface==bgBROWSE_FILES) {      
      if (object==bgBROWSE_FILES_CLOSE) bgBrowse(CLOSE,"","");
      else if (object==bgBROWSE_FILES_LIST) bgBrowse(LIST,"","");
   }
   // BROWSE TEXT on transparent background  
   else if (interface==bgBROWSE_TRANS) {      
      bgBrowse(CLOSE,"","");
   }
   else if (interface==bgDEBUG_QUERRY) {      
      if (object==bgDEBUG_TEXT) bg_debug_input();
   }                     
}


I'm sorry if you find the above confusing but there are no short cuts in making a proper GUI.   This code is thorough and as simple as I know how to make it.  There are lots of things to keep track of and lots of things that can go wrong.  That's why we try to disuade people from rolling their own GUI the first time out with AGS.  Cheers.
 
#1752
Quote
but I correctly got a compile error saying the "object" was already defined. Can you elaborate on what sort of code you had that lead it to crash?

The sample game I gave you produces the error.  If you remember, you got the runtime error as well.  If you don't have a copy of the sample it's still up  here: http://www.gaia-spa.com/project/ags/
#1753
For example:

  • For each verb check box in the custom properties schema add a corresponding text entry field.

  • Now edit the properties of an item such as a rock object.

  • Check the "Eat" verb (or "Drink" or whatever). 

  • Now enter the custom message in the text entry field: "You're not man enough to eat that rock, are you?"

  • If an action is defined for this item then the message is ignored as is done now.  If not then the custom property message is displayed instead.  If the message in the custom properties is empty then you can display the default message for that type of item as you do now.
#1754
Custom Properties
Have you considered adding a  text property for each of the verbs.  That way if someone checks a verb for an item they could just enter a text message for it right there. 

So if there isn't any other action defined then the message could be displayed.   If there isn't a custom message defined in the item's properties then you could display default messages according to item type as you are doing now. 

#1755
OK, I got my Firefox working correctly.  I did the following to fix the problem and stay logged on forever using the Firefox browser.

  • Enter the forum forum  from http://www.adventuregamestudio.co.uk/yabb/index.php

  • Delete all cookies

  • Delete all exceptions, which I think may have been the problem.  (i.e. Allow, Block, etc) cookies from speciific sites.

  • Option: Allow sites to set cookies

  • Option: Ask me everytime

  • Repeat above procedure until it works



#1756
You could give BlueGui a try.  Just follow the link im my signature line below or click here: BluSoft.tk.  It is pretty much the classic Sierra interface.   The sprites can simply be replaced with ones of your own design.

There are also quite a few GUI templates by Rui Pires on his website skimbleshanks

#1757
Quote
Quote
I tried your test game but I didn't get a crash. All I got was it ran through the first room and then got an Array Index Out of Bounds error on global script line 1075.
At what point does it crash for you?
It crashes right at startup.  I may even happen before the video mode is switched etc.  I happens both when I do a Test or when I execute the exe directly.   I didn't have any problems with V2.62.   

I guess I'll go check line 1075 and see what's going on there and let you know if I can get it to work.  Maybe I'll just start doing surgery until the problem goes away.  If you can't repoduce the problem then there probably isn't much you can do on your end.   If you have any other ideas or things you would like me to try just let me know.
If you remember the problem I had converting an existing game a couple of betas back... The problem is that I was using "object" as a parameter name in a number of functions I created.   It seemed an appropiate name to use, at the time, for passing a room object's id number.   It's not surprising that object-o-izing (hehe, sorry couldn't resist the 'o' thingy)  process laid claim to "object" as a reserved word but the resulting error message is a bit confusing in that the line number given doesn't seem to exist or be related.  I suppose "object" contains a pointer or something that go used in trying to acces the object[] array.

I guess this is more of a gotcha than a bug for people upgrading existing projects.

P.S.  I accidently disobeyed you and upgarded everything on that project and now have no way back to my V2.62 version.   Everything seems to now work ok under the new beta.   Will I be forgiven and my project see a bright future or shall I be cursed and my project suffer a thousand calamities?   ??? 
#1758
Quote
struct Derived extends Base {
  int b;
}
Does this also work for internal AGS objects (i.e Characters, Objects, GUI, etd) or just ones created in the script?

#1759
Quote
Added simple inheritance support ("extends" keyword).
Can you give a sample usage of reference a descritption in manual.  Thanks.

Quote
All GUI controls now have a "Script name" property, which allows you to give them a VB-style "lstSaveGames" or "btnCancel" type name.
Then, in the script you can do stuff like:
lstSaveGames.AddItem("Jibble");
rather than
ListBoxAdd(3, 6, "Jibble");
all much nicer the new way.
Wouldn't it be something like gMyGui.lstSaveGames.AddItem("Jibble").  If not then how is the particular GUI id resolved?  Also, there is no "Script O-name" display for Gui components in the editor pane.  Is the "lst", "btn", ect prefixes enforced by the editor (as is with gName, oName and cName) or is this just by convention for Gui components? 

Quote
Room objects now have script names, so that you can do:
oDoor.Animate( ... );
and so on, which is much more user friendly than the previous number-based approach.
Cool! Cool! Cool! 
Would it be practical, at some point, to allow mixed case for the object names so that instead of oFrontdoor.Animate(...)  one could have oFrontDoor.Animate(...). 

Character Objects
Don't yet have a Script O-name display in the editor pane as do Object Objects and Gui Objects. 

All I can say is really cool stuff here CJ  8)

#1760
In addition only one key can be pressed at a time so instead of the convuluted logic you have you only need something like

if (IsKeyPressed(69)==1){
}
else if  (IsKeyPressed(70)==1){
}
(IsKeyPressed(71)==1){
}
      :
(IsKeyPressed(72)==1){
}

Also this line has an error in that you said "&" when I think you meant tosay "&&"
Quote
if ((IsKeyPressed(65)==1) && (IsKeyPressed(87)==0) && (IsKeyPressed(83)==0) & (IsKeyPressed(75)==0))
SMF spam blocked by CleanTalk