SHARE
TWEET

Arduino & Freetronics LCD - Hunt the Wumpus

a guest Aug 26th, 2012 224 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* Wumpus Conversion for the Freetronics 16x2 LCD shield
  2. http://www.freetronics.com/pages/16x2-lcd-shield-quickstart-guide#.UBKMm7T9OK9
  3. http://www.atariarchives.org/bcc1/showpage.php?page=247
  4.  
  5. by eturnerx@gmail.com 201208
  6.  
  7. */
  8. /*--------------------------------------------------------------------------------------
  9.   Includes
  10. --------------------------------------------------------------------------------------*/
  11. #include <LiquidCrystal.h>   // include LCD library
  12. /*--------------------------------------------------------------------------------------
  13.   Defines
  14. --------------------------------------------------------------------------------------*/
  15. // Pins in use
  16. #define BUTTON_ADC_PIN           A0  // A0 is the button ADC input
  17. #define LCD_BACKLIGHT_PIN         3  // D3 controls LCD backlight
  18. // ADC readings expected for the 5 buttons on the ADC input
  19. #define RIGHT_10BIT_ADC           0  // right
  20. #define UP_10BIT_ADC            145  // up
  21. #define DOWN_10BIT_ADC          329  // down
  22. #define LEFT_10BIT_ADC          505  // left
  23. #define SELECT_10BIT_ADC        741  // right
  24. #define BUTTONHYSTERESIS         10  // hysteresis for valid button sensing window
  25. //return values for ReadButtons()
  26. #define BUTTON_NONE               0  //
  27. #define BUTTON_RIGHT              1  //
  28. #define BUTTON_UP                 2  //
  29. #define BUTTON_DOWN               3  //
  30. #define BUTTON_LEFT               4  //
  31. #define BUTTON_SELECT             5  //
  32.  
  33. // Define our states
  34. #define STATE_TITLE               00  // A title screen
  35. #define STATE_KEYWAIT             05  // Waiting for a keypress
  36. #define STATE_GO1                 10  // Flavour intro
  37. #define STATE_SENSINGWUMPUS       20  // Situational Awareness: Wumpus
  38. #define STATE_SENSINGBATS         22  // Situational Awareness: Bats
  39. #define STATE_SENSINGPIT          24  // Situational Awareness: Pit
  40. #define STATE_NEWROOM             30  // Just arrived -> print the goodies
  41. #define STATE_HUNTING             31  // Wait for instructions
  42. #define STATE_SHOOT               40  // Setting up the shot
  43. #define STATE_SHOOTREPORT         50  // Doing the shot
  44. #define STATE_BATS                60  // Bat rapid teleport system
  45. #define STATE_PIT                 70  // Oh dear, fell in a pit!
  46. #define STATE_WUMPUSCHOMP         80  // Oh dear, eaten by the wumpus
  47. #define STATE_SUICIDE             85  // Whoops! you shot yourself
  48. #define STATE_GAMEWIN             90  // You won! Yay!
  49. #define STATE_GAMEOVER            98  // Gameover. Option to Shuffle and restart or just restart
  50. #define STATE_GAMEOVERWAIT        99
  51.  
  52. // Misc. Defines
  53. #define MAXSHOTDISTANCE            6  // How far can a shot travel?
  54.  
  55. // A datatype that describes a room
  56. typedef struct {
  57.   byte dir1, dir2, dir3;
  58.   char id;
  59.   byte visited;
  60.   byte known;
  61. } room_t;
  62.  
  63. /*--------------------------------------------------------------------------------------
  64.   Variables
  65. --------------------------------------------------------------------------------------*/
  66. byte buttonJustPressed  = false;         //this will be true after a ReadButtons() call if triggered
  67. byte buttonJustReleased = false;         //this will be true after a ReadButtons() call if triggered
  68. byte buttonWas          = BUTTON_NONE;   //used by ReadButtons() for detection of button events
  69.  
  70. // Setup the variables that will be used
  71. byte state, nextstate;
  72. byte playerroom, wumpusroom, batsroom, pitroom;
  73. byte startplayerroom, startwumpusroom, startbatsroom, startpitroom;
  74. byte shot[MAXSHOTDISTANCE], shots;
  75. room_t caves[20];
  76.  
  77. /*--------------------------------------------------------------------------------------
  78.   Init the LCD library with the LCD pins to be used
  79. --------------------------------------------------------------------------------------*/
  80. LiquidCrystal lcd( 8, 9, 4, 5, 6, 7 );   //Pins for the freetronics 16x2 LCD shield. LCD: ( RS, E, LCD-D4, LCD-D5, LCD-D6, LCD-D7 )
  81.  
  82.  
  83. /*--------------------------------------------------------------------------------------
  84.   setup()
  85.   Called by the Arduino framework once, before the main loop begins
  86. --------------------------------------------------------------------------------------*/
  87. void setup() {
  88.   // Setup pins.
  89.   pinMode(BUTTON_ADC_PIN, INPUT );         // Analogue input for the LCD's buttons
  90.   digitalWrite(BUTTON_ADC_PIN, LOW );
  91.   pinMode(LCD_BACKLIGHT_PIN, OUTPUT );     // Backlight control (off/on)
  92.   digitalWrite(LCD_BACKLIGHT_PIN, HIGH );  // Turn the backlight on
  93.   randomSeed(analogRead(1));               // Send the random number generator
  94.  
  95.   lcd.begin( 16, 2 );                      // Tell LCD library this is 16x2 display
  96.   lcd.setCursor( 0, 0 );
  97.   //          1234567890123456
  98.   lcd.print( "Hunt the Wumpus!" );
  99.   lcd.setCursor( 0, 1 );
  100.   lcd.print( '.' );
  101.   shuffle();
  102.   lcd.print(  '.' );   flashbacklight();
  103.   lcd.print(   '.' );  flashbacklight();
  104.   lcd.print(    '.' ); flashbacklight();
  105.   state = STATE_TITLE;  
  106. }
  107.  
  108.  
  109. /*--------------------------------------------------------------------------------------
  110.   loop()
  111.   Arduino main loop
  112. --------------------------------------------------------------------------------------*/
  113. void loop() {
  114.   byte button;
  115.    
  116.   button = ReadButtons();
  117.   switch(state) {                  //    Do different things depending on "state"
  118.  
  119.  
  120.     case STATE_TITLE:
  121.       lcd.setCursor( 0, 0 );
  122.       //          1234567890123456
  123.       lcd.print( "Hunt the Wumpus!" );
  124.       lcd.setCursor( 0, 1 );
  125.       lcd.print( "Press [any] key" );
  126.       newgame();
  127.       nextstate = STATE_GO1;
  128.       state = STATE_KEYWAIT;
  129.       break;
  130.  
  131.  
  132.     case STATE_KEYWAIT:
  133.       if(buttonJustPressed) state = nextstate;
  134.       break;
  135.  
  136.  
  137.     case STATE_GO1:
  138.       if(wumpusroom == playerroom) {
  139.         state = STATE_WUMPUSCHOMP;
  140.       } else if(batsroom == playerroom) {
  141.         state = STATE_BATS;
  142.       } else if(pitroom == playerroom) {
  143.         state = STATE_PIT;
  144.       } else {
  145.         state = STATE_SENSINGWUMPUS;
  146.       }
  147.       break;
  148.  
  149.  
  150.     case STATE_SENSINGWUMPUS:
  151.       if(wumpusroom == caves[playerroom].dir1 || wumpusroom == caves[playerroom].dir2 || wumpusroom == caves[playerroom].dir3) {
  152.         outputplayerroom();
  153.         //          1234567890123456
  154.         lcd.print( "You smell wumpus" );
  155.         nextstate = STATE_SENSINGBATS;
  156.         state = STATE_KEYWAIT;
  157.         break;
  158.       } else state = STATE_SENSINGBATS; // and fall through...
  159.  
  160.  
  161.     case STATE_SENSINGBATS:
  162.       if(batsroom == caves[playerroom].dir1 || batsroom == caves[playerroom].dir2 || batsroom == caves[playerroom].dir3) {
  163.         outputplayerroom();
  164.         //          1234567890123456
  165.         lcd.print( "You hear wings" );
  166.         nextstate = STATE_SENSINGPIT;
  167.         state = STATE_KEYWAIT;
  168.         break;
  169.       } else state = STATE_SENSINGPIT; // and fall through...
  170.  
  171.  
  172.     case STATE_SENSINGPIT:
  173.       if(pitroom == caves[playerroom].dir1 || pitroom == caves[playerroom].dir2 || pitroom == caves[playerroom].dir3) {
  174.         outputplayerroom();
  175.         //          1234567890123456
  176.         lcd.print( "You feel breeze" );
  177.         nextstate = STATE_NEWROOM;
  178.         state = STATE_KEYWAIT;
  179.         break;
  180.       } else state = STATE_NEWROOM; // and fall through...
  181.  
  182.  
  183.     case STATE_NEWROOM:
  184.       caves[playerroom].visited = true;
  185.       caves[caves[playerroom].dir1].known = true;
  186.       caves[caves[playerroom].dir2].known = true;
  187.       caves[caves[playerroom].dir3].known = true;
  188.       outputplayerroom();
  189.       //         1234567890123456
  190.       lcd.print("  <");
  191.       lcd.print(    caves[caves[playerroom].dir1].id);
  192.       lcd.print(     "  ^");
  193.       lcd.print(         caves[caves[playerroom].dir2].id);
  194.       lcd.print(         "  ");
  195.       lcd.print(            caves[caves[playerroom].dir3].id);
  196.       lcd.print(             ">  *");
  197.       state = STATE_HUNTING;
  198.       break;
  199.  
  200.  
  201.     case STATE_HUNTING:
  202.       if(buttonJustPressed) {
  203.         switch(button) {
  204.           case BUTTON_LEFT:
  205.             playerroom = caves[playerroom].dir1;
  206.             state = STATE_GO1;
  207.             break;
  208.           case BUTTON_UP:
  209.             playerroom = caves[playerroom].dir2;
  210.             state = STATE_GO1;
  211.             break;
  212.           case BUTTON_RIGHT:
  213.             playerroom = caves[playerroom].dir3;
  214.             state = STATE_GO1;
  215.             break;
  216.           case BUTTON_SELECT:
  217.             for(int i = 1; i < MAXSHOTDISTANCE; i++) shot[i] = 255;
  218.             shots = 0;
  219.             shot[0] = playerroom;
  220.             outputshotui();
  221.             state = STATE_SHOOT;
  222.             break;
  223.           default:
  224.             flashbacklight();
  225.             break;
  226.         }
  227.       }
  228.       break;
  229.  
  230.  
  231.     case STATE_SHOOT:
  232.       if(buttonJustPressed) {
  233.         room_t r = caves[shot[shots]];
  234.         switch(button) {
  235.           case BUTTON_LEFT:
  236.             if(shots < MAXSHOTDISTANCE && r.visited && caves[r.dir1].known) {
  237.               shots++;
  238.               shot[shots] = r.dir1;
  239.               outputshotui();
  240.             } else flashbacklight();
  241.             break;
  242.           case BUTTON_UP:
  243.             if(shots < MAXSHOTDISTANCE && r.visited && caves[r.dir2].known) {
  244.               shots++;
  245.               shot[shots] = r.dir2;
  246.               outputshotui();
  247.           } else flashbacklight();
  248.             break;
  249.           case BUTTON_RIGHT:
  250.             if(shots < MAXSHOTDISTANCE && r.visited && caves[r.dir3].known) {
  251.               shots++;
  252.               shot[shots] = r.dir3;
  253.               outputshotui();
  254.             } else flashbacklight();
  255.             break;
  256.           case BUTTON_SELECT:
  257.             state = STATE_SHOOTREPORT;
  258.             break;
  259.           default:
  260.             flashbacklight();
  261.             break;
  262.         }
  263.       }
  264.       break;
  265.  
  266.  
  267.     case STATE_SHOOTREPORT:
  268.       lcd.clear();
  269.       lcd.setCursor(0,0);
  270.       //         1234567890123456
  271.       lcd.print("--Arrow Report--");
  272.       lcd.setCursor(0,1);
  273.       lcd.print(">>--> ");
  274.       nextstate = STATE_GO1;
  275.       state = STATE_KEYWAIT;
  276.       for(int i = 1; i <= shots; i++) {
  277.         room_t r = caves[shot[i]];
  278.         lcd.print(r.id);
  279.         if(shot[i] == playerroom) {
  280.           lcd.print(" HIT");
  281.           nextstate = STATE_SUICIDE;
  282.           state = STATE_KEYWAIT;
  283.           break;
  284.         } else if(shot[i] == wumpusroom) {
  285.           lcd.print(" HIT");
  286.           nextstate = STATE_GAMEWIN;
  287.           state = STATE_KEYWAIT;
  288.           break;
  289.         }
  290.       }
  291.       if(nextstate == STATE_GO1) { // Missed - the Wumpus might move
  292.         switch(random(4)) {
  293.           case 0: break; // Does not move
  294.           case 1: wumpusroom = caves[wumpusroom].dir1; break;
  295.           case 2: wumpusroom = caves[wumpusroom].dir2; break;
  296.           case 3: wumpusroom = caves[wumpusroom].dir3; break;
  297.         }
  298.       }
  299.       break;
  300.  
  301.  
  302.     case STATE_BATS:
  303.       lcd.clear();
  304.       lcd.setCursor(0,0);
  305.       //         1234567890123456
  306.       lcd.print("Bats fly you to");
  307.       lcd.setCursor(0,1);
  308.       lcd.print("a random room.");
  309.       playerroom = random(20);
  310.       nextstate = STATE_GO1;
  311.       state = STATE_KEYWAIT;
  312.       break;
  313.  
  314.  
  315.     case STATE_PIT:
  316.       lcd.clear();
  317.       lcd.setCursor(0,0);
  318.       //         1234567890123456
  319.       lcd.print("AAIIIEEEeeee.e..");
  320.       lcd.setCursor(0,1);
  321.       lcd.print("You fell in  pit");
  322.       nextstate = STATE_GAMEOVER;
  323.       state = STATE_KEYWAIT;
  324.       break;
  325.  
  326.  
  327.     case STATE_WUMPUSCHOMP:
  328.       lcd.clear();
  329.       lcd.setCursor(0,0);
  330.       //         1234567890123456
  331.       lcd.print("Omnomnomnomnomn!");
  332.       lcd.setCursor(0,1);
  333.       lcd.print("Wumpus ate you.");
  334.       nextstate = STATE_GAMEOVER;
  335.       state = STATE_KEYWAIT;
  336.       break;
  337.  
  338.  
  339.     case STATE_SUICIDE:
  340.       lcd.clear();
  341.       lcd.setCursor(0,0);
  342.       //         1234567890123456
  343.       lcd.print("BOOOOM HEADSHOT!");
  344.       lcd.setCursor(0,1);
  345.       lcd.print("Shot yourself ><");
  346.       nextstate = STATE_GAMEOVER;
  347.       state = STATE_KEYWAIT;
  348.       break;
  349.  
  350.  
  351.     case STATE_GAMEWIN:
  352.       lcd.clear();
  353.       lcd.setCursor(0,0);
  354.       //         1234567890123456
  355.       lcd.print("Great shot Robin");
  356.       lcd.setCursor(0,1);
  357.       lcd.print("Wumpus is dead");
  358.       nextstate = STATE_GAMEOVER;
  359.       state = STATE_KEYWAIT;
  360.       break;
  361.  
  362.  
  363.     case STATE_GAMEOVER:
  364.       lcd.clear();
  365.       lcd.setCursor(0,0);
  366.       //         1234567890123456
  367.       lcd.print("-- GAME  OVER --");
  368.       lcd.setCursor(0,1);
  369.       lcd.print("<NewMap  Replay>");
  370.       state = STATE_GAMEOVERWAIT;
  371.       break;
  372.  
  373.  
  374.     case STATE_GAMEOVERWAIT:
  375.       if(buttonJustPressed) {
  376.         switch(button) {
  377.           case BUTTON_LEFT:
  378.             shuffle(); // Fall through .....
  379.           case BUTTON_RIGHT:
  380.             newgame();
  381.             break;
  382.           default:
  383.             flashbacklight();
  384.             break;
  385.         }
  386.       }
  387.       break;
  388.  
  389.  
  390.     default: break;
  391.   }
  392.   //clear the buttonJustPressed & buttonJustReleased flags; they've already done their job
  393.  if(buttonJustPressed)  buttonJustPressed  = false;
  394.  if(buttonJustReleased) buttonJustReleased = false;
  395.  delay(25);                           // Delay to stop buttons "jittering" false presses
  396. }
  397.  
  398. void flashbacklight() {
  399.   digitalWrite(LCD_BACKLIGHT_PIN, LOW);  delay(150);
  400.   digitalWrite(LCD_BACKLIGHT_PIN, HIGH); delay(150);
  401. }
  402.  
  403. void outputplayerroom() {
  404.   lcd.clear();
  405.   lcd.setCursor(0,0);
  406.   //          1234567890123456
  407.   lcd.print( "Room:" );
  408.   lcd.print(       caves[playerroom].id );
  409.   lcd.print(       " Exits:" );
  410.   lcd.print(               caves[caves[playerroom].dir1].id );
  411.   lcd.print(                caves[caves[playerroom].dir2].id );
  412.   lcd.print(                 caves[caves[playerroom].dir3].id );
  413.   lcd.setCursor(0,1);
  414. }
  415.  
  416. void outputshotui() {
  417.   lcd.clear();
  418.   lcd.setCursor(0,0);
  419.   lcd.print("SHOOT: ");
  420.   for(byte i = 0; i < MAXSHOTDISTANCE; i++) {
  421.     if(shot[i] == 255) lcd.print('.');
  422.     else lcd.print(caves[shot[i]].id);
  423.   }
  424.   if(shots < MAXSHOTDISTANCE) {
  425.     room_t r = caves[shot[shots]];
  426.     if(r.visited && caves[r.dir1].known) {
  427.       lcd.setCursor(2,1);
  428.       lcd.print('<');
  429.       lcd.print(caves[r.dir1].id);
  430.     }
  431.     if(r.visited && caves[r.dir2].known) {
  432.       lcd.setCursor(6,1);
  433.       lcd.print('^');
  434.       lcd.print(caves[r.dir2].id);
  435.     }
  436.     if(r.visited && caves[r.dir3].known) {
  437.       lcd.setCursor(10,1);
  438.       lcd.print(caves[r.dir3].id);
  439.       lcd.print('>');
  440.     }
  441.   }
  442.   lcd.setCursor(14,1);
  443.   lcd.print('*');
  444. }
  445.  
  446. void newgame() {
  447.   state = STATE_GO1;
  448.   playerroom = startplayerroom;
  449.   wumpusroom = startwumpusroom;
  450.   batsroom = startbatsroom;
  451.   pitroom = startpitroom;
  452.   for(int i = 0; i < 20; i++) caves[i].visited = caves[i].known = false;
  453. }
  454.  
  455. void shuffle() {
  456.   int i, j, k;
  457.   char l;
  458.   // Reset the map
  459.   caves[0] = (room_t) { 1,4,5,'A',false,false };
  460.   caves[1] = (room_t) { 0,2,7,'B',false,false };
  461.   caves[2] = (room_t) { 1,3,9,'C',false,false };
  462.   caves[3] = (room_t) { 2,4,11,'D',false,false };
  463.   caves[4] = (room_t) { 0,3,13,'E',false,false };
  464.   caves[5] = (room_t) { 0,6,14,'F',false,false };
  465.   caves[6] = (room_t) { 5,7,15,'G',false,false };
  466.   caves[7] = (room_t) { 1,6,8,'H',false,false };
  467.   caves[8] = (room_t) { 7,9,16,'I',false,false };
  468.   caves[9] = (room_t) { 2,8,10,'J',false,false };
  469.   caves[10] = (room_t) { 9,11,17,'K',false,false };
  470.   caves[11] = (room_t) { 3,10,12,'L',false,false };
  471.   caves[12] = (room_t) { 11,13,18,'M',false,false };
  472.   caves[13] = (room_t) { 4,12,14,'N',false,false };
  473.   caves[14] = (room_t) { 5,13,19,'O',false,false };
  474.   caves[15] = (room_t) { 6,16,19,'P',false,false };
  475.   caves[16] = (room_t) { 8,15,17,'Q',false,false };
  476.   caves[17] = (room_t) { 10,16,18,'R',false,false };
  477.   caves[18] = (room_t) { 12,17,19,'S',false,false };
  478.   caves[19] = (room_t) { 14,15,18,'T',false,false };
  479.   // Place the player, wumpus, bats and the pit
  480.   startplayerroom = random(20);
  481.   do { startwumpusroom = random(20); } while (startwumpusroom == startplayerroom);
  482.   do { startbatsroom = random(20); } while (startbatsroom == startwumpusroom || startbatsroom == startplayerroom);
  483.   do { startpitroom = random(20); } while (startpitroom == startbatsroom || startpitroom == startwumpusroom || startpitroom == startplayerroom);
  484.   // Mix up the room IDs
  485.   for(i = 0; i < 500; i++) {
  486.     j = random(20);
  487.     do { k = random(20); } while( k == j );
  488.     l = caves[j].id;
  489.     caves[j].id = caves[k].id;
  490.     caves[k].id = l;
  491.   }
  492.   // Re-alphabetasize the room IDs
  493.   for(i = 0; i < 20; i++) {
  494.     if(caves[caves[i].dir3].id < caves[caves[i].dir2].id) { j = caves[i].dir2; caves[i].dir2 = caves[i].dir3; caves[i].dir3 = j; }
  495.     if(caves[caves[i].dir2].id < caves[caves[i].dir1].id) { j = caves[i].dir1; caves[i].dir1 = caves[i].dir2; caves[i].dir2 = j; }
  496.     if(caves[caves[i].dir3].id < caves[caves[i].dir2].id) { j = caves[i].dir2; caves[i].dir2 = caves[i].dir3; caves[i].dir3 = j; }
  497.   }
  498. }
  499.  
  500. /*--------------------------------------------------------------------------------------
  501.   ReadButtons()
  502.   Detect the button pressed and return the value
  503.   Uses global values buttonWas, buttonJustPressed, buttonJustReleased.
  504. --------------------------------------------------------------------------------------*/
  505. byte ReadButtons() {
  506.    unsigned int buttonVoltage;
  507.    byte button = BUTTON_NONE;   // return no button pressed if the below checks don't write to btn
  508.    
  509.    //read the button ADC pin voltage
  510.    buttonVoltage = analogRead( BUTTON_ADC_PIN );
  511.    //sense if the voltage falls within valid voltage windows
  512.    if( buttonVoltage < ( RIGHT_10BIT_ADC + BUTTONHYSTERESIS ) )
  513.    {
  514.       button = BUTTON_RIGHT;
  515.    }
  516.    else if(   buttonVoltage >= ( UP_10BIT_ADC - BUTTONHYSTERESIS )
  517.            && buttonVoltage <= ( UP_10BIT_ADC + BUTTONHYSTERESIS ) )
  518.    {
  519.       button = BUTTON_UP;
  520.    }
  521.    else if(   buttonVoltage >= ( DOWN_10BIT_ADC - BUTTONHYSTERESIS )
  522.            && buttonVoltage <= ( DOWN_10BIT_ADC + BUTTONHYSTERESIS ) )
  523.    {
  524.       button = BUTTON_DOWN;
  525.    }
  526.    else if(   buttonVoltage >= ( LEFT_10BIT_ADC - BUTTONHYSTERESIS )
  527.            && buttonVoltage <= ( LEFT_10BIT_ADC + BUTTONHYSTERESIS ) )
  528.    {
  529.       button = BUTTON_LEFT;
  530.    }
  531.    else if(   buttonVoltage >= ( SELECT_10BIT_ADC - BUTTONHYSTERESIS )
  532.            && buttonVoltage <= ( SELECT_10BIT_ADC + BUTTONHYSTERESIS ) )
  533.    {
  534.       button = BUTTON_SELECT;
  535.    }
  536.    //handle button flags for just pressed and just released events
  537.    if( ( buttonWas == BUTTON_NONE ) && ( button != BUTTON_NONE ) )
  538.    {
  539.       //the button was just pressed, set buttonJustPressed, this can optionally be used to trigger a once-off action for a button press event
  540.       //it's the duty of the receiver to clear these flags if it wants to detect a new button change event
  541.       buttonJustPressed  = true;
  542.       buttonJustReleased = false;
  543.    }
  544.    if( ( buttonWas != BUTTON_NONE ) && ( button == BUTTON_NONE ) )
  545.    {
  546.       buttonJustPressed  = false;
  547.       buttonJustReleased = true;
  548.    }
  549.    
  550.    //save the latest button value, for change event detection next time round
  551.    buttonWas = button;
  552.    
  553.    return( button );
  554. }
RAW Paste Data
Pastebin PRO Summer Special!
Get 60% OFF on Pastebin PRO accounts!
Top