Completed
Pull Request — master (#189)
by Marek
02:07
created

ige.ospace.IAIPiratePlayer   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 259
Duplicated Lines 35.52 %

Importance

Changes 0
Metric Value
eloc 193
dl 92
loc 259
rs 7.4757
c 0
b 0
f 0
wmc 53

17 Methods

Rating   Name   Duplication   Size   Complexity  
A IAIPiratePlayer.register() 15 15 3
B IAIPiratePlayer.setStartingTechnologies() 0 18 6
A IAIPiratePlayer.setStartingPlanet() 0 8 1
B IAIPiratePlayer.init() 0 13 6
A IAIPiratePlayer.processINITPhase() 0 7 3
A IAIPiratePlayer.setStartingShipDesigns() 0 4 1
A IAIPiratePlayer.givePirateTech() 0 3 1
A IAIPiratePlayer.update() 0 20 1
A IAIPiratePlayer.processFINALPhase() 0 12 2
A IAIPiratePlayer.distToNearestPiratePlanet() 0 9 3
A IAIPiratePlayer.getDiplomacyWith() 14 14 2
F IAIPiratePlayer.stealTechs() 26 26 12
A IAIPiratePlayer.processDIPLPhase() 0 4 1
B IAIPiratePlayer.forceAllyWithEDEN() 26 26 3
A IAIPiratePlayer.capturePlanet() 11 11 3
A IAIPiratePlayer.processRSRCHPhase() 0 4 1
A IAIPiratePlayer.isPactActive() 0 9 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ige.ospace.IAIPiratePlayer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#
2
#  Copyright 2001 - 2016 Ludek Smid [http://www.ospace.net/]
3
#
4
#  This file is part of Outer Space.
5
#
6
#  Outer Space is free software; you can redistribute it and/or modify
7
#  it under the terms of the GNU General Public License as published by
8
#  the Free Software Foundation; either version 2 of the License, or
9
#  (at your option) any later version.
10
#
11
#  Outer Space is distributed in the hope that it will be useful,
12
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
#  GNU General Public License for more details.
15
#
16
#  You should have received a copy of the GNU General Public License
17
#  along with Outer Space; if not, write to the Free Software
18
#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
#
20
import math
21
import random
22
import sys
23
import time
24
25
import Rules
26
import Utils
27
28
from Const import *
29
from ige import log
30
from ige.IDataHolder import IDataHolder
31
from ige.IObject import public
32
from IPlayer import IPlayer
33
34
class IAIPiratePlayer(IPlayer):
35
36
    typeID = T_AIPIRPLAYER
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_AIPIRPLAYER does not seem to be defined.
Loading history...
37
    resignTo = T_PIRPLAYER
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_PIRPLAYER does not seem to be defined.
Loading history...
38
    forums = {"INBOX": 56, "OUTBOX": 56, "EVENTS": 0}
39
40
    def init(self, obj):
41
        IPlayer.init(self, obj)
42
        #
43
        obj.name = u'Pirate'
44
        obj.login = '*'
45
        #
46
        obj.pirateFame = 0
47
        obj.techLevel = 99
48
        # grant all TL1 ship techs except for colony module(s)
49
        for techID in Rules.techs:
50
            tech = Rules.techs[techID]
51
            if tech.level == 1 and (tech.isShipEquip or tech.isShipHull) and not tech.unpackStruct:
52
                obj.techs[techID] = Rules.techMaxImprovement
53
54 View Code Duplication
    def register(self, tran, obj, galaxyID):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
55
        log.debug("Registering player", obj.oid)
56
        counter = 1
57
        while 1:
58
            obj.name = u'Pirate faction %d' % counter
59
            obj.login = '*AIP*pirate%d' % counter
60
            if galaxyID in tran.gameMngr.accountGalaxies(obj.login):
61
                counter += 1
62
                continue
63
            tran.gameMngr.registerPlayer(obj.login, obj, obj.oid)
64
            tran.db[OID_UNIVERSE].players.append(obj.oid)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_UNIVERSE does not seem to be defined.
Loading history...
65
            tran.gameMngr.clientMngr.createAIAccount(obj.login, obj.name, 'ais_pirate')
66
            break
67
        # grant techs and so on
68
        self.cmd(obj).update(tran, obj)
69
70
    @staticmethod
71
    def setStartingPlanet(tran, planet):
72
        planet.plSlots = max(planet.plSlots, 2)
73
        planet.plMaxSlots = max(planet.plMaxSlots, 2)
74
        planet.plDiameter = max(planet.plDiameter, 2000)
75
        planet.slots.append(Utils.newStructure(tran, Rules.Tech.PIRATEBASE, planet.owner, STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable STRUCT_STATUS_ON does not seem to be defined.
Loading history...
76
        planet.slots.append(Utils.newStructure(tran, Rules.Tech.PIRATEDEN, planet.owner, STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio))
77
        planet.storPop = 6000
78
79
    @staticmethod
80
    def setStartingTechnologies(obj):
81
        for techID in Rules.techs:
82
            tech = Rules.techs[techID]
83
            if tech.level == 1 and (tech.isShipEquip or tech.isShipHull) and not tech.unpackStruct:
84
                obj.techs[techID] = Rules.techMaxImprovement
85
        obj.techs[Rules.Tech.EMCANNONTUR] = Rules.techMaxImprovement
86
        obj.techs[Rules.Tech.SSROCKET2] = Rules.techMaxImprovement
87
        obj.techs[Rules.Tech.TORPEDO] = Rules.techMaxImprovement
88
        obj.techs[Rules.Tech.PIRATEBASE] = Rules.techMaxImprovement
89
        obj.techs[Rules.Tech.PIRATEDEN] = Rules.techMaxImprovement
90
        obj.techs[Rules.Tech.PIRATESD] = Rules.techMaxImprovement
91
        obj.techs[Rules.Tech.PIRATEBREWERY] = Rules.techMaxImprovement
92
        obj.techs[Rules.Tech.PIRATEPRISON] = Rules.techMaxImprovement
93
        obj.techs[Rules.Tech.PIRATEPRISON] = Rules.techMaxImprovement
94
        obj.techs[Rules.Tech.PIRSMCOLONYMOD] = Rules.techMaxImprovement
95
        obj.techs[Rules.Tech.PIRATEFTLENG] = Rules.techMaxImprovement
96
        obj.techs[Rules.Tech.PIRCOLONYMOD] = Rules.techMaxImprovement
97
98
    @staticmethod
99
    def setStartingShipDesigns(obj):
100
        # these are generated by the AI itself
101
        pass
102
103
    def processINITPhase(self, tran, obj, data):
104
        IPlayer.processINITPhase(self, tran, obj, data)
105
        # TODO -- remove following lines
106
        obj.lastLogin = time.time()
107
        # delete itself if there are no fleets and planets
108
        if not obj.fleets and not obj.planets:
109
            self.cmd(obj).delete(tran, obj)
110
111
    def update(self, tran, obj):
112
        obj.techLevel = 99
113
        obj.race = "p"
114
        # call super method
115
        IPlayer.update(self, tran, obj)
116
        #
117
        obj.techLevel = 99
118
        # grant technologies
119
        obj.techs[Rules.Tech.EMCANNONTUR] = Rules.techMaxImprovement
120
        obj.techs[Rules.Tech.SSROCKET2] = Rules.techMaxImprovement
121
        obj.techs[Rules.Tech.TORPEDO] = Rules.techMaxImprovement
122
        # grant special technologies
123
        obj.techs[Rules.Tech.PIRATEBASE] = Rules.techMaxImprovement
124
        obj.techs[Rules.Tech.PIRATEDEN] = Rules.techMaxImprovement
125
        obj.techs[Rules.Tech.PIRATESD] = Rules.techMaxImprovement
126
        obj.techs[Rules.Tech.PIRATEBREWERY] = Rules.techMaxImprovement
127
        obj.techs[Rules.Tech.PIRATEPRISON] = Rules.techMaxImprovement
128
        obj.techs[Rules.Tech.PIRSMCOLONYMOD] = Rules.techMaxImprovement
129
        obj.techs[Rules.Tech.PIRATEFTLENG] = Rules.techMaxImprovement
130
        obj.techs[Rules.Tech.PIRCOLONYMOD] = Rules.techMaxImprovement
131
132 View Code Duplication
    def getDiplomacyWith(self, tran, obj, playerID):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
133
        if obj.oid == playerID:
134
            return REL_UNITY
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable REL_UNITY does not seem to be defined.
Loading history...
135
        # this AI battles with overyone
136
        # make default
137
        dipl = IDataHolder()
138
        dipl.type = T_DIPLREL
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_DIPLREL does not seem to be defined.
Loading history...
139
        dipl.pacts = {}
140
        dipl.relation = REL_ENEMY
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable REL_ENEMY does not seem to be defined.
Loading history...
141
        dipl.relChng = 0
142
        dipl.lastContact = tran.db[OID_UNIVERSE].turn
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_UNIVERSE does not seem to be defined.
Loading history...
143
        dipl.contactType = CONTACT_NONE
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable CONTACT_NONE does not seem to be defined.
Loading history...
144
        dipl.stats = None
145
        return dipl
146
147
    def isPactActive(self, tran, obj, partnerID, pactID):
148
        if partnerID == OID_NONE:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_NONE does not seem to be defined.
Loading history...
149
            return 0
150
        partner = tran.db.get(partnerID, None)
151
        if partner.type == T_AIEDENPLAYER:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_AIEDENPLAYER does not seem to be defined.
Loading history...
152
            # force the peace!
153
            if pactID in (PACT_ALLOW_CIVILIAN_SHIPS, PACT_ALLOW_MILITARY_SHIPS):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable PACT_ALLOW_MILITARY_SHIPS does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable PACT_ALLOW_CIVILIAN_SHIPS does not seem to be defined.
Loading history...
154
                return PACT_ACTIVE
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable PACT_ACTIVE does not seem to be defined.
Loading history...
155
        return 0
156
157
    @public(AL_ADMIN)
158
    def processDIPLPhase(self, tran, obj, data):
159
        self.forceAllyWithEDEN(tran,obj)
160
        IPlayer.processDIPLPhase(self,tran, obj, data)
161
162
    @public(AL_ADMIN)
163
    def processFINALPhase(self, tran, obj, data):
164
        obj.govPwr = Rules.pirateGovPwr
165
        IPlayer.processFINALPhase(self, tran, obj, data)
166
        # get fame every 1:00 turns
167
        if tran.db[OID_UNIVERSE].turn % Rules.turnsPerDay == 0:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_UNIVERSE does not seem to be defined.
Loading history...
168
            Utils.sendMessage(tran, obj, MSG_GAINED_FAME, obj.oid, Rules.pirateSurvivalFame)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_GAINED_FAME does not seem to be defined.
Loading history...
169
            obj.pirateFame += Rules.pirateSurvivalFame
170
        # fix goverment power
171
        obj.govPwrCtrlRange = 10000
172
        # bonus for gained fame
173
        obj.prodEff += obj.pirateFame / 100.0
174
175
    @public(AL_ADMIN)
176
    def processRSRCHPhase(self, tran, obj, data):
177
        # do not research anything
178
        return
179
180
    def distToNearestPiratePlanet(self,tran,obj,srcObj):
181
        # srcObj can be Planet or System type
182
        dist = sys.maxint
183
        for objID in obj.planets:
184
            pirPl = tran.db[objID]
185
            d = math.hypot(srcObj.x - pirPl.x, srcObj.y - pirPl.y)
186
            if d < dist:
187
                dist = d
188
        return dist
189
190 View Code Duplication
    def capturePlanet(self, tran, obj, planet):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
191
        # find distance to closes pirate's planet
192
        dist = self.distToNearestPiratePlanet(tran,obj,planet)
193
        if random.random() <= Rules.pirateGainFamePropability(dist):
194
            log.debug(obj.oid, "Pirate captured planet + fame", dist, planet.oid)
195
            obj.pirateFame += Rules.pirateCaptureInRangeFame
196
            Utils.sendMessage(tran, obj, MSG_GAINED_FAME, planet.oid, Rules.pirateCaptureInRangeFame)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_GAINED_FAME does not seem to be defined.
Loading history...
197
        elif random.random() <= Rules.pirateLoseFameProbability(dist):
198
            log.debug(obj.oid, "Pirate captured planet OUT OF range", dist, planet.oid)
199
            obj.pirateFame += Rules.pirateCaptureOutOfRangeFame
200
            Utils.sendMessage(tran, obj, MSG_LOST_FAME, planet.oid, Rules.pirateCaptureOutOfRangeFame)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_LOST_FAME does not seem to be defined.
Loading history...
201
202 View Code Duplication
    def stealTechs(self, tran, piratePlayer, oldOwnerID, stealFromPlanetID):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
203
        if oldOwnerID == OID_NONE:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_NONE does not seem to be defined.
Loading history...
204
            return
205
        log.debug(piratePlayer.oid, "IPiratePlayer stealing techs")
206
        oldOwner = tran.db[oldOwnerID]
207
        canSteal = Rules.pirateCanStealImprovements
208
        while canSteal > 0:
209
            stealed = False
210
            for techID in oldOwner.techs:
211
                tech = Rules.techs[techID]
212
                if oldOwner.techs[techID] <= piratePlayer.techs.get(techID, 0):
213
                    # skip techs that are already stealed
214
                    continue
215
                if (tech.isShipEquip or tech.isShipHull) and not tech.unpackStruct and canSteal > 0:
216
                    self.givePirateTech(tran, piratePlayer, oldOwner, techID, stealFromPlanetID)
217
                    canSteal -= 1
218
                    stealed = True
219
                if tech.isProject and canSteal > 0:
220
                    self.givePirateTech(tran, piratePlayer, oldOwner, techID, stealFromPlanetID)
221
                    canSteal -= 1
222
                    stealed = True
223
            if not stealed:
224
                break
225
        # update techs
226
        self.cmd(piratePlayer).update(tran, piratePlayer)
227
        return
228
229
    def givePirateTech(self, tran, piratePlayer, oldOwner, techID, stealFromPlanetID):
230
        piratePlayer.techs[techID] = min(piratePlayer.techs.get(techID, 0) + 1, oldOwner.techs[techID])
231
        Utils.sendMessage(tran, piratePlayer, MSG_GAINED_TECH, stealFromPlanetID, (techID, piratePlayer.techs[techID]))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_GAINED_TECH does not seem to be defined.
Loading history...
232
233 View Code Duplication
    def forceAllyWithEDEN(self,tran,obj):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
234
        for partyID in obj.diplomacyRels.keys():
235
            party = tran.db.get(partyID, None)
236
            if party.type == T_AIEDENPLAYER:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_AIEDENPLAYER does not seem to be defined.
Loading history...
237
                diplSelf = obj.diplomacyRels.get(party.oid, None)
238
                log.debug("Allying Pirate with EDEN (forced)", obj.oid, partyID)
239
                diplEDEN = IDataHolder()
240
                diplEDEN.type = T_DIPLREL
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_DIPLREL does not seem to be defined.
Loading history...
241
                diplEDEN.pacts = {
242
                    PACT_ALLOW_CIVILIAN_SHIPS: [PACT_ACTIVE, PACT_ALLOW_CIVILIAN_SHIPS],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable PACT_ALLOW_CIVILIAN_SHIPS does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable PACT_ACTIVE does not seem to be defined.
Loading history...
243
                    PACT_ALLOW_MILITARY_SHIPS: [PACT_ACTIVE, PACT_ALLOW_MILITARY_SHIPS]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable PACT_ALLOW_MILITARY_SHIPS does not seem to be defined.
Loading history...
244
                }
245
                diplEDEN.relation = REL_FRIENDLY
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable REL_FRIENDLY does not seem to be defined.
Loading history...
246
                diplEDEN.relChng = 0
247
                diplEDEN.lastContact = tran.db[OID_UNIVERSE].turn
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_UNIVERSE does not seem to be defined.
Loading history...
248
                diplEDEN.contactType = CONTACT_STATIC
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable CONTACT_STATIC does not seem to be defined.
Loading history...
249
                diplEDEN.stats = None
250
251
                diplSelf.relation = REL_FRIENDLY
252
                diplSelf.pacts = {
253
                    PACT_ALLOW_CIVILIAN_SHIPS: [PACT_ACTIVE, PACT_ALLOW_CIVILIAN_SHIPS],
254
                    PACT_ALLOW_MILITARY_SHIPS: [PACT_ACTIVE, PACT_ALLOW_MILITARY_SHIPS]
255
                }
256
257
                obj.diplomacyRels[party.oid] = diplSelf
258
                party.diplomacyRels[obj.oid] = diplEDEN
259
260
261