예제 #1
0
파일: phase.go 프로젝트: arlm/diplicity
func (self *Phase) Options(nation dip.Nation) (result dip.Options, err error) {
	state, err := self.State()
	if err != nil {
		return
	}
	result = state.Phase().Options(state, nation)
	return
}
예제 #2
0
파일: game.go 프로젝트: JorenC/diplicity
func (self *Game) resolve(c common.SkinnyContext, phase *Phase) (err error) {
	// Check that we are in a phase where we CAN resolve
	if self.State != common.GameStateStarted {
		err = fmt.Errorf("%+v is not started", self)
		return
	}
	// Load our members
	members, err := self.Members(c.DB())
	if err != nil {
		return
	}
	// Load the godip state for the phase
	state, err := phase.State()
	if err != nil {
		return
	}
	// Load "now"
	epoch, err := epoch.Get(c.DB())
	if err != nil {
		return
	}
	// Just to limit runaway resolution to 100 phases.
	for i := 0; i < 100; i++ {
		// Resolve the phase!
		if err = state.Next(); err != nil {
			return
		}
		// Load the new godip phase from the state
		nextDipPhase := state.Phase()
		// Create a diplicity phase for the new phase
		nextPhase := &Phase{
			GameId:      self.Id,
			Ordinal:     phase.Ordinal + 1,
			Orders:      map[dip.Nation]map[dip.Province][]string{},
			Resolutions: map[dip.Province]string{},
			Season:      nextDipPhase.Season(),
			Year:        nextDipPhase.Year(),
			Type:        nextDipPhase.Type(),
			Deadline:    epoch + (time.Minute * time.Duration(self.Deadlines[nextDipPhase.Type()])),
		}
		// Set the new phase positions
		var resolutions map[dip.Province]error
		nextPhase.Units, nextPhase.SupplyCenters, nextPhase.Dislodgeds, nextPhase.Dislodgers, nextPhase.Bounces, resolutions = state.Dump()
		// Store the results of the previous godip phase in the previous diplicity phase
		for _, nationOrders := range phase.Orders {
			for prov, _ := range nationOrders {
				if res, found := resolutions[prov]; found && res != nil {
					phase.Resolutions[prov] = res.Error()
				} else {
					phase.Resolutions[prov] = "OK"
				}
			}
		}

		// Commit everyone that doesn't have any orders to give
		waitFor := []*Member{}
		active := []*Member{}
		nonSurrendering := []*Member{}
		for index, _ := range members {
			opts := dip.Options{}
			if opts, err = nextPhase.Options(members[index].Nation); err != nil {
				return
			}
			if err = self.endPhaseConsequences(c, phase, &members[index], opts, &waitFor, &active, &nonSurrendering); err != nil {
				return
			}
		}

		// Mark the old phase as resolved, and save it
		phase.Resolved = true
		if err = c.DB().Set(phase); err != nil {
			return
		}

		// If we have a solo victor, end and return
		if winner := nextDipPhase.Winner(state); winner != nil {
			var winnerMember *Member
			for _, member := range members {
				if member.Nation == *winner {
					winnerMember = &member
					break
				}
			}
			if winnerMember == nil {
				err = fmt.Errorf("None of %+v has nation %#v??", members, *winner)
				return
			}
			if err = self.end(c, nextPhase, members, winnerMember, common.SoloVictory(*winner)); err != nil {
				return
			}
			return
		}

		// End the game now if nobody is active anymore
		if len(active) == 0 {
			if err = self.end(c, nextPhase, members, nil, common.ZeroActiveMembers); err != nil {
				return
			}
			return
		}

		// End the game now if only one player isn't surrendering
		if len(nonSurrendering) == 1 {
			if err = self.end(c, nextPhase, members, nonSurrendering[0], common.SoloVictory(nonSurrendering[0].Nation)); err != nil {
				return
			}
			return
		}

		// Store the next phase
		if err = c.DB().Set(nextPhase); err != nil {
			return
		}

		// If there is anyone we need to wait for, schedule an auto resolve and return here.
		if len(waitFor) > 0 {
			if err = nextPhase.Schedule(c); err != nil {
				return
			}
			nextPhase.SendScheduleEmails(c, self)
			return
		}
		phase = nextPhase
	}
	return
}