File: Clone.cpp

package info (click to toggle)
vcmi 0.99%2Bdfsg%2Bgit20190113.f06c8a87-2
  • links: PTS, VCS
  • area: contrib
  • in suites: bullseye
  • size: 11,136 kB
  • sloc: cpp: 142,615; sh: 315; objc: 248; makefile: 32; ansic: 28; python: 13
file content (132 lines) | stat: -rw-r--r-- 3,508 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * Clone.cpp, part of VCMI engine
 *
 * Authors: listed in file AUTHORS in main folder
 *
 * License: GNU General Public License v2.0 or later
 * Full text of license available in license.txt file, in main folder
 *
 */
#include "StdInc.h"

#include "Clone.h"
#include "Registry.h"
#include "../ISpellMechanics.h"
#include "../../NetPacks.h"
#include "../../battle/CBattleInfoCallback.h"
#include "../../battle/CUnitState.h"
#include "../../serializer/JsonSerializeFormat.h"

static const std::string EFFECT_NAME = "core:clone";

namespace spells
{
namespace effects
{

VCMI_REGISTER_SPELL_EFFECT(Clone, EFFECT_NAME);

Clone::Clone()
	: UnitEffect(),
	maxTier(0)
{
}

Clone::~Clone() = default;

void Clone::apply(BattleStateProxy * battleState, RNG & rng, const Mechanics * m, const EffectTarget & target) const
{
	for(const Destination & dest : target)
	{
		const battle::Unit * clonedStack = dest.unitValue;

		//we shall have all targets to be stacks
		if(!clonedStack)
		{
			battleState->complain("No target stack to clone! Invalid effect target transformation.");
			continue;
		}

		//should not happen, but in theory we might have stack took damage from other effects
		if(clonedStack->getCount() < 1)
			continue;

		auto hex = m->cb->getAvaliableHex(clonedStack->creatureId(), m->casterSide);

		if(!hex.isValid())
		{
			battleState->complain("No place to put new clone!");
			break;
		}

		auto unitId = m->cb->battleNextUnitId();

		battle::UnitInfo info;
		info.id = unitId;
		info.count = clonedStack->getCount();
		info.type = clonedStack->creatureId();
		info.side = m->casterSide;
		info.position = hex;
		info.summoned = true;

		BattleUnitsChanged pack;
		pack.changedStacks.emplace_back(info.id, UnitChanges::EOperation::ADD);
		info.save(pack.changedStacks.back().data);
		battleState->apply(&pack);

		//TODO: use BattleUnitsChanged with UPDATE operation

		BattleUnitsChanged cloneFlags;

		auto cloneUnit = m->cb->battleGetUnitByID(unitId);
		auto cloneState = cloneUnit->acquireState();
		cloneState->cloned = true;
		cloneFlags.changedStacks.emplace_back(cloneState->unitId(), UnitChanges::EOperation::RESET_STATE);
		cloneState->save(cloneFlags.changedStacks.back().data);

		auto originalState = clonedStack->acquireState();
		originalState->cloneID = unitId;
		cloneFlags.changedStacks.emplace_back(originalState->unitId(), UnitChanges::EOperation::RESET_STATE);
		originalState->save(cloneFlags.changedStacks.back().data);

		battleState->apply(&cloneFlags);

		SetStackEffect sse;
		Bonus lifeTimeMarker(Bonus::N_TURNS, Bonus::NONE, Bonus::SPELL_EFFECT, 0, SpellID::CLONE); //TODO: use special bonus type
		lifeTimeMarker.turnsRemain = m->getEffectDuration();
		std::vector<Bonus> buffer;
		buffer.push_back(lifeTimeMarker);
		sse.toAdd.push_back(std::make_pair(unitId, buffer));
		battleState->apply(&sse);
	}
}

bool Clone::isReceptive(const Mechanics * m, const battle::Unit * s) const
{
	int creLevel = s->creatureLevel();
	if(creLevel > maxTier)
		return false;

	//use default algorithm only if there is no mechanics-related problem
	return UnitEffect::isReceptive(m, s);
}

bool Clone::isValidTarget(const Mechanics * m, const battle::Unit * s) const
{
	//can't clone already cloned creature
	if(s->isClone())
		return false;
	//can`t clone if old clone still alive
	if(s->hasClone())
		return false;

	return UnitEffect::isValidTarget(m, s);
}

void Clone::serializeJsonUnitEffect(JsonSerializeFormat & handler)
{
	handler.serializeInt("maxTier", maxTier);
}

}
}