Steemnova: Fleet market and transfer mission

in #utopian-io3 years ago (edited)

Steemnova is active opensource project based on the old Ogame gameplay. New features are coming.

Transfer mission

The new mission "transfer" was needed for the market - to sell the fleet.
It is very simple mission which is used to give the fleet away to another player.

Peek 2018-04-05 22-41.gif

After success we have the message about transfer:

Peek 2018-04-05 22-43.gif

Solution

Here you can find the steps how to create a new mission:

  1. I've created the new mission file which extends MissionFunctions
 includes/classes/missions/MissionCaseTransfer.class.php
@@ -0,0 +1,70 @@
+<?php
+
+class MissionCaseTransfer extends MissionFunctions implements Mission
+{
+   function __construct($Fleet)
+   {
+       $this->_fleet   = $Fleet;
+   }
+

TargetEvent method is called when the fleet is on the target planet. So whole logic is here. The first part is getting data about planets. Messages for users need this.

+   function TargetEvent()
+   {
+       $sql = 'SELECT name FROM %%PLANETS%% WHERE `id` = :planetId;';
+
+       $startPlanetName    = Database::get()->selectSingle($sql, array(
+           ':planetId' => $this->_fleet['fleet_start_id']
+       ), 'name');
+
+       $targetPlanetName   = Database::get()->selectSingle($sql, array(
+           ':planetId' => $this->_fleet['fleet_end_id']
+       ), 'name');

Here message is created in the user's language:

+
+       $LNG            = $this->getLanguage(NULL, $this->_fleet['fleet_owner']);
+
+       $Message        = sprintf($LNG['sys_transfer_mess_owner'],
+           $targetPlanetName, GetTargetAddressLink($this->_fleet, ''),
+           pretty_number($this->_fleet['fleet_resource_metal']), $LNG['tech'][901],
+           pretty_number($this->_fleet['fleet_resource_crystal']), $LNG['tech'][902],
+           pretty_number($this->_fleet['fleet_resource_deuterium']), $LNG['tech'][903]
+       );

After that I get the fleet and add it to the message

+
+
+       $fleet = FleetFunctions::unserialize($this->_fleet['fleet_array']);
+
+       foreach($fleet as $elementID => $amount) {
+           $Message    .= '<br>'.$LNG['tech'][$elementID].': '.pretty_number($amount);
+       }
+

And here how message looks like:

One of your fleets reaches the planet Planeta domowa [1:1:8] and delivers 0 Metal, 0 Crystal and 0 Deuterium.
Heavy Cargo: 10

Created message is sent to the user

+       PlayerUtil::sendMessage($this->_fleet['fleet_owner'], 0, $LNG['sys_mess_tower'], 5,
+           $LNG['sys_mess_transport'], $Message, $this->_fleet['fleet_start_time'], NULL, 1, $this->_fleet['fleet_universe']);
+

Customer will receive similar message in his language:

+       $LNG            = $this->getLanguage(NULL, $this->_fleet['fleet_target_owner']);
+       $Message        = sprintf($LNG['sys_transfer_mess_user'],
+           $startPlanetName, GetStartAddressLink($this->_fleet, ''),
+           $targetPlanetName, GetTargetAddressLink($this->_fleet, ''),
+           pretty_number($this->_fleet['fleet_resource_metal']), $LNG['tech'][901],
+           pretty_number($this->_fleet['fleet_resource_crystal']), $LNG['tech'][902],
+           pretty_number($this->_fleet['fleet_resource_deuterium']), $LNG['tech'][903]
+       );
+
+       foreach($fleet as $elementID => $amount) {
+           $Message    .= '<br>'.$LNG['tech'][$elementID].': '.pretty_number($amount);
+       }
+
+       PlayerUtil::sendMessage($this->_fleet['fleet_target_owner'], 0, $LNG['sys_mess_tower'], 5,
+           $LNG['sys_mess_transport'], $Message, $this->_fleet['fleet_start_time'], NULL, 1, $this->_fleet['fleet_universe']);
+

And the more important part here. StoreGoodsToPlanet is droping resources to the target planet and RestoreFleet adds to the fleet.
function RestoreFleet($onStart = true)

+       $this->StoreGoodsToPlanet();
+       $this->RestoreFleet(false);
+   }
+
+   function EndStayEvent()
+   {
+       return;
+   }
+
+   function ReturnEvent()
+   {
+       $this->RestoreFleet();
+   }
+}

Also I had to add new mission in a few places like handler:

 includes/classes/class.FlyingFleetHandler.php
@@ -33,6 +33,7 @@ class FlyingFleetHandler
        11  => 'MissionCaseFoundDM',
        15  => 'MissionCaseExpedition',
        16  => 'MissionCaseTrade',
+       17  => 'MissionCaseTransfer',
    );

and mission class:

@@ -446,13 +446,19 @@ public static function GetAvailableMissions($USER, $MissionInfo, $GetInfoPlanet)
                if (!$YourPlanet && self::OnlyShipByID($MissionInfo['Ship'], 210) && isModuleAvailable(MODULE_MISSION_SPY))
                    $availableMissions[]    = 6;
 
                if (!$YourPlanet) {
+                   if(isModuleAvailable(MODULE_MISSION_TRANSFER)) {
+                       $availableMissions[]    = 17;
+                   }
+

That is all. I'm skipping parts with translactions.

Fleet Market

Idea of the fleet market is to give the possibility to buy ships from players. Also like in the real live you do not need know submarine building technology to buy it.

Peek 2018-04-05 22-44.gif

Peek 2018-04-05 22-45.gif

Solution

First step - change the UI to give the posibility to add offer to market.

styles/templates/game/page.fleetStep2.default.tpl


@@ -85,6 +86,17 @@
                        </select>
                    </td>
                </tr>
+               <tr class="no-border">
+                   <td>
+                       {$LNG.fl_market_type}
+                   </td>
+                   <td>
+                       <select name="markettype">
+                           <option value="0" selected>{$LNG.fl_mt_resources}</option>
+                           <option value="1">{$LNG.fl_mt_fleet}</option>
+                       </select>
+                   </td>
+               </tr>
            </table>
Use the preferences create the offer. Like you can see there is a limit that offer can be on the fleet market without resources.

includes/pages/game/ShowFleetStep3Page.class.php

@@ -38,7 +38,7 @@ public function show()
        $TransportDeuterium     = max(0, round(HTTP::_GP('deuterium', 0.0)));
        $WantedResourceType     = HTTP::_GP('resEx', 0);
        $WantedResourceAmount       = max(0, round(HTTP::_GP('exchange', 0.0)));
-
+       $markettype     = HTTP::_GP('markettype', 0);
        $visibility     = HTTP::_GP('visibility', 0);
        $maxFlightTime      = HTTP::_GP('maxFlightTime', 0);
        $stayTime               = HTTP::_GP('staytime', 0);
@@ -91,13 +91,22 @@ public function show()
            )));
        }
 
-       if (($targetMission == 3 || $targetMission == 16)&& $TransportMetal + $TransportCrystal + $TransportDeuterium < 1)
+       // Transport and market type 0 have to contain resources
+       if (($targetMission == 3 || ($targetMission == 16 && $markettype == 0))&& $TransportMetal + $TransportCrystal + $TransportDeuterium < 1)
        {
            $this->printMessage($LNG['fl_no_noresource'], array(array(
                'label' => $LNG['sys_back'],
                'url'   => 'game.php?page=fleetStep2'
            )));
        }
+       // Market typ 1 cannot contain resources
+       if($targetMission == 16 && $markettype == 1 && $TransportMetal + $TransportCrystal + $TransportDeuterium != 0)
+       {
+           $this->printMessage($LNG['fl_resources'], array(array(
+               'label' => $LNG['sys_back'],
+               'url'   => 'game.php?page=fleetStep2'
+           )));
+       }

And here changed sql to keep the transaction type.

    if($targetMission == 16) {
            $sql    = 'INSERT INTO %%TRADES%% SET
+               transaction_type            = :transaction,
                seller_fleet_id             = :sellerFleet,
                filter_visibility           = :visibility,
                filter_flighttime           = :flightTime,
                ex_resource_type            = :resType,
                ex_resource_amount      = :resAmount;';
 
                $db->insert($sql, array(
+                   ':transaction'          => $markettype,
                    ':sellerFleet'          => $fleet_id,
                    ':resType'                  => $WantedResourceType,
                    ':resAmount'                => $WantedResourceAmount,
Market place

In the show method data is "transfered" to the template. So I had to prepare some data for the main market view

Like fleet information to know what you buy:

@@ -354,21 +406,33 @@ public function show()
            $TO_HC_SPEED        = FleetFunctions::GetFleetMaxSpeed(array(203 =>1), $USER);
            $TO_HC_DUR          = FleetFunctions::GetMissionDuration(10, $TO_HC_SPEED, $TO_Distance, $SpeedFactor, $USER);
 
+           $fleet_str = '';
+           foreach($FROM_fleet as $name => $amount) {
+               $fleet_str .= $LNG['shortNames'][$name].' x'.$amount."\n";
+           }
+

Here is exporting of the data to the template:


 
            $total = $fleetsRow['fleet_resource_metal'] + $fleetsRow['fleet_resource_crystal'] + $fleetsRow['fleet_resource_deuterium'];
            $FlyingFleetList[]  = array(
                'id'            => $fleetsRow['fleet_id'],
                'username'          => $fleetsRow['username'],
+               'type' => $fleetsRow['transaction_type'],
 
                'fleet_resource_metal'      => $fleetsRow['fleet_resource_metal'],
                'fleet_resource_crystal'            => $fleetsRow['fleet_resource_crystal'],
                'fleet_resource_deuterium'          => $fleetsRow['fleet_resource_deuterium'],
                'total' => $total,
                'ratio' => round($total / $fleetsRow['ex_resource_amount'], 1),
+               'fleet'     => $fleet_str,
                'diplo' => $fleetsRow['level'],
+               'from_alliance' => $fleetsRow['ally_id'] == $USER['ally_id'],
                'possible_to_buy' => $buy['buyable'],
                'reason' => $buy['reason'],
                'fleet_wanted_resource' => $resourceN,
@@ -387,7 +451,8 @@ public function show()
        $this->assign(array(
            'message' => $message,
            'FlyingFleetList'       => $FlyingFleetList,
-           'history' => $this->getTradeHistory(),
+           'resourceHistory' => $this->getResourceTradeHistory(),
+           'fleetHistory' => $this->getFleetTradeHistory(),
        ));
        $this->tplObj->loadscript('marketplace.js');
        $this->display('page.marketPlace.default.tpl');

And the special method to get the fleet transactions which is used.

+   private function getFleetTradeHistory() {
+       global $LNG;
+       $db = Database::get();
+       $sql = 'SELECT
+           seller.fleet_array as fleet,
+           buy_time as time,
+           ex_resource_type as res_type,
+           ex_resource_amount as amount
+           FROM %%TRADES%%
+           JOIN %%LOG_FLEETS%% seller ON seller.fleet_id = seller_fleet_id
+           JOIN %%LOG_FLEETS%% buyer ON buyer.fleet_id = buyer_fleet_id
+           WHERE transaction_type = 1 ORDER BY time DESC LIMIT 40;';
+       $trades = $db->select($sql, array(
+           //TODO LIMIT
+       ));
+       for($i =0; $i< count($trades);$i++){
+           $fleet =  FleetFunctions::unserialize($trades[$i]['fleet']);
+           $fleet_str = '';
+           foreach($fleet as $name => $amount) {
+               $fleet_str .= $LNG['shortNames'][$name].' x'.$amount."\n";
+           }
+           $trades[$i]['fleet_str'] = $fleet_str;
+       }
+       return $trades;
+   }
+

Also what we need to change is the buy action when some one will click into the button.

    private function doBuy() {
        global $USER, $PLANET, $reslist, $resource, $LNG, $pricelist;
        $FleetID            = HTTP::_GP('fleetID', 0);
@@ -104,7 +149,14 @@ private function doBuy() {
            if ($db->rowCount() != 0) {
                $level = $res[0]['level'];
            }
-           $buy = $this->checkBuyable($fleetResult[0]['filter_visibility'], $level, $fleetResult[0]['ally_id'], $USER['ally_id']);
+           $buy = $this->checkDiplo($fleetResult[0]['filter_visibility'], $level, $fleetResult[0]['ally_id'], $USER['ally_id']);
+           if(!$buy['buyable']) {
+               return $buy['reason'];
+           }
+       }
+
+       if($fleetResult[0]['transaction_type'] == 1) {
+           $buy = $this->checkTechs($fleetResult[0]);
            if(!$buy['buyable']) {
                return $buy['reason'];
            }

Mission 3 is transport but for the fleet transport the 17 is used. What means transfer mission created before.

@@ -237,7 +289,7 @@ private function doBuy() {
            ':fleet_start_time' => $fleetStartTime,
            ':fleet_end_stay' => $fleetStayTime,
            ':fleet_end_time' => $fleetEndTime,
-           ':fleet_mission' => 3,
+           ':fleet_mission' => $fleetResult['transaction_type'] == 0 ? 3 : 17,
            ':fleet_no_m_return' => 1,
            ':fleet_mess'=> 0,
        );

Market UI

Like you can see on the gif, I;ve split the website into two divs which are changing after the button action.

For this I use jquery:

styles/templates/game/page.marketPlace.default.tpl

@@ -7,13 +7,22 @@
            {$LNG.market_info_header}
        </th>
    </tr>
+   <tr>
+       <td>
+           <button id="resourceMBtn" class="marketOption selected">Resource market</button>
+       </td>
+       <td>
+           <button id="fleetMBtn" class="marketOption">Fleet market</button>
+       </td>
+   </tr>

.....

 {block name="script" append}
 <script src="scripts/base/jquery.tablesorter.js"></script>
-<script>$(function() {
+<script>
+function reloadMarketBox() {
+   var cl = $("#resourceMBtn").attr("class");
+   var resB = $("#resourceMarketBox");
+   if(cl !=null && cl.indexOf("selected") != -1)
+       resB.attr("style","display: inline");
+   else
+       resB.attr("style","display: none");
+
+   cl = $("#fleetMBtn").attr("class");
+   var fleetB = $("#fleetMarketBox");
+   if(cl !=null && cl.indexOf("selected") != -1)
+       fleetB.attr("style","display: inline");
+   else
+       fleetB.attr("style","display: none");
+}
+
+$(function() {
+// Set the default
+reloadMarketBox();
+//
+$("#resourceMBtn, #fleetMBtn").on("click", function(){
+   $(".marketOption").removeClass("selected");
+   $(this).addClass("selected");
+   reloadMarketBox();
+});

And new table with the data:

+<div id="fleetMarketBox"  style="display:none">
+<table id="tradeFleetList" style="width:50%;white-space: nowrap;" class="tablesorter">
+   <thead>
+       <tr>
+           <th>ID</th>
+           <th>{$LNG['gl_player']}</th>
+           <th>{$LNG['market_fleet']}</th>
+           <th>{$LNG.market_p_end}</th>
+           <th  class="no-background no-border center">-></th>
+           <th>{$LNG.market_p_cost_type}</th>
+           <th>{$LNG.market_p_cost_amount}</th>
+           <th>{$LNG.market_p_from_duration}</th>
+           <th class="LC" style="display: none;">{$LNG.market_p_to_duration}</th>
+           <th class="HC">{$LNG.market_p_to_duration}</th>
+           <th>{$LNG.market_p_buy}</th>
+       </tr>
+   </thead>
+   <tbody>
 
+   {foreach name=FlyingFleets item=FlyingFleetRow from=$FlyingFleetList}
+   {if $FlyingFleetRow.type == 1}
+   <tr class='{if {$FlyingFleetRow.diplo} == 5}
+    trade-enemy
+       {elseif ({$FlyingFleetRow.diplo} != NULL && {$FlyingFleetRow.diplo} <= 3) || {$FlyingFleetRow.from_alliance} == 1}
+        trade-ally
+         {/if}
+   {if $FlyingFleetRow.possible_to_buy != true} trade-disallowed {/if}'>
+       <td>{$smarty.foreach.FlyingFleets.iteration}</td>
+       <td class="table_username">{$FlyingFleetRow.username}</td>
+       <td>{$FlyingFleetRow.fleet}</td>
+       <td data-time="{$FlyingFleetRow.end}">{pretty_fly_time({$FlyingFleetRow.end})}</td>
+       <td class="no-background no-border">
+           {if $FlyingFleetRow.fleet_wanted_resource_id == 1}
+           <img src="./styles/theme/nova/images/metal.gif"/>
+           {elseif $FlyingFleetRow.fleet_wanted_resource_id == 2}
+           <img src="./styles/theme/nova/images/crystal.gif"/>
+           {elseif $FlyingFleetRow.fleet_wanted_resource_id == 3}
+           <img src="./styles/theme/nova/images/deuterium.gif"/>
+           {/if}
+       </td>
+       <td class="wanted-resource-{$FlyingFleetRow.fleet_wanted_resource_id}">{$FlyingFleetRow.fleet_wanted_resource}</td>
+       <td class="wanted-resource-amount">{$FlyingFleetRow.fleet_wanted_resource_amount|number}</td>
+       <td>{pretty_fly_time({$FlyingFleetRow.from_duration})}</td>
+       <td class="LC" style="display: none;">{pretty_fly_time({$FlyingFleetRow.to_lc_duration})}</td>
+       <td class="HC">{pretty_fly_time({$FlyingFleetRow.to_hc_duration})}</td>
+       <td>
+           {if $FlyingFleetRow.possible_to_buy == true}
+           <form class="market_form" action="game.php?page=marketPlace&amp;action=buy" method="post">
+               <input name="fleetID" value="{$FlyingFleetRow.id}" type="hidden">
+               <input value="{$LNG.market_p_submit}" type="submit">
+           </form>
+           {else}
+               {$FlyingFleetRow.reason}
+           {/if}
+       </td>
+   </tr>
+
+   {/if}
+   {/foreach}
+   </tbody>
+</table>
+<hr/>
 
+<table id="fleetHistoryList" style="width:50%;white-space: nowrap;" class="tablesorter">
+   <thead>
+       <tr>
+           <th>ID</th>
+           <th>{$LNG.tkb_datum}</th>
+           <th>{$LNG['market_fleet']}</th>
+           <th  class="no-background no-border center">-></th>
+           <th>{$LNG.market_p_cost_amount}</th>
+       </tr>
+   </thead>
+   <tbody>
+       {foreach name=History item=row from=$fleetHistory}
+       <tr>
+           <td>{$smarty.foreach.History.iteration}</td>
+           <td>{$row.time}</td>
+           <td>{$row.fleet_str}</td>
+           <td class="no-background no-border center">
+               {if $row.res_type == 1}<img src="./styles/theme/nova/images/metal.gif"/>
+               {elseif $row.res_type == 2}<img src="./styles/theme/nova/images/crystal.gif"/>
+               {elseif $row.res_type == 3}<img src="./styles/theme/nova/images/deuterium.gif"/>{/if}</td>
+           <td>{$row.amount}</td>
+       </tr>
+       {/foreach}
+   </tbody>
+</table>
+
+</div>
 {/block}

Limited transfer

After discussion small problem has been found. What if weaker players will transfer fllet to stronger (with better technologies) to create better attack.
So the some limitation has been created. You cannot sell and transfer fleet to player with better combat technologies then yours. It needed only small changes in the transfer and market place.

+
+       if ($targetMission == 17) {
+           $attack = $USER[$resource[109]] * 10 + $USER['factor']['Attack'] * 100;
+           $defensive = $USER[$resource[110]] * 10 + $USER['factor']['Defensive'] * 100;
+           $shield = $USER[$resource[111]] * 10 + $USER['factor']['Shield'] * 100;
+
+           $targetPlayerData['factor']     = getFactors($targetPlayerData);
+
+           $attack_targ = $targetPlayerData[$resource[109]] * 10 + $targetPlayerData['factor']['Attack'] * 100;
+           $defensive_targ = $targetPlayerData[$resource[110]] * 10 + $targetPlayerData['factor']['Defensive'] * 100;
+           $shield_targ = $targetPlayerData[$resource[111]] * 10 + $targetPlayerData['factor']['Shield'] * 100;
+
+           if($attack < $attack_targ || $defensive < $defensive_targ || $shield < $shield_targ) {
+               $this->printMessage($LNG['fl_stronger_techs'], array(array(
+                   'label' => $LNG['sys_back'],
+                   'url'   => 'game.php?page=fleetTable'
+               )));
+           }
+       }
+

includes/pages/game/ShowMarketPlacePage.class.php

+   private function checkTechs($SELLER){
+       global $USER, $resource, $LNG;
+
+       $attack = $USER[$resource[109]] * 10 + $USER['factor']['Attack'] * 100;
+       $defensive = $USER[$resource[110]] * 10 + $USER['factor']['Defensive'] * 100;
+       $shield = $USER[$resource[111]] * 10 + $USER['factor']['Shield'] * 100;
+
+       $SELLER['factor']       = getFactors($SELLER);
+       $attack_targ = $SELLER[$resource[109]] * 10 + $SELLER['factor']['Attack'] * 100;
+       $defensive_targ = $SELLER[$resource[110]] * 10 + $SELLER['factor']['Defensive'] * 100;
+       $shield_targ = $SELLER[$resource[111]] * 10 + $SELLER['factor']['Shield'] * 100;
+
+       if($attack > $attack_targ || $defensive > $defensive_targ || $shield > $shield_targ) {
+           return array(
+               'buyable' => false,
+               'reason' => $LNG['market_buyable_no_tech']
+           );
+       }
+
+       return array("buyable" => true,
+           'reason' => '');
+   }
+           $buy = $this->checkDiplo($fleetsRow['filter_visibility'], $fleetsRow['level'], $fleetsRow['ally_id'], $USER['ally_id']);
+           //Fleet market
+           if($buy['buyable'] && $fleetsRow['transaction_type'] == 1)
+               $buy = $this->checkTechs($fleetsRow);
+



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Don't understand much but thanks for showing me the coding efforts made to add the new markets.

i hope that players like it :) I'm waiting for offers :)

Congratulations @dotevo! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of upvotes

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

Upvote this notification to help all Steemit users. Learn why here!

Do not miss the last announcement from @steemitboard!

Hey @dotevo I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x