Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Failed Conditions
Pull Request — main (#1494)
by Dan
08:06 queued 03:15
created

ShopGoodsProcessor::build()   F

Complexity

Conditions 46
Paths > 20000

Size

Total Lines 250
Code Lines 152

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 46
eloc 152
nc 23236608
nop 1
dl 0
loc 250
rs 0
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace Smr\Pages\Player;
4
5
use AbstractSmrPlayer;
6
use Exception;
7
use Globals;
8
use Smr\Page\PlayerPageProcessor;
9
use Smr\Request;
10
use Smr\TransactionType;
11
use SmrPort;
12
13
class ShopGoodsProcessor extends PlayerPageProcessor {
14
15
	public function __construct(
16
		private readonly int $goodID,
17
		private readonly ?int $amount = null,
18
		private readonly int $bargainNumber = 0,
19
		private readonly ?int $bargainPrice = null, // only for NPC
20
		private readonly ?int $offeredPrice = null,
21
		private readonly ?int $idealPrice = null
22
	) {}
23
24
	public function build(AbstractSmrPlayer $player): never {
25
		$ship = $player->getShip();
26
		$sector = $player->getSector();
27
28
		$amount = $this->amount ?? Request::getInt('amount');
29
		// no negative amounts are allowed
30
		if ($amount <= 0) {
31
			create_error('You must enter an amount > 0!');
32
		}
33
34
		$good_id = $this->goodID;
35
		$good_name = Globals::getGoodName($good_id);
36
37
		// do we have enough turns?
38
		if ($player->getTurns() == 0) {
39
			create_error('You don\'t have enough turns to trade.');
40
		}
41
42
		// get rid of those bugs when we die...there is no port at the home sector
43
		if (!$sector->hasPort()) {
44
			create_error('I can\'t see a port in this sector. Can you?');
45
		}
46
		$port = $sector->getPort();
47
48
		// check if the player has the right relations to trade at the current port
49
		if ($player->getRelation($port->getRaceID()) < RELATIONS_WAR) {
50
			create_error('This port refuses to trade with you because you are at <span class="big bold red">WAR!</span>');
51
		}
52
53
		// does the port actually buy or sell this good?
54
		if (!$port->hasGood($good_id)) {
55
			create_error('I don\'t trade in that good.');
56
		}
57
58
		// check if there are enough left at port
59
		if ($port->getGoodAmount($good_id) < $amount) {
60
			create_error('I\'m short of ' . $good_name . '. So I\'m not going to sell you ' . $amount . ' pcs.');
61
		}
62
63
		$transaction = $port->getGoodTransaction($good_id);
64
65
		// does we have what we are going to sell?
66
		if ($transaction === TransactionType::Sell && $amount > $ship->getCargo($good_id)) {
67
			create_error('Scanning your ship indicates you don\'t have ' . $amount . ' pcs. of ' . $good_name . '!');
68
		}
69
70
		// check if we have enough room for the thing we are going to buy
71
		if ($transaction === TransactionType::Buy && $amount > $ship->getEmptyHolds()) {
72
			create_error('Scanning your ship indicates you don\'t have enough free cargo bays!');
73
		}
74
75
		// get relations for us (global + personal)
76
		$relations = $player->getRelation($port->getRaceID());
77
78
		$ideal_price = $this->idealPrice ?? $port->getIdealPrice($good_id, $transaction, $amount, $relations);
79
		$offered_price = $this->offeredPrice ?? $port->getOfferPrice($ideal_price, $relations, $transaction);
80
81
		// nothing should happen here but just to avoid / by 0
82
		if ($ideal_price == 0 || $offered_price == 0) {
83
			create_error('Port calculation error...buy more goods.');
84
		}
85
86
		$stealing = Request::get('action', '') === TransactionType::STEAL;
0 ignored issues
show
Bug introduced by
The constant Smr\TransactionType::STEAL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
87
88
		if (!$stealing && $this->bargainNumber === 0) {
89
			$container = new ShopGoodsNegotiate(
90
				goodID: $this->goodID,
91
				amount: $amount,
92
				bargainNumber: $this->bargainNumber,
93
				bargainPrice: $offered_price,
94
				offeredPrice: $offered_price,
95
				idealPrice: $ideal_price
96
			);
97
			$container->go();
98
		}
99
100
		if ($stealing) {
101
			$bargain_price = 0;
102
		} else {
103
			$bargain_price = $this->bargainPrice ?? Request::getInt('bargain_price');
104
			if ($bargain_price <= 0) {
105
				create_error('You must enter an amount > 0!');
106
			}
107
		}
108
109
		// check if the guy has enough money
110
		if ($transaction === TransactionType::Buy && $player->getCredits() < $bargain_price) {
111
			create_error('You don\'t have enough credits!');
112
		}
113
114
		if ($stealing) {
115
			if (!$ship->isUnderground()) {
116
				throw new Exception('Player tried to steal in a non-underground ship!');
117
			}
118
			if ($transaction !== TransactionType::Buy) {
119
				throw new Exception('Player tried to steal a good the port does not sell!');
120
			}
121
122
			// Small chance to get caught stealing
123
			$catchChancePercent = $port->getMaxLevel() - $port->getLevel() + 1;
124
			if (rand(1, 100) <= $catchChancePercent) {
125
				$fine = $ideal_price * ($port->getLevel() + 1);
126
				// Don't take the trader all the way to 0 credits
127
				$newCredits = max(5000, $player->getCredits() - $fine);
128
				$player->setCredits($newCredits);
129
				$player->decreaseAlignment(5);
130
				$player->decreaseRelationsByTrade($amount, $port->getRaceID());
131
132
				$fineMessage = '<span class="red">A Federation patrol caught you loading stolen goods onto your ship!<br />The stolen goods have been confiscated and you have been fined ' . number_format($fine) . ' credits.</span>';
133
				$container = new ShopGoods($fineMessage);
134
				$container->go();
135
			}
136
		}
137
138
		// can we accept the current price?
139
		if ($stealing ||
140
			  ($transaction === TransactionType::Buy && $bargain_price >= $ideal_price) ||
141
			  ($transaction === TransactionType::Sell && $bargain_price <= $ideal_price)) {
142
143
			// base xp is the amount you would get for a perfect trade.
144
			// this is the absolut max. the real xp can only be smaller.
145
			$base_xp = SmrPort::getBaseExperience($amount, $port->getGoodDistance($good_id));
146
147
			// if offered equals ideal we get a problem (division by zero)
148
			if ($stealing) {
149
				$expPercent = 1; // stealing gives full exp
150
			} else {
151
				$expPercent = $port->calculateExperiencePercent($ideal_price, $bargain_price, $transaction);
152
			}
153
			$gained_exp = IRound($expPercent * $base_xp);
0 ignored issues
show
Bug introduced by
The function IRound was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

153
			$gained_exp = /** @scrutinizer ignore-call */ IRound($expPercent * $base_xp);
Loading history...
154
155
			$portGood = Globals::getGood($good_id);
156
			if ($stealing) {
157
				$msg_transaction = 'stolen';
158
				$ship->increaseCargo($good_id, $amount);
159
				$player->increaseHOF($amount, ['Trade', 'Goods', 'Stolen'], HOF_ALLIANCE);
160
				$player->increaseHOF($gained_exp, ['Trade', 'Experience', 'Stealing'], HOF_PUBLIC);
161
				$port->stealGoods($portGood, $amount);
0 ignored issues
show
Bug introduced by
$amount of type double is incompatible with the type integer expected by parameter $goodsTraded of AbstractSmrPort::stealGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

161
				$port->stealGoods($portGood, /** @scrutinizer ignore-type */ $amount);
Loading history...
162
			} elseif ($transaction === TransactionType::Buy) {
163
				$msg_transaction = 'bought';
164
				$ship->increaseCargo($good_id, $amount);
165
				$player->decreaseCredits($bargain_price);
166
				$player->increaseHOF($amount, ['Trade', 'Goods', 'Bought'], HOF_ALLIANCE);
167
				$player->increaseHOF($gained_exp, ['Trade', 'Experience', 'Buying'], HOF_PUBLIC);
168
				$player->decreaseHOF($bargain_price, ['Trade', 'Money', 'Profit'], HOF_PUBLIC);
169
				$player->increaseHOF($bargain_price, ['Trade', 'Money', 'Buying'], HOF_PUBLIC);
170
				$port->buyGoods($portGood, $amount, $ideal_price, $bargain_price, $gained_exp);
0 ignored issues
show
Bug introduced by
$amount of type double is incompatible with the type integer expected by parameter $goodsTraded of AbstractSmrPort::buyGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

170
				$port->buyGoods($portGood, /** @scrutinizer ignore-type */ $amount, $ideal_price, $bargain_price, $gained_exp);
Loading history...
Bug introduced by
$gained_exp of type double is incompatible with the type integer expected by parameter $exp of AbstractSmrPort::buyGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

170
				$port->buyGoods($portGood, $amount, $ideal_price, $bargain_price, /** @scrutinizer ignore-type */ $gained_exp);
Loading history...
Bug introduced by
$bargain_price of type double is incompatible with the type integer expected by parameter $bargainPrice of AbstractSmrPort::buyGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

170
				$port->buyGoods($portGood, $amount, $ideal_price, /** @scrutinizer ignore-type */ $bargain_price, $gained_exp);
Loading history...
171
				$player->increaseRelationsByTrade($amount, $port->getRaceID());
0 ignored issues
show
Bug introduced by
$amount of type double is incompatible with the type integer expected by parameter $numGoods of AbstractSmrPlayer::increaseRelationsByTrade(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

171
				$player->increaseRelationsByTrade(/** @scrutinizer ignore-type */ $amount, $port->getRaceID());
Loading history...
172
			} else { // $transaction === TransactionType::Sell
173
				$msg_transaction = 'sold';
174
				$ship->decreaseCargo($good_id, $amount);
175
				$player->increaseCredits($bargain_price);
176
				$player->increaseHOF($amount, ['Trade', 'Goods', 'Sold'], HOF_ALLIANCE);
177
				$player->increaseHOF($gained_exp, ['Trade', 'Experience', 'Selling'], HOF_PUBLIC);
178
				$player->increaseHOF($bargain_price, ['Trade', 'Money', 'Profit'], HOF_PUBLIC);
179
				$player->increaseHOF($bargain_price, ['Trade', 'Money', 'Selling'], HOF_PUBLIC);
180
				$port->sellGoods($portGood, $amount, $gained_exp);
0 ignored issues
show
Bug introduced by
$gained_exp of type double is incompatible with the type integer expected by parameter $exp of AbstractSmrPort::sellGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

180
				$port->sellGoods($portGood, $amount, /** @scrutinizer ignore-type */ $gained_exp);
Loading history...
Bug introduced by
$amount of type double is incompatible with the type integer expected by parameter $goodsTraded of AbstractSmrPort::sellGoods(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

180
				$port->sellGoods($portGood, /** @scrutinizer ignore-type */ $amount, $gained_exp);
Loading history...
181
				$player->increaseRelationsByTrade($amount, $port->getRaceID());
182
			}
183
184
			$player->increaseHOF($gained_exp, ['Trade', 'Experience', 'Total'], HOF_PUBLIC);
185
			$player->increaseHOF(1, ['Trade', 'Results', 'Success'], HOF_PUBLIC);
186
187
			// log action
188
			$logAction = $stealing ? TransactionType::STEAL : $transaction->value;
189
			$player->log(LOG_TYPE_TRADING, $logAction . 's ' . $amount . ' ' . $good_name . ' for ' . $bargain_price . ' credits and ' . $gained_exp . ' experience');
190
191
			$player->increaseExperience($gained_exp);
0 ignored issues
show
Bug introduced by
$gained_exp of type double is incompatible with the type integer expected by parameter $experience of AbstractSmrPlayer::increaseExperience(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

191
			$player->increaseExperience(/** @scrutinizer ignore-type */ $gained_exp);
Loading history...
192
193
			//will use these variables in current sector and port after successful trade
194
			$tradeMessage = 'You have just ' . $msg_transaction . ' <span class="yellow">' . $amount . '</span> ' . pluralise($amount, 'unit', false) . ' of <span class="yellow">' . $good_name . '</span>';
195
			if ($bargain_price > 0) {
196
				$tradeMessage .= ' for <span class="creds">' . $bargain_price . '</span> ' . pluralise($bargain_price, 'credit', false) . '.';
197
			}
198
199
			if ($gained_exp > 0) {
200
				if ($stealing) {
201
					$qualifier = 'cunning';
202
				} elseif ($gained_exp < $base_xp * 0.25) {
203
					$qualifier = 'novice';
204
				} elseif ($gained_exp < $base_xp * 0.5) {
205
					$qualifier = 'mediocre';
206
				} elseif ($gained_exp < $base_xp * 0.75) {
207
					$qualifier = 'respectable';
208
				} elseif ($gained_exp < IRound($base_xp)) {
209
					$qualifier = 'excellent';
210
				} else {
211
					$qualifier = 'peerless';
212
				}
213
				$skill = $stealing ? 'thievery' : 'trading';
214
				$tradeMessage .= '<br />Your ' . $qualifier . ' ' . $skill . ' skills have earned you <span class="exp">' . $gained_exp . ' </span> ' . pluralise($gained_exp, 'experience point', false) . '!';
215
			}
216
217
			if ($ship->getEmptyHolds() == 0) {
218
				$container = new CurrentSector(tradeMessage: $tradeMessage);
219
			} else {
220
				$container = new ShopGoods($tradeMessage);
221
			}
222
		} else {
223
			// lose relations for bad bargain
224
			$player->decreaseRelationsByTrade($amount, $port->getRaceID());
225
			$player->increaseHOF(1, ['Trade', 'Results', 'Fail'], HOF_PUBLIC);
226
227
			// do we have enough of it?
228
			$maxTries = 5;
229
			if ($this->bargainNumber > 1 && rand($this->bargainNumber, $maxTries) >= $maxTries) {
230
				$player->decreaseRelationsByTrade($amount, $port->getRaceID());
231
				$player->increaseHOF(1, ['Trade', 'Results', 'Epic Fail'], HOF_PUBLIC);
232
				create_error('You don\'t want to accept my offer? I\'m sick of you! Get out of here!');
233
			}
234
235
			$port_off = IRound($offered_price * 100 / $ideal_price);
236
			$trader_off = IRound($bargain_price * 100 / $ideal_price);
237
238
			// get relative numbers!
239
			// be careful! one of this value is negative!
240
			$port_off_rel = 100 - $port_off;
241
			$trader_off_rel = 100 - $trader_off;
242
243
			// Should we change the offer price?
244
			// only do something, if we are more off than the trader
245
			if (abs($port_off_rel) > abs($trader_off_rel)) {
246
				// get a random number between
247
				// (port_off) and (100 +/- $trader_off_rel)
248
				if (100 + $trader_off_rel < $port_off) {
249
					$offer_modifier = rand(100 + $trader_off_rel, $port_off);
250
				} else {
251
					$offer_modifier = rand($port_off, 100 + $trader_off_rel);
252
				}
253
				$offered_price = IRound($ideal_price * $offer_modifier / 100);
254
			}
255
256
			// transfer values to next page
257
			$container = new ShopGoodsNegotiate(
258
				goodID: $this->goodID,
259
				amount: $amount,
260
				bargainNumber: $this->bargainNumber,
261
				bargainPrice: $bargain_price,
262
				offeredPrice: $offered_price,
263
				idealPrice: $ideal_price
264
			);
265
		}
266
267
		// only take turns if they bargained
268
		if (!$stealing) {
269
			$player->takeTurns(TURNS_PER_TRADE, TURNS_PER_TRADE);
270
		}
271
272
		// go to next page
273
		$container->go();
274
	}
275
276
}
277