~widelands-dev/widelands/trunk

« back to all changes in this revision

Viewing changes to data/maps/MP_Scenarios/Smugglers.wmf/scripting/smuggling.lua

Merged lp:~widelands-dev/widelands/bug-1751440-smugglers-desync-single-coroutine:
Fixed desync in the Smugglers scenario by using a single coroutine and selecting the wares round robin. The scenario can now be played with any tribe combination as soon as we implement the selection code in the UI.

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
 
5
5
include "scripting/messages.lua"
6
6
 
 
7
-- Init routes
 
8
route_descrs = {
 
9
   {
 
10
      value = 2,
 
11
      send = map:get_field(35, 52):region(2),
 
12
      recv = map:get_field(96, 77):region(2),
 
13
      sending_warehouse = nil,
 
14
      receiving_warehouse = nil,
 
15
      wares = {}
 
16
   },
 
17
   {
 
18
      value = 2,
 
19
      send = map:get_field(98, 55):region(2),
 
20
      recv = map:get_field(34, 76):region(2),
 
21
      sending_warehouse = nil,
 
22
      receiving_warehouse = nil,
 
23
      wares = {}
 
24
   },
 
25
 
 
26
   {
 
27
      value = 3,
 
28
      send = map:get_field(64, 57):region(2),
 
29
      recv = map:get_field(78, 73):region(2),
 
30
      sending_warehouse = nil,
 
31
      receiving_warehouse = nil,
 
32
      wares = {}
 
33
   },
 
34
   {
 
35
      value = 3,
 
36
      send = map:get_field(77, 58):region(2),
 
37
      recv = map:get_field(65, 72):region(2),
 
38
      sending_warehouse = nil,
 
39
      receiving_warehouse = nil,
 
40
      wares = {}
 
41
   },
 
42
 
 
43
   {
 
44
      value = 2,
 
45
      send = map:get_field(62, 93):region(2),
 
46
      recv = map:get_field(78, 34):region(2),
 
47
      sending_warehouse = nil,
 
48
      receiving_warehouse = nil,
 
49
      wares = {}
 
50
   },
 
51
   {
 
52
      value = 2,
 
53
      send = map:get_field(80, 95):region(2),
 
54
      recv = map:get_field(63, 29):region(2),
 
55
      sending_warehouse = nil,
 
56
      receiving_warehouse = nil,
 
57
      wares = {}
 
58
   },
 
59
   {
 
60
      value = 2,
 
61
      send = map:get_field(18, 66):region(2),
 
62
      recv = map:get_field(121, 61):region(2),
 
63
      sending_warehouse = nil,
 
64
      receiving_warehouse = nil,
 
65
      wares = {}
 
66
   },
 
67
   {
 
68
      value = 2,
 
69
      send = map:get_field(124, 72):region(2),
 
70
      recv = map:get_field(19, 57):region(2),
 
71
      sending_warehouse = nil,
 
72
      receiving_warehouse = nil,
 
73
      wares = {}
 
74
   }
 
75
}
 
76
 
7
77
-- =================
8
78
-- Helper functions
9
79
-- =================
35
105
   game_over_done = true
36
106
end
37
107
 
38
 
function do_smuggling(route_descr, recv_plr, send_plr, recv_whf, send_whf)
39
 
   while 1 do
 
108
function do_smuggling()
 
109
   while true do
40
110
      sleep(10000) -- Sleep 10s
41
 
 
42
111
      if points[1] >= points_to_win or
43
112
         points[2] >= points_to_win
44
113
      then
45
114
         do_game_over()
46
 
         break
47
 
      end
48
 
 
49
 
      if not send_whf.immovable or
50
 
         send_whf.immovable.descr.type_name ~= "warehouse" or
51
 
         send_whf.immovable.owner ~= send_plr or
52
 
         not recv_whf.immovable or
53
 
         recv_whf.immovable.descr.type_name ~= "warehouse" or
54
 
         recv_whf.immovable.owner ~= recv_plr
55
 
      then
56
 
         send_to_all(smuggling_route_broken:bformat(
57
 
            (ngettext("%i point", "%i points", route_descr.value)):format(route_descr.value), recv_plr.name, send_plr.name)
58
 
         )
59
 
         run(wait_for_established_route, route_descr)
60
 
         break
61
 
      end
62
 
 
63
 
      -- Warp one ware
64
 
      local wares = send_whf.immovable:get_wares("all")
65
 
      local wn = {}
66
 
      for name,count in pairs(wares) do
67
 
         if count > 0 then
68
 
            wn[#wn + 1] = name
 
115
         return
 
116
      end
 
117
 
 
118
      for idx, route_descr in ipairs(route_descrs) do
 
119
         if (route_descr.sending_warehouse ~= nil and route_descr.receiving_warehouse ~= nil) then
 
120
            print("NOCOM do smuggling for route " .. idx)
 
121
 
 
122
            local send_plr = route_descr.sending_warehouse.owner
 
123
            local recv_plr = route_descr.receiving_warehouse.owner
 
124
            local send_whf = route_descr.sending_warehouse.fields[1]
 
125
            local recv_whf = route_descr.receiving_warehouse.fields[1]
 
126
 
 
127
            -- Ensure that the warehouses are still there and owned by the same player
 
128
            if not send_whf.immovable or
 
129
               send_whf.immovable.descr.type_name ~= "warehouse" or
 
130
               send_whf.immovable.owner ~= send_plr or
 
131
               not recv_whf.immovable or
 
132
               recv_whf.immovable.descr.type_name ~= "warehouse" or
 
133
               recv_whf.immovable.owner ~= recv_plr
 
134
            then
 
135
               send_to_all(smuggling_route_broken:bformat(
 
136
                  (ngettext("%i point", "%i points", route_descr.value)):format(route_descr.value), recv_plr.name, send_plr.name)
 
137
               )
 
138
               run(wait_for_established_route, route_descr)
 
139
            else
 
140
               -- Only use ware types that both sending and receiving player can use
 
141
               local wares = route_descr.wares
 
142
 
 
143
               -- We start counting at 0 so that we can use the modulo (%) operator
 
144
               -- for going round robin
 
145
               local last_ware_index = 0;
 
146
 
 
147
               -- Warp the next available ware, going round robin
 
148
               local empty_warehouse_guard = #wares
 
149
               local warp_index = last_ware_index
 
150
               while empty_warehouse_guard > 0 do
 
151
                  -- Index shift, because Lua tables start counting at 1
 
152
                  local ware_to_warp = wares[warp_index + 1]
 
153
                  if send_whf.immovable:get_wares(ware_to_warp) > 0 then
 
154
                     print("NOCOM Route " .. idx .. " (" .. send_whf.x .. ", " .. send_whf.y .. ") warping ware " .. ware_to_warp ..  ": " .. send_plr.name .. " -> " .. recv_plr.name)
 
155
                     send_whf.immovable:set_wares(ware_to_warp, send_whf.immovable:get_wares(ware_to_warp) - 1)
 
156
                     recv_whf.immovable:set_wares(
 
157
                        ware_to_warp, recv_whf.immovable:get_wares(ware_to_warp) + 1
 
158
                     )
 
159
                     points[recv_plr.team] = points[recv_plr.team] + route_descr.value
 
160
                     break
 
161
                  end
 
162
                  warp_index = (warp_index + 1) % #wares;
 
163
                  empty_warehouse_guard = empty_warehouse_guard - 1
 
164
               end
 
165
               -- Next round robin index
 
166
               last_ware_index = (last_ware_index + 1) % #wares;
 
167
            end
69
168
         end
70
169
      end
71
 
      if #wn > 0 then
72
 
         local ware_to_warp = wn[math.random(#wn)]
73
 
         send_whf.immovable:set_wares(ware_to_warp, wares[ware_to_warp] - 1)
74
 
         recv_whf.immovable:set_wares(
75
 
            ware_to_warp, recv_whf.immovable:get_wares(ware_to_warp) + 1
76
 
         )
77
 
         points[recv_plr.team] = points[recv_plr.team] + route_descr.value
78
 
      end
79
170
   end
80
171
end
81
172
 
82
173
function wait_for_established_route(route_descr)
83
174
   local receiving_wh, sending_wh
84
 
   while 1 do
 
175
   route_descr.sending_warehouse = nil
 
176
   route_descr.receiving_warehouse = nil
 
177
   route_descr.wares = {}
 
178
 
 
179
   while true do
85
180
      receiving_wh = find_warehouse(route_descr.recv)
86
181
      sending_wh = find_warehouse(route_descr.send)
87
 
      if receiving_wh and sending_wh and receiving_wh.owner.team == sending_wh.owner.team then break end
 
182
      if receiving_wh and sending_wh and receiving_wh.owner.team == sending_wh.owner.team then
 
183
         route_descr.sending_warehouse = sending_wh
 
184
         route_descr.receiving_warehouse = receiving_wh
 
185
 
 
186
         -- Collect ware types that both sending and receiving player can use
 
187
         for idx,ware in pairs(sending_wh.owner.tribe.wares) do
 
188
            if receiving_wh.owner.tribe:has_ware(ware.name) then
 
189
               table.insert(route_descr.wares, ware.name)
 
190
            end
 
191
         end
 
192
         break
 
193
      end
88
194
      sleep(7138)
89
195
   end
90
196
 
104
210
   send_message(sending_wh.owner, _"Status",
105
211
      smuggling_route_established_sender:format(points), {popup=true, field=sending_wh.fields[1]}
106
212
   )
107
 
 
108
 
   run(do_smuggling, route_descr, receiving_wh.owner, sending_wh.owner, receiving_wh.fields[1], sending_wh.fields[1])
109
213
end