4
\$\begingroup\$

Friend is forcing me to post code here because he doesn't like my long $_SESSION variables, and I'm telling him there's no way to short it out without again later in code defining them again which is unneeded overhead. I realize I don't need class for every monster I'm planning to remaking that later.

Playable version: https://vanjavk.me/rpggame/ (code has changed now)

<?php
session_start();



if(!isset($_SESSION['hp'])) {
    $_SESSION['hp']=10;
}

if(!isset($_SESSION['randomenemy'])) {
    $_SESSION['randomenemy']=0;
}



if(!isset($_SESSION['gold'])) {
    $_SESSION['gold']=0;
}

if(!isset($_SESSION['xp'])) {
    $_SESSION['xp']=100;
}

if(!isset($_SESSION['xy'])) {
    $_SESSION['xy']=array(0,0);
}
function calculateLevel($xp)
{
    $level=0;
    $startxp=100;
    $increase=0.1;
    while ($xp>=$startxp+$level*$increase*$startxp)
    {
        $xp-=$startxp+$level*$increase*$startxp;
        $level++;
    }
    $hp=10*$level;

    return array($level,$xp,$hp);
}

$levelxp = calculateLevel($_SESSION['xp']);

if(isset($_POST['name'])) {
    $_SESSION['name']=$_POST['name'];
}
if(isset($_POST['heal'])) {
    $_SESSION['hp']=15+$levelxp[2];
}

class location {
    public $name;
    public $xy;
    public $description;
    public $enemies;
    public $img;
    public $info;

    public function __construct($name,$xy,$description,$enemies,$img,$info)
    {
        $this->name = $name;
        $this->xy = $xy;
        $this->description = $description;
        $this->enemies = $enemies;
        $this->img = $img;
        $this->info = $info;
    }

}

class enemyBear {
    public $name;
    public $hp;
    public $description;
    public $minDmg;
    public $maxDmg;
    public $critChance;
    public $missChance;
    public $img;

    public function __construct()
    {
        $this->name = "Bear";
        $this->hp = 20;
        $this->description = "A mighty bear.";
        $this->minDmg = 0;
        $this->maxDmg = 2;
        $this->critChance = 0.03;
        $this->missChance = 0.20;
        $this->img = "img/bear.jpg";
    }
}
class enemyBoar {
    public $name;
    public $hp;
    public $description;
    public $minDmg;
    public $maxDmg;
    public $critChance;
    public $missChance;
    public $img;

    public function __construct()
    {
        $this->name = "Bear";
        $this->hp = 12;
        $this->description = "A wild boar.";
        $this->minDmg = 0;
        $this->maxDmg = 2;
        $this->critChance = 0.1;
        $this->missChance = 0.25;
        $this->img = "img/bear.jpg";
    }
}
class enemyWolf {
    public $name;
    public $hp;
    public $description;
    public $minDmg;
    public $maxDmg;
    public $critChance;
    public $missChance;
    public $img;

    public function __construct()
    {
        $this->name = "Wolf";
        $this->hp = 8;
        $this->description = "A wolf with sharp teeth.";
        $this->minDmg = 0;
        $this->maxDmg = 3;
        $this->critChance = 0.25;
        $this->missChance = 0.15;
        $this->img = "img/wolf.jpg";
    }
}
class enemyReaper {
    public $name;
    public $hp;
    public $description;
    public $minDmg;
    public $maxDmg;
    public $critChance;
    public $missChance;
    public $img;

    public function __construct()
    {
        $this->name = "Harvest reaper";
        $this->hp = 55;
        $this->description = "Stay off my field you pest.";
        $this->minDmg = 3;
        $this->maxDmg = 7;
        $this->critChance = 0.15;
        $this->missChance = 0.15;
        $this->img = "img/reaper.jpg";
    }
}
class enemyVulture {    
    public $name;
    public $hp;
    public $description;
    public $minDmg;
    public $maxDmg;
    public $critChance;
    public $missChance;
    public $img;

    public function __construct()
    {
        $this->name = "Vulture fleshripper";
        $this->hp = 35;
        $this->description = "Mmmmm... Flesh of fallen angels.";
        $this->minDmg = 5;
        $this->maxDmg = 10;
        $this->critChance = 0.25;
        $this->missChance = 0.15;
        $this->img = "img/vulture.jpg";
    }
}
//array(0,0)
if(!isset($_SESSION['locations'])) {
$_SESSION['locations']=array("0,0"=>new location("Goldshire inn",array(0,0),"Relax and dance in our inn.",array(),"img/goldshire.jpg","Melika Isenstrider greets you!"),
    "1,0"=>new location("Elwynn Forest",array(1,0),"Monsters lurk here.",array(new enemyBoar(), new enemyWolf(), new enemyBoar(), new enemyWolf(), new enemyBear(), new enemyBoar(), new enemyWolf(), new enemyBoar(), new enemyWolf(), new enemyBear()),"img/elwynn.jpg","You hear a strange sound."),
    "-1,0"=>new location("Westfall",array(-1,0),"Farmers are fightning wild animals.",array(new enemyVulture(), new enemyReaper(), new enemyVulture(), new enemyReaper(), new enemyReaper(), new enemyVulture(), new enemyReaper(), new enemyVulture(), new enemyReaper()),"img/westfall.jpg","You hear a strange mechanical sound."),
    "-1,-1"=>new location("Sentinel hill",array(-1,-1),"Everyone is peacefully enjoying sunny weather.",array(),"img/sentinelhill.jpg","You hear a welcoming sound."));
}
function splitString1($string)
{
    $x=substr($string, 0, 10);
    while (strlen($x)!=10){
        $x.=".";
    }
    return $x;
};
function splitString2($string)
{
    $x=substr($string, 10, 10);
    while (strlen($x)!=10){
        $x.=".";
    }
    return $x;
};
function attackEnemy($maxDmg,$minDmg,$critChance,$missChance){
    $attackdmg=0;
    $msg="miss";
    if (mt_rand()/mt_getrandmax()>$missChance){
        $attackdmg=random_int($minDmg,$maxDmg);
        $msg="hit";
        if (mt_rand()/mt_getrandmax()<$critChance){
            $attackdmg*=1.5;
            $msg="crit";
        }
    }
    return array($attackdmg,$msg);
}
function attack($level){
    return round($level+rand(0,5)/10*$level,2);
}
function combat($attack)
{
    $attackdmg= attack($GLOBALS["levelxp"][0]);
    $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->hp-=$attackdmg;
    $attackdmge=attackEnemy($_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->maxDmg,$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->minDmg,$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->critChance,$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->missChance);
    $_SESSION['hp']-=$attackdmge[0];
    if ($attack)
    {
        $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->info.="<p style='color:#1aa51d;'>You hit " . $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->name . " for " . $attackdmg . ". Current hp: ". $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->hp ."</p>";
    }else{
       $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->info.="<p style='color:#bcab2d;'>You tried to flee, but failed.</p>";
    }

    if ($attackdmge[1]==="hit")
    {
        $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->info.="<p style='color:#f4424b;'>" . $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->name . " hit you for " . $attackdmge[0] . ". Your hp: ". $_SESSION["hp"] ."</p>";

    }elseif ($attackdmge[1]==="miss") {
        $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->info.="<p style='color:#9e9e9e;'>" . $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->name . " missed you. Your hp: ". $_SESSION["hp"] ."</p>";
    }elseif ($attackdmge[1]==="crit") {
        $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->info.="<p style='color:#af0c14;'>" . $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->name . " critically hit you for " . $attackdmge[0] . ". Your hp: ". $_SESSION["hp"] ."</p>";
    }


    if ($_SESSION['hp']<=0)
    {
        echo "<script>window.alert('You died!');</script>";
        header("Location: http://vanjavk.me/rpggame/reset.php");
        die();
    }

    if ($_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->hp<=0)
    {
        $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->info.="<p style='color:#000000;'>" . $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->name . " died. You earned 50 xp!</p>";
        array_shift($_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies);
        $_SESSION['xp']+=50;

    }

}
if(isset($_POST['attack'])) 
{
    combat(true);
}
function post($string){
    return "<a onclick='document.getElementById(".$string.").click();' href='#'>";
}
function leaveCombat(){
    if (sizeof($_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies)>0)
    {
      if (mt_rand()/mt_getrandmax()<0.35)
      {
        return false;
      } else {
        combat(false);
        return true;
      }
    }

}
if(isset($_POST['right'])) {
    if (isset($_SESSION['locations'][($_SESSION['xy'][0]+1).",".$_SESSION['xy'][1]]))
    {
        (function(){
        if (leaveCombat()){ return; }
        $_SESSION['xy'][0]+=1;
        })();
    }
}
if(isset($_POST['left'])) {
    if (isset($_SESSION['locations'][($_SESSION['xy'][0]-1).",".$_SESSION['xy'][1]]))
    {
        (function(){
        if (leaveCombat()){ return; }
        $_SESSION['xy'][0]-=1;
        })();
    }
}
if(isset($_POST['up'])) {
    if (isset($_SESSION['locations'][$_SESSION['xy'][0].",".($_SESSION['xy'][1]+1)]))
    {
        (function(){
        if (leaveCombat()){ return; }
        $_SESSION['xy'][1]+=1;
        })();
    }
}
if(isset($_POST['down'])) {
    if (isset($_SESSION['locations'][$_SESSION['xy'][0].",".($_SESSION['xy'][1]-1)]))
    {
        (function(){
        if (leaveCombat()){ return; }
        $_SESSION['xy'][1]-=1;
        })();
    }
}
//echo $_SESSION['xy'][0].",".$_SESSION['xy'][1];
//echo $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->description;
?>

<!DOCTYPE html>

<html>
    <head>
        <script
        src="https://code.jquery.com/jquery-3.3.1.min.js"
        integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
        crossorigin="anonymous"></script>
        <link rel="stylesheet" type="text/css" href="/css/default.css">
        <link rel="stylesheet" type="text/css" href="css/default.css">
        <meta charset="UTF-8">
        <title>vanjavk</title>
    </head>
    <body>
        <script>
            var left="left";
            var right="right";
            var up="up";
            var down="down";
            var W = [119,87];
            var A = [97,65];
            var S = [115,83];
            var D = [100,68];
            document.onkeydown = function(event){
            if(D.includes(event.which) || D.includes(event.keyCode))    //d
                document.getElementById(right).click();
            else if(S.includes(event.which) || S.includes(event.keyCode))   //s    //d
                document.getElementById(down).click();
            else if(A.includes(event.which) || A.includes(event.keyCode)) //a    //d
                document.getElementById(left).click();
            else if(W.includes(event.which) || W.includes(event.keyCode))     //d
                document.getElementById(up).click();
            }
        </script>
        <div class="container">
            <div class="topleft">
<?php
if(isset($_SESSION["name"])) {
    echo "Your name: " . $_SESSION['name'] . "<br>";
    echo "Hitpoints: " . $_SESSION['hp'] . "<br>";
    echo "Gold: " . $_SESSION['gold'] . "<br>";
    echo "XP: " . $levelxp[1] . "<br>";
    echo "Level: " . $levelxp[0] . "<br>";
    echo "Location: " . $_SESSION['xy'][0] . ", " . $_SESSION['xy'][1] . "<br>";
    echo "<a href='reset.php'>RESET ALL DATA</a><br>";
    if (isset($_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->hp)){
        if ($_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->hp>0)
        {
            echo "<br>Enemy name: ".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->name."<br>";
            echo "Enemy description: ".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->description."<br>";
            echo "Enemy hitpoints: ".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->hp."<br>";
            echo "Enemy max damage: ".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->maxDmg."<br>";
            echo "Enemy min damage: ".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->minDmg."<br>";
            echo "Enemy crit chance: ".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->critChance."<br>";
            echo "Enemy miss chance: ".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->missChance."<br>";
        }
    }
} else {
    echo "Hey! Tell us your name: <form method='post' action=''>
    <input type='text' name='name'>
    <input type='submit'>
    </form>" . PHP_EOL;

}
?>


            </div>
            <div class="top"><div id="info">
<?php




echo $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->info;
?>

            </div></div>
            <script>$("#info").scrollTop($("#info")[0].scrollHeight);</script>
            <div class="topright">
                <div class="topright1">
<?php
//echo $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]];
echo "<h1>".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->name . "</h1><br>";
echo $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->description . "<br>";
echo "<img src='".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->img."' style='max-width:100%;max-height:80%;'>" . "<br>";
?>
                </div>
                <div class="topright2">

<?php
//echo $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]];
echo "<h1>".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->name . "</h1><br>";
echo $_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->description . "<br>";
echo "<img src='".$_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies[$_SESSION['randomenemy']]->img."' style='max-width:100%;max-height:80%;'>" . "<br>";
?>
                </div>
            </div>
            <div class="botleft"><h1>botleft Page</h1></div>
            <div class="bot"><div class="bot1">
<?php
if (sizeof($_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->enemies)>0){
    echo "<form method='post' action=''>
    <input name='attack' type='submit' value='attack'>
    </form>";
} else
{
    echo "<form method='post' action=''>
    <input name='heal' type='submit' value='heal'>
    </form>";  
}



?>
            </div><div class="bot2">



            </div>
            </div>
            <div class="botright">

<?php echo splitString1($_SESSION['locations'][($_SESSION['xy'][0]-1).",".($_SESSION['xy'][1]+1)]->name);?>|<?php echo post("up").splitString1($_SESSION['locations'][$_SESSION['xy'][0].",".($_SESSION['xy'][1]+1)]->name);?></a>|<?php echo splitString1($_SESSION['locations'][($_SESSION['xy'][0]+1).",".($_SESSION['xy'][1]+1)]->name);?><br>
<?php echo splitString2($_SESSION['locations'][($_SESSION['xy'][0]-1).",".($_SESSION['xy'][1]+1)]->name);?>|<?php echo post("up").splitString2($_SESSION['locations'][$_SESSION['xy'][0].",".($_SESSION['xy'][1]+1)]->name);?></a>|<?php echo splitString2($_SESSION['locations'][($_SESSION['xy'][0]+1).",".($_SESSION['xy'][1]+1)]->name);?><br>
--------------------------------<br>
<?php echo post("left").splitString1($_SESSION['locations'][($_SESSION['xy'][0]-1).",".$_SESSION['xy'][1]]->name);?></a>|<?php echo splitString1($_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->name);?>|<?php echo post("right").splitString1($_SESSION['locations'][($_SESSION['xy'][0]+1).",".$_SESSION['xy'][1]]->name);?></a><br>
<?php echo post("left").splitString2($_SESSION['locations'][($_SESSION['xy'][0]-1).",".$_SESSION['xy'][1]]->name);?></a>|<?php echo splitString2($_SESSION['locations'][$_SESSION['xy'][0].",".$_SESSION['xy'][1]]->name);?>|<?php echo post("right").splitString2($_SESSION['locations'][($_SESSION['xy'][0]+1).",".$_SESSION['xy'][1]]->name);?></a><br>
--------------------------------<br>
<?php echo splitString1($_SESSION['locations'][($_SESSION['xy'][0]-1).",".($_SESSION['xy'][1]-1)]->name);?>|<?php echo post("down").splitString1($_SESSION['locations'][$_SESSION['xy'][0].",".($_SESSION['xy'][1]-1)]->name);?></a>|<?php echo splitString1($_SESSION['locations'][($_SESSION['xy'][0]+1).",".($_SESSION['xy'][1]-1)]->name);?><br>
<?php echo splitString2($_SESSION['locations'][($_SESSION['xy'][0]-1).",".($_SESSION['xy'][1]-1)]->name);?>|<?php echo post("down").splitString2($_SESSION['locations'][$_SESSION['xy'][0].",".($_SESSION['xy'][1]-1)]->name);?></a>|<?php echo splitString2($_SESSION['locations'][($_SESSION['xy'][0]+1).",".($_SESSION['xy'][1]-1)]->name);?><br>

            </div>
        </div>
        <div style="visibility: hidden">
        <form name="post" action="" method="post">
        <input id="left" name="left" type='submit'>
        <input id="right" name="right" type='submit'>
        <input id="up" name="up" type='submit'>
        <input id="down" name="down" type='submit'>
        </div>
        </form>
    </body>

</html>
\$\endgroup\$
2
  • \$\begingroup\$ Welcome to Code Review! I'm thankful for friends who help me be accountable for my code, I hope you also get something out of reviewing! \$\endgroup\$
    – Phrancis
    Apr 1, 2018 at 5:27
  • \$\begingroup\$ All classes have common property variables. You could use one generic abstract class to sort of reduce the lines of code in the sub-classes. \$\endgroup\$
    – Rotimi
    Apr 1, 2018 at 19:11

1 Answer 1

1
\$\begingroup\$

For small, demo apps, $_SESSION is fine for persisting session data. However, moving forward, you'll need to know about the drawbacks of $_SESSION and why it's not recommended.

  • Shared hosting services share the same server instance for several websites. You risk leaking your session data with other websites on the same server if it's configured badly.
  • If your host has load-balancing capabilities, it may transparently spread traffic across different nodes. A session variable may "disappear" because the session data in one server isn't necessarily on the other server.
  • Sessions make code hard to test. It can cause two identical HTTP requests to act differently depending on the lingering session data.

Ideally, your PHP code should be stateless. This allows your code to scale horizontally in a load-balanced environment and act in the same way given the same input. Any form of state, like session data, should be pushed off elsewhere, away from the webserver. For example, CodeIgniter encrypts session data in cookies, each request effectively carries its session. Drupal has a Session module which stores session data in the database, tied to a user (if authenticated) or a unique identifier in a cookie (if unauthenticated).

As for your classes, it looks like you have multiple "enemy" classes that look the same. Consider making a single Enemy class instead, and instantiate from that. If there are classes with unique properties but still have something in common with Enemy, subclass Enemy for that particular class.

You also have utility functions in the global scope. Consider collecting them under one class. You can probably have them as methods of an instance of a utility class, or static methods of that utility class. Either way, just avoid having stuff on the global scope.

Also consider moving logic and rendering into separate classes. In typical Java terms, these would comprise your "rendering classes" and "service classes".

Now that everything is in a class, you might want to check out PHP's class-loading capabilities. This allows you to register a class loader, which allows PHP to load classes on the fly, as well as define your code in a one class per file fashion, pretty much like Java.

Lastly, flow control. Instead of your script running top-to-bottom with everything disorganized in the global space, you can define a "shell" class that instantiates singletons of logic classes (in Java, they're called "beans"), orchestrates the flow of data in your app. Something along the lines of...

// Enemy.php - base class for all enemies
class Enemy {...}

// Utils.php - all utility functions in here
class Utils {...}

// CombatLogic.php - All calculations go in here
class CombatLogic {...}

// PageRenderer.php - Receives data, and renders HTML
class PageRenderer {...}

// Request.php - All logic that grabs from $_POST, $_GET, etc goes here
class Request {...}

// Session.php - Logic that grabs session data from wherever you store it
class Session {...}

// App.php - Flow control here
class App {

  public __construct(){
    $this->renderer = new PageRenderer();
    $this->session = new Session();
    ...and so on.
  }

  public function main(){
    // Grab all data from Request
    // Recreate session data from Session, Enemy, etc.
    // Calculate new game state using CombatLogic, Utils, etc.
    // Render using PageRenderer
  }
}

(new App()).main()

Of course, in large scale apps and CMSes, these can be very generic and loose (interfaces, dependency injection, stuff) but the general idea is pretty much like this.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.