|
1 /* $Id$ */ |
|
2 |
|
3 /** @file ai_transactionmode.cpp class to switch the AI to Transaction mode */ |
|
4 |
|
5 #include "ai_transactionmode.hpp" |
|
6 #include "ai_execmode.hpp" |
|
7 #include "../../command.h" |
|
8 #include "../../debug.h" |
|
9 #include <stack> |
|
10 |
|
11 bool AITransactionMode::ModeProc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, int32 costs) |
|
12 { |
|
13 AITransactionMode *instance = (AITransactionMode *)AIObject::GetDoCommandModeInstance(); |
|
14 /* Don't record if we are stopped */ |
|
15 if (instance->stopped) return false; |
|
16 AITransactionModeCommand command; |
|
17 |
|
18 /* Store all params in a nice list, so we can execute them later */ |
|
19 command.tile = tile; |
|
20 command.p1 = p1; |
|
21 command.p2 = p2; |
|
22 command.flags = flags; |
|
23 command.procc = procc; |
|
24 command.text = (_cmd_text == NULL) ? NULL : strdup(_cmd_text); |
|
25 instance->command_stack.push(command); |
|
26 instance->costs += costs; |
|
27 |
|
28 /* Now we return 'false', as we don't want to execute the commands just yet */ |
|
29 return false; |
|
30 } |
|
31 |
|
32 AITransactionMode::AITransactionMode() |
|
33 { |
|
34 this->costs = 0; |
|
35 this->stopped = false; |
|
36 this->last_mode = this->GetDoCommandMode(); |
|
37 this->last_instance = this->GetDoCommandModeInstance(); |
|
38 this->SetDoCommandMode(&AITransactionMode::ModeProc, this); |
|
39 } |
|
40 |
|
41 AITransactionMode::~AITransactionMode() |
|
42 { |
|
43 this->SetDoCommandMode(this->last_mode, this->last_instance); |
|
44 |
|
45 /* Clean up the command_stack nicely (as in: free the cmd_text) */ |
|
46 AITransactionModeCommand command; |
|
47 while (!this->command_stack.empty()) { |
|
48 command = this->command_stack.front(); |
|
49 free(command.text); |
|
50 this->command_stack.pop(); |
|
51 } |
|
52 |
|
53 /* Clean up the reverse_stack too */ |
|
54 while (!this->reverse_stack.empty()) { |
|
55 command = this->reverse_stack.front(); |
|
56 free(command.text); |
|
57 this->reverse_stack.pop(); |
|
58 } |
|
59 } |
|
60 |
|
61 bool AITransactionMode::Execute() |
|
62 { |
|
63 /* Make sure we are stopped */ |
|
64 this->Stop(); |
|
65 |
|
66 /* Switch to a forced execute mode */ |
|
67 AIExecMode exec; |
|
68 |
|
69 /* Reverse stack should be empty */ |
|
70 assert(this->reverse_stack.empty()); |
|
71 |
|
72 AITransactionModeCommand command; |
|
73 while (!this->command_stack.empty()) { |
|
74 command = this->command_stack.front(); |
|
75 _cmd_text = command.text; |
|
76 /* Make sure we return 'false' if the command fails to execute. This allows rollback of failed builds. */ |
|
77 if (!this->DoCommand(command.tile, command.p1, command.p2, command.flags, command.procc)) return false; |
|
78 /* Add the command to the reverse stack */ |
|
79 this->reverse_stack.push(command); |
|
80 /* Remove the item from the list */ |
|
81 this->command_stack.pop(); |
|
82 } |
|
83 |
|
84 /* Everything went okay, clean the reverse stack */ |
|
85 while (!this->reverse_stack.empty()) { |
|
86 command = this->reverse_stack.front(); |
|
87 free(command.text); |
|
88 this->reverse_stack.pop(); |
|
89 } |
|
90 |
|
91 /* Reverse stack should be empty again */ |
|
92 assert(this->reverse_stack.empty()); |
|
93 |
|
94 return true; |
|
95 } |
|
96 |
|
97 void AITransactionMode::Stop() |
|
98 { |
|
99 this->stopped = true; |
|
100 } |
|
101 |
|
102 void AITransactionMode::Rollback() |
|
103 { |
|
104 AITransactionModeCommand command; |
|
105 |
|
106 DEBUG(ai, 0, "AITransactionMode::Rollback is not yet implemented"); |
|
107 return; |
|
108 |
|
109 while (!this->reverse_stack.empty()) { |
|
110 command = this->reverse_stack.front(); |
|
111 _cmd_text = command.text; |
|
112 |
|
113 /* Find the reverse, and issue it */ |
|
114 /* TODO -- Make a table which reverses every command.procc */ |
|
115 this->DoCommand(command.tile, command.p1, command.p2, command.flags, command.procc); |
|
116 |
|
117 /* Remove the item from the list */ |
|
118 this->reverse_stack.pop(); |
|
119 } |
|
120 } |
|
121 |
|
122 int32 AITransactionMode::GetCosts() |
|
123 { |
|
124 return this->costs; |
|
125 } |
|
126 |
|
127 void AITransactionMode::Append(AITransactionMode *transaction) |
|
128 { |
|
129 /* Can't append to myself! */ |
|
130 if (transaction == this) return; |
|
131 |
|
132 /* Simply move the queue from transaction to ourself */ |
|
133 while (!transaction->command_stack.empty()) { |
|
134 this->command_stack.push(transaction->command_stack.front()); |
|
135 transaction->command_stack.pop(); |
|
136 } |
|
137 } |