hy-farm/common/services/LandService.php
2026-05-07 20:10:54 +08:00

499 lines
18 KiB
PHP

<?php
/**
* Created by PhpStorm.
* User: zn
* Date: 2017/6/2
* Time: 10:35
*/
namespace common\services;
use common\models\Friend;
use common\models\Interaction;
use common\models\Land;
use common\modules\achievement\AchievementUtil;
use common\modules\vip\vo\CardUtil;
use common\utils\EnumUtil;
use common\utils\RedisKeyUtil;
use RedisLock\RedisLock;
use Yii;
use yii\base\Object;
/**
* 农田帮助类
* Class LandService
* @package common\services
*/
class LandService extends Object
{
/**
* 根据要升级的等级查找可以升级的农田
* @param $landConfigList
* @param $level
* @return Land
*/
public static function findLandUpgradeItemByLevel($landConfigList, $level)
{
if ($level == 0) return null;
//要查找的等级
$findLevel = $level - 1;
//查找农田
$findLandDbData = null;
foreach ($landConfigList as $item) {
if ($item['level'] == $findLevel) return $item;
}
//未找到,递归查找上一等级
return self::findLandUpgradeItemByLevel($landConfigList, $findLevel);
}
/**
* 播种
* @param $farmID
* @param $position
* @param $itemID
* @return int
*/
public static function sowSeeds($farmID, $position, $itemID, $isMysterySeed = 0)
{
try {
$landDbData = Land::findByFarmIDAndPosition($farmID, $position);
if (!$landDbData) return ResultStatusServices::RS_NOT_FIND_IN_DB;
//判断农田是否已经有农作物
if ($landDbData->crop_id != 0) return ResultStatusServices::RS_LAND_HAS_CROP;
$itemConfig = GameConfigServices::getParamByPath('item_list.' . $itemID);
if (empty($itemConfig)) return ResultStatusServices::RS_NOT_FIND_IN_CONFIG;
$cropConfig = GameConfigServices::getParamByPath('crop_list.' . $itemConfig['effect_id']);
if (empty($cropConfig)) return ResultStatusServices::RS_NOT_FIND_IN_CONFIG;
//修改农田数据
$landDbData->crop_id = $cropConfig['id'];
$landDbData->crop_start_time = time();
$landDbData->crop_gather_time = time() + intval($cropConfig['seedling_time']) + intval($cropConfig['grow_time']) + intval($cropConfig['ripe_time']);
$landDbData->is_mystery_seed = $isMysterySeed;
if (!$landDbData->save()) return ResultStatusServices::RS_SAVE_DB_ERROR;
} finally {
}
return ResultStatusServices::RS_OPERATION_SUCCESS;
}
/**
* 收获作物
* @param $farmID
* @param $position
* @param $output
* @param $itemID
* @return int
*/
public static function gatherCrop($farmID, $position, &$output, &$itemID)
{
$output = 0;
$itemID = null;
//加锁
$lock = new RedisLock(Yii::$app->redis, RedisKeyUtil::lockLand($farmID, $position), RedisLock::FLAG_CATCH_EXCEPTIONS);
if (!$lock->acquire(10)) return ResultStatusServices::RS_SAME_TIME_OPERATION;
try {
$landDbData = Land::findByFarmIDAndPosition($farmID, $position);
if (!$landDbData) return ResultStatusServices::RS_NOT_FIND_IN_DB;
//检查农作物
if ($landDbData->crop_id == 0) return ResultStatusServices::RS_LAND_NOT_CROP;
//判断时间,农作物是否可收获
if ($landDbData->is_ripe != 1) return ResultStatusServices::RS_CROP_NOT_RIPE;
//检查是否已收获过
if ($landDbData->has_gather != 0) return ResultStatusServices::RS_CROP_HAD_GATHER;
//获取配置
$cropConfig = GameConfigServices::getParamByPath('crop_list.' . $landDbData->crop_id);
if (empty($cropConfig)) return ResultStatusServices::RS_NOT_FIND_IN_CONFIG;
//设置收获的物品
$itemID = $cropConfig['item_id'];
//收获产量
$output = $landDbData->crop_num;
//设置已收获标志
$landDbData->has_gather = 1;
//保存数据
if (!$landDbData->save()) return ResultStatusServices::RS_SAVE_DB_ERROR;
} finally {
$lock->release();
}
return ResultStatusServices::RS_OPERATION_SUCCESS;
}
/**
* 更新所有农作物状态
* @param $farmID
* @param $farmLevel
* @return int
*/
public static function updateAllCropStatus($userID, $farmID, $farmLevel)
{
$landDbList = Land::findAll(['farm_id' => $farmID]);
foreach ($landDbList as $land) {
//检查是否需要更新
if ($land->crop_id != 0) {
//更新单个农作物状态
$rs = self::updateCropStatus($userID, $farmID, $land->position, $farmLevel);
if ($rs != ResultStatusServices::RS_OPERATION_SUCCESS)
return $rs;
}
}
return ResultStatusServices::RS_OPERATION_SUCCESS;
}
/**
* 更新单个农作物状态
* @param $farmID
* @param $position
* @param $farmLevel
* @return int
*/
public static function updateCropStatus($userID, $farmID, $position, $farmLevel)
{
//加锁
$lock = new RedisLock(Yii::$app->redis, RedisKeyUtil::lockLand($farmID, $position), RedisLock::FLAG_CATCH_EXCEPTIONS);
if (!$lock->acquire(10)) return ResultStatusServices::RS_SAME_TIME_OPERATION;
try {
$landDbData = Land::findRedis($farmID, $position);
if (!$landDbData) return ResultStatusServices::RS_NOT_FIND_IN_DB;
//检查农作物
if ($landDbData->crop_id == 0) return ResultStatusServices::RS_LAND_NOT_CROP;
//农作物是收获状态,直接返回
if ($landDbData->is_ripe == 1) return ResultStatusServices::RS_OPERATION_SUCCESS;
$cropConfig = GameConfigServices::getParamByPath('crop_list.' . $landDbData->crop_id);
$change = false;
//判断是否达到收获时间
if (time() < self::getLandCropGatherTime($landDbData)) {
//未成熟,随机病虫害
$growPhaseTime1 = $landDbData->crop_start_time + $cropConfig['seedling_time'];
if (time() > $growPhaseTime1) {
//种子期不随机虫
//计算需要随机的次数
if ($landDbData->disease_rand_time == 0)
$lastRandTime = time() - $landDbData->crop_start_time - $cropConfig['seedling_time'];
else
$lastRandTime = time() - $landDbData->disease_rand_time;
$time = GameConfigServices::getCommonNumByID(GameConfigServices::COMMON_DISEASE_RAND_TIME);
if ($time == 0) $time = 1;
$randCount = intval($lastRandTime / $time);
if ($randCount <= 0) $randCount = 0;
if ($randCount > 10) $randCount = 10;
//随机病害
for ($i = 0; $i < $randCount; $i++) {
if ($landDbData->has_dry == 0 && RandServices::randLandDisease(GameConfigServices::COMMON_DRY_RAND_NUM))
$landDbData->has_dry = 1;
if ($landDbData->has_bug == 0 && RandServices::randLandDisease(GameConfigServices::COMMON_BUG_RAND_NUM))
$landDbData->has_bug = 1;
if ($landDbData->has_grass == 0 && RandServices::randLandDisease(GameConfigServices::COMMON_GRASS_RAND_NUM))
$landDbData->has_grass = 1;
}
//更新随机时间
if ($randCount > 0)
$landDbData->disease_rand_time = time();
$change = true;
}
} else {
//农作物成熟,计算产量
//农场增产量
$farmConfig = GameConfigServices::getParamByPath('farm_level.' . $farmLevel);
$farmOutput = intval($farmConfig['output']);
//农作物产量
$cropOutput = intval($cropConfig['output']);
//农田等级产量
$landConfig = GameConfigServices::getLandUpgradeByLevelAndPosition($landDbData->level, $landDbData->position);
$landOutput = intval($landConfig['output']);
//vip
// $vip = CardUtil::findByUserID($userID);
// $vipConfig = GameConfigServices::getParamByPath('vip_list.' . $vip->level);
// $vipCount = 0;
// if (!empty($vipConfig)) $vipCount = (int)$vipConfig['fruit'];
//总产量
// $totalOutput = $farmOutput + $cropOutput + $landOutput ;
$addPercent = floatval($farmOutput) / 100 + floatval($landOutput) / 100;
$totalOutput = $cropOutput * (1 + $addPercent);
//计算保底产量
$minOutputPercent = GameConfigServices::getCommonNumByID(GameConfigServices::COMMON_MIN_OUTPUT_ID) / 100;
$landDbData->crop_min_num = $totalOutput * $minOutputPercent;
if ($landDbData->crop_min_num < 0) $landDbData->crop_min_num = 0;
//干旱减产百分比
$dryReductionPercent = 0;
if ($landDbData->has_dry)
$dryReductionPercent = floatval(GameConfigServices::getCommonNumByID(GameConfigServices::COMMON_DRY_ID)) / 100;
//虫害减产百分比
$bugReductionPercent = 0;
if ($landDbData->has_bug)
$bugReductionPercent = floatval(GameConfigServices::getCommonNumByID(GameConfigServices::COMMON_BUG_ID)) / 100;
//杂草减产百分比
$grassReductionPercent = 0;
if ($landDbData->has_grass)
$grassReductionPercent = floatval(GameConfigServices::getCommonNumByID(GameConfigServices::COMMON_GRASS_ID)) / 100;
//总减产百分比
$totalReductionPercent = $dryReductionPercent + $bugReductionPercent + $grassReductionPercent;
//最终产量
$landDbData->crop_num = $totalOutput * (1 - $totalReductionPercent);
if ($landDbData->crop_num < $landDbData->crop_min_num) $landDbData->crop_num = $landDbData->crop_min_num;
$landDbData->crop_num = intval($landDbData->crop_num);
//更改成熟状态
$landDbData->is_ripe = 1;
$change = true;
}
//保存
if ($change && !$landDbData->save()) ResultStatusServices::RS_SAVE_DB_ERROR;
} finally {
$lock->release();
}
return ResultStatusServices::RS_OPERATION_SUCCESS;
}
/**
* 清理农田
* @param $farmID
* @param $position
* @return int
*/
public static function clearLand($farmID, $position)
{
try {
$landDbData = Land::findByFarmIDAndPosition($farmID, $position);
if (!$landDbData) return ResultStatusServices::RS_NOT_FIND_IN_DB;
//检查是否需要清理
if ($landDbData->crop_id == 0) return ResultStatusServices::RS_LAND_NOT_NEED_CLEAR;
$landDbData->crop_id = 0;
$landDbData->crop_start_time = 0;
$landDbData->is_ripe = 0;
$landDbData->crop_num = 0;
$landDbData->crop_min_num = 0;
$landDbData->has_dry = 0;
$landDbData->has_bug = 0;
$landDbData->has_grass = 0;
$landDbData->has_gather = 0;
$landDbData->disease_rand_time = 0;
//保存
if (!$landDbData->save()) ResultStatusServices::RS_SAVE_DB_ERROR;
} finally {
}
return ResultStatusServices::RS_OPERATION_SUCCESS;
}
/**
* 初始化新数据
* @param Land $landDbData
* @param $farmID
* @param $position
* @return bool
*/
public static function initNewFarmDataAndSave(Land $landDbData, $farmID, $position)
{
$landDbData->farm_id = $farmID;
$landDbData->position = $position;
return $landDbData->save();
}
/**获取农田可交互类型
* @param $fromUserID
* @param $beUserID
* @param $landDbData
* @return array
*/
public static function getLandInteractionType($fromUserID, $beUserID, Land $landDbData)
{
if (!Friend::findOne(['user_id' => $fromUserID, 'friend_user_id' => $beUserID, 'status' => EnumUtil::FRIEND_AGREE]) &&
!Friend::findOne(['user_id' => $beUserID, 'friend_user_id' => $fromUserID, 'status' => EnumUtil::FRIEND_AGREE])
) return [];
if (!$landDbData || $landDbData->crop_id == 0) return [];
$typeList = [];
//是否偷取过
if ($landDbData->is_ripe && !$landDbData->has_gather &&
!Interaction::findRedis($fromUserID, $beUserID, $landDbData->crop_start_time, $landDbData->position, EnumUtil::INTERACTION_TYPE_STEAL) &&
$landDbData->crop_num > $landDbData->crop_min_num
) {
array_push($typeList, EnumUtil::INTERACTION_TYPE_STEAL);
}
//是否可以放虫
if (!$landDbData->is_ripe && !$landDbData->has_bug &&
!Interaction::findRedis($fromUserID, $beUserID, $landDbData->crop_start_time, $landDbData->position, EnumUtil::INTERACTION_TYPE_BUG)
) {
array_push($typeList, EnumUtil::INTERACTION_TYPE_BUG);
}
//是否可以放草
if (!$landDbData->is_ripe && !$landDbData->has_grass &&
!Interaction::findRedis($fromUserID, $beUserID, $landDbData->crop_start_time, $landDbData->position, EnumUtil::INTERACTION_TYPE_GRASS)
) {
array_push($typeList, EnumUtil::INTERACTION_TYPE_GRASS);
}
//是否可以浇水
if (!$landDbData->is_ripe && $landDbData->has_dry &&
!Interaction::findRedis($fromUserID, $beUserID, $landDbData->crop_start_time, $landDbData->position, EnumUtil::INTERACTION_TYPE_WATERING)
) {
array_push($typeList, EnumUtil::INTERACTION_TYPE_WATERING);
}
//是否可以除虫
if (!$landDbData->is_ripe && $landDbData->has_bug &&
!Interaction::findRedis($fromUserID, $beUserID, $landDbData->crop_start_time, $landDbData->position, EnumUtil::INTERACTION_TYPE_DISINSECTION)
) {
array_push($typeList, EnumUtil::INTERACTION_TYPE_DISINSECTION);
}
//是否可以除草
if (!$landDbData->is_ripe && $landDbData->has_grass &&
!Interaction::findRedis($fromUserID, $beUserID, $landDbData->crop_start_time, $landDbData->position, EnumUtil::INTERACTION_TYPE_WEEDING)
) {
array_push($typeList, EnumUtil::INTERACTION_TYPE_WEEDING);
}
return $typeList;
}
/**
* 偷菜
* @param $farmID
* @param $position
* @param $stealCount
* @return int
*/
public static function steal($farmID, $position, &$stealCount)
{
//加锁
$lock = new RedisLock(Yii::$app->redis, RedisKeyUtil::lockLand($farmID, $position), RedisLock::FLAG_CATCH_EXCEPTIONS);
if (!$lock->acquire(10)) return ResultStatusServices::RS_SAME_TIME_OPERATION;
try {
$landDbData = Land::findByFarmIDAndPosition($farmID, $position);
if (!$landDbData) return ResultStatusServices::RS_NOT_FIND_IN_DB;
//检查农作物
if ($landDbData->crop_id == 0) return ResultStatusServices::RS_LAND_NOT_CROP;
//农作物是否成熟状态
if ($landDbData->is_ripe != 1) return ResultStatusServices::RS_CROP_NOT_RIPE;
//农作物是否被收获过
if ($landDbData->has_gather == 1) return ResultStatusServices::RS_CROP_HAD_GATHER;
//可偷取数量
$stealCount = GameConfigServices::getCommonNumByID(GameConfigServices::COMMON_STEAL_NUM);
//收获保底数量
if ($landDbData->crop_num - $stealCount < $landDbData->crop_min_num)
$stealCount = $landDbData->crop_num - $landDbData->crop_min_num;
//没有可偷取的数量
if ($stealCount <= 0)
return ResultStatusServices::RS_CROP_STEAL_NOT_NUM;
//偷取
$landDbData->crop_num -= $stealCount;
//保存
if (!$landDbData->save()) ResultStatusServices::RS_SAVE_DB_ERROR;
} finally {
$lock->release();
}
return ResultStatusServices::RS_OPERATION_SUCCESS;
}
/**获取农田收获时间
* @param Land $landDbData
* @return int
*/
public static function getLandCropGatherTime(Land $landDbData)
{
$cropConfig = GameConfigServices::getParamByPath('crop_list.' . $landDbData->crop_id);
if (empty($cropConfig)) return $landDbData->crop_start_time;
//配置表生长周期是单个周期的时间差,为了方便计算,把生长周期变成从播种开始的时间
return $landDbData->crop_start_time + $cropConfig['seedling_time'] + $cropConfig['grow_time'] + $cropConfig['ripe_time'];
}
/**
* 获取农作物当前阶段
* @param Land $landDbData
* @return int
*/
public static function getLandCropPhase(Land $landDbData)
{
$cropConfig = GameConfigServices::getParamByPath('crop_list.' . $landDbData->crop_id);
//配置表生长周期是单个周期的时间差,为了方便计算,把生长周期变成从播种开始的时间
$growPhaseTime1 = $landDbData->crop_start_time + $cropConfig['seedling_time'];
$growPhaseTime2 = $growPhaseTime1 + $cropConfig['grow_time'];
$growPhaseTime3 = $growPhaseTime2 + $cropConfig['ripe_time'];
//每个阶段还需要的时间
if (time() < $growPhaseTime1) return EnumUtil::CROP_PHASE_SEED;
elseif (time() < $growPhaseTime2) return EnumUtil::CROP_PHASE_SEEDLING;
elseif (time() < $growPhaseTime3) return EnumUtil::CROP_PHASE_GROW;
else return EnumUtil::CROP_PHASE_RIPE;
}
}