fill.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /* $Id$
  2. * MegaZeux
  3. *
  4. * Copyright (C) 1996 Greg Janson
  5. * Copyright (C) 1998 Matthew D. Williams - dbwilli@scsn.net
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. /* Fill function. */
  22. #include "beep.h"
  23. #include "idarray.h"
  24. #include "fill.h"
  25. #include "roballoc.h"
  26. #include "error.h"
  27. #include "data.h"
  28. /* Pseudo-code algorithm-
  29. (MATCHES means that the id/color at that id is what we are
  30. filling over. PLACING includes deleting the old, deleting programs,
  31. and copying current program, if any. The STACK is an array for
  32. keeping track of areas we need to continue filling at, and the
  33. direction to fill in at that point. A PUSH onto the STACK moves the
  34. stack pointer up one and inserts info, unless the STACK is full, in
  35. which case the operation is cancelled. A STACK size of about 500
  36. elements is usally enough for a fairly complex 100 by 100 section.)
  37. (Note that the usual Robot#0 code is NOT performed- If current is a
  38. robot, it is already #0 and must stay that way for proper filling.)
  39. 1) Initialize fill stack and record what we are filling over.
  40. 2) Push current position going left.
  41. 3) Loop:
  42. 1) Take top element off of stack.
  43. 1.5) Verify it still matches (in case another branch got here)
  44. 2) Start at noted position. Set ABOVE_MATCH and BELOW_MATCH to 0.
  45. 3a) If direction is left, push onto stack-
  46. 1) Id above, going left, if matches. Set ABOVE_MATCH to 1.
  47. 2) Id below, going left, if matches. Set BELOW_MATCH to 1.
  48. 3) Id to the right, going right, if matches.
  49. 3b) If direction is right, push nothing.
  50. 4) Place at position.
  51. 6) Note what is above- If it DOESN'T match, set ABOVE_MATCH to 0.
  52. 7) Note what is below- If it DOESN'T match, set BELOW_MATCH to 0.
  53. 8) If above DOES match and ABOVE_MATCH is 0-
  54. 1) Push onto stack Id above, going left.
  55. 2) Set ABOVE_MATCH to 1.
  56. 9) If below DOES match and BELOW_MATCH is 0-
  57. 1) Push onto stack Id below, going left.
  58. 2) Set BELOW_MATCH to 1.
  59. 10) Go one step in direction. (left/right)
  60. 11) If position matches, jump to #4.
  61. 12) If any elements remain on stack, loop.
  62. 4) Done.
  63. */
  64. //Structure for one element of the stack
  65. struct StackElem {
  66. unsigned int x:9;
  67. unsigned int y:8;
  68. signed int dir:2;//-1=Left, 1=Right.
  69. };
  70. typedef struct StackElem StackElem;
  71. //The stack
  72. #define STACK_SIZE 500
  73. int stack_pos;//Current element. -1=empty.
  74. StackElem stack[STACK_SIZE+1];
  75. //with_param is assumed to be the current param, so is changed to 0 when
  76. //appropriate for robots/etc. (according to with_id)
  77. void fill_area(int x,int y,int with_id,int with_color,int &with_param) {
  78. int fover_id,fover_color,t1;//What we are filling over
  79. char dir,above_match,below_match;
  80. if(with_id==127) return;//Cannot fill w/player
  81. if(level_id[x+y*max_bxsiz]==127) return;//Cannot fill over player
  82. if((level_id[x+y*max_bxsiz]==with_id)&&(level_color[x+y*max_bxsiz]==with_color)) {
  83. if(with_id==100) return;//Strange... ?
  84. //We are trying to fill with a similar color and id. First we
  85. //must fill instead with ids of 100, same color/param.
  86. fill_area(x,y,100,with_color,with_param);
  87. //Now we just fill normally.
  88. }
  89. //1) Initialize fill stack and record what we are filling over.
  90. fover_id=level_id[x+y*max_bxsiz];
  91. fover_color=level_color[x+y*max_bxsiz];
  92. stack_pos=0;
  93. //2) Push current position going left.
  94. stack[0].x=x;
  95. stack[0].y=y;
  96. stack[0].dir=-1;
  97. //3) Loop:
  98. do {
  99. // 1) Take top element off of stack.
  100. x=stack[stack_pos].x;
  101. y=stack[stack_pos].y;
  102. dir=stack[stack_pos--].dir;
  103. // 1.5) Verify it matches
  104. if((level_id[x+y*max_bxsiz]!=fover_id)||
  105. (level_color[x+y*max_bxsiz]!=fover_color))
  106. continue;
  107. // 2) Start at noted position. Set ABOVE_MATCH and BELOW_MATCH to 0.
  108. above_match=below_match=0;
  109. // 3a) If direction is left, push onto stack-
  110. if(dir==-1) {
  111. // 1) Id above, going left, if matches. Set ABOVE_MATCH to 1.
  112. if(y>0) {
  113. if((level_id[x+(y-1)*max_bxsiz]==fover_id)&&
  114. (level_color[x+(y-1)*max_bxsiz]==fover_color)) {
  115. if(stack_pos<STACK_SIZE) {
  116. stack[++stack_pos].x=x;
  117. stack[stack_pos].y=y-1;
  118. stack[stack_pos].dir=-1;
  119. above_match=1;
  120. }
  121. }
  122. }
  123. // 2) Id below, going left, if matches. Set BELOW_MATCH to 1.
  124. if(y<(board_ysiz-1)) {
  125. if((level_id[x+(y+1)*max_bxsiz]==fover_id)&&
  126. (level_color[x+(y+1)*max_bxsiz]==fover_color)) {
  127. if(stack_pos<STACK_SIZE) {
  128. stack[++stack_pos].x=x;
  129. stack[stack_pos].y=y+1;
  130. stack[stack_pos].dir=-1;
  131. below_match=1;
  132. }
  133. }
  134. }
  135. // 3) Id to the right, going right, if matches.
  136. if(x<(board_xsiz-1)) {
  137. if((level_id[x+1+y*max_bxsiz]==fover_id)&&
  138. (level_color[x+1+y*max_bxsiz]==fover_color)) {
  139. if(stack_pos<STACK_SIZE) {
  140. stack[++stack_pos].x=x+1;
  141. stack[stack_pos].y=y;
  142. stack[stack_pos].dir=1;
  143. }
  144. }
  145. }
  146. }
  147. // 3b) If direction is right, push nothing.
  148. // 4) Place at position.
  149. num_four:
  150. // [delete at position, copying current to 0 if neccesary]
  151. if(fover_id==122) {//(sensor)
  152. t1=level_param[x+y*max_bxsiz];
  153. // if((with_id==122)&&(with_param==t1)) {
  154. // copy_sensor(0,t1);
  155. // with_param=0;
  156. // }
  157. clear_sensor(t1);
  158. }
  159. else if((fover_id==123)||(fover_id==124)) {//(robot)
  160. t1=level_param[x+y*max_bxsiz];
  161. // if(((with_id==123)||(with_id==124))&&(with_param==t1)) {
  162. // copy_robot(0,t1);
  163. // with_param=0;
  164. // }
  165. clear_robot(t1);
  166. }
  167. else if((fover_id==125)||(fover_id==126)) {//(scroll)
  168. t1=level_param[x+y*max_bxsiz];
  169. // if(((with_id==125)||(with_id==126))&&(with_param==t1)) {
  170. // copy_scroll(0,t1);
  171. // with_param=0;
  172. // }
  173. clear_scroll(t1);
  174. }
  175. id_remove_top(x,y);
  176. // [place at position, copying current if neccesary]
  177. if(with_id==122) {//(sensor)
  178. if(!(t1=find_sensor())) {
  179. error("No available sensors",1,24,current_pg_seg,0x0801);
  180. return;//Fill aborted
  181. }
  182. copy_sensor(t1,with_param);
  183. // if(with_param==0) clear_sensor(0);
  184. // with_param=t1;
  185. id_place(x,y,with_id,with_color,t1);
  186. }
  187. else if((with_id==123)||(with_id==124)) {//(robot)
  188. if(!(t1=find_robot())) {
  189. error("No available robots",1,24,current_pg_seg,0x0901);
  190. return;//Fill aborted
  191. }
  192. if(copy_robot(t1,with_param)) {
  193. robots[t1].used=0;
  194. error("Out of robot memory",1,21,current_pg_seg,0x0502);
  195. return;//Fill aborted
  196. }
  197. // if(with_param==0) clear_robot(0);
  198. // with_param=t1;
  199. id_place(x,y,with_id,with_color,t1);
  200. }
  201. else if((with_id==125)||(with_id==126)) {//(scroll)
  202. if(!(t1=find_scroll())) {
  203. error("No available scrolls",1,24,current_pg_seg,0x0A01);
  204. return;//Fill aborted
  205. }
  206. if(copy_scroll(t1,with_param)) {
  207. robots[t1].used=0;
  208. error("Out of robot memory",1,21,current_pg_seg,0x0503);
  209. return;//Fill aborted
  210. }
  211. // if(with_param==0) clear_scroll(0);
  212. // with_param=t1;
  213. id_place(x,y,with_id,with_color,t1);
  214. }
  215. else id_place(x,y,with_id,with_color,with_param);
  216. // 6) Note what is above- If it DOESN'T match, set ABOVE_MATCH to 0.
  217. if(y>0) {
  218. if((level_id[x+(y-1)*max_bxsiz]!=fover_id)||
  219. (level_color[x+(y-1)*max_bxsiz]!=fover_color))
  220. above_match=0;
  221. }
  222. // 7) Note what is below- If it DOESN'T match, set BELOW_MATCH to 0.
  223. if(y<(board_ysiz-1)) {
  224. if((level_id[x+(y+1)*max_bxsiz]!=fover_id)||
  225. (level_color[x+(y+1)*max_bxsiz]!=fover_color))
  226. below_match=0;
  227. }
  228. // 8) If above DOES match and ABOVE_MATCH is 0-
  229. if(y>0) {
  230. if((level_id[x+(y-1)*max_bxsiz]==fover_id)&&
  231. (level_color[x+(y-1)*max_bxsiz]==fover_color)&&
  232. (above_match==0)) {
  233. // 1) Push onto stack Id above, going left.
  234. if(stack_pos<STACK_SIZE) {
  235. stack[++stack_pos].x=x;
  236. stack[stack_pos].y=y-1;
  237. stack[stack_pos].dir=-1;
  238. }
  239. // 2) Set ABOVE_MATCH to 1.
  240. above_match=1;
  241. }
  242. }
  243. // 9) If below DOES match and BELOW_MATCH is 0-
  244. if(y<(board_ysiz-1)) {
  245. if((level_id[x+(y+1)*max_bxsiz]==fover_id)&&
  246. (level_color[x+(y+1)*max_bxsiz]==fover_color)&&
  247. (below_match==0)) {
  248. // 1) Push onto stack Id below, going left.
  249. if(stack_pos<STACK_SIZE) {
  250. stack[++stack_pos].x=x;
  251. stack[stack_pos].y=y+1;
  252. stack[stack_pos].dir=-1;
  253. }
  254. // 2) Set BELOW_MATCH to 1.
  255. below_match=1;
  256. }
  257. }
  258. // 10) Go one step in direction. (left/right)
  259. x+=dir;
  260. // 11) If position matches, jump to #4.
  261. if((x>=0)&&(x<board_xsiz))
  262. if((level_id[x+y*max_bxsiz]==fover_id)&&
  263. (level_color[x+y*max_bxsiz]==fover_color))
  264. goto num_four;
  265. // 12) If any elements remain on stack, loop.
  266. } while(stack_pos>=0);
  267. //4) Done.
  268. }
  269. //with_id is, of course, really considered the parameter in the editor.
  270. void fill_overlay(int x,int y,int with_id,int with_color) {
  271. int fover_id,fover_color;//What we are filling over
  272. char dir,above_match,below_match;
  273. //1) Initialize fill stack and record what we are filling over.
  274. fover_id=overlay[x+y*max_bxsiz];
  275. fover_color=overlay_color[x+y*max_bxsiz];
  276. if((fover_id==with_id)&&(fover_color==with_color)) return;
  277. stack_pos=0;
  278. //2) Push current position going left.
  279. stack[0].x=x;
  280. stack[0].y=y;
  281. stack[0].dir=-1;
  282. //3) Loop:
  283. do {
  284. // 1) Take top element off of stack.
  285. x=stack[stack_pos].x;
  286. y=stack[stack_pos].y;
  287. dir=stack[stack_pos--].dir;
  288. // 2) Start at noted position. Set ABOVE_MATCH and BELOW_MATCH to 0.
  289. above_match=below_match=0;
  290. // 3a) If direction is left, push onto stack-
  291. if(dir==-1) {
  292. // 1) Id above, going left, if matches. Set ABOVE_MATCH to 1.
  293. if(y>0) {
  294. if((overlay[x+(y-1)*max_bxsiz]==fover_id)&&
  295. (overlay_color[x+(y-1)*max_bxsiz]==fover_color)) {
  296. if(stack_pos<STACK_SIZE) {
  297. stack[++stack_pos].x=x;
  298. stack[stack_pos].y=y-1;
  299. stack[stack_pos].dir=-1;
  300. above_match=1;
  301. }
  302. }
  303. }
  304. // 2) Id below, going left, if matches. Set BELOW_MATCH to 1.
  305. if(y<(board_ysiz-1)) {
  306. if((overlay[x+(y+1)*max_bxsiz]==fover_id)&&
  307. (overlay_color[x+(y+1)*max_bxsiz]==fover_color)) {
  308. if(stack_pos<STACK_SIZE) {
  309. stack[++stack_pos].x=x;
  310. stack[stack_pos].y=y+1;
  311. stack[stack_pos].dir=-1;
  312. below_match=1;
  313. }
  314. }
  315. }
  316. // 3) Id to the right, going right, if matches.
  317. if(x<(board_xsiz-1)) {
  318. if((overlay[x+1+y*max_bxsiz]==fover_id)&&
  319. (overlay_color[x+1+y*max_bxsiz]==fover_color)) {
  320. if(stack_pos<STACK_SIZE) {
  321. stack[++stack_pos].x=x+1;
  322. stack[stack_pos].y=y;
  323. stack[stack_pos].dir=1;
  324. }
  325. }
  326. }
  327. }
  328. // 3b) If direction is right, push nothing.
  329. // 4) Place at position.
  330. num_four:
  331. overlay[x+y*max_bxsiz]=with_id;
  332. overlay_color[x+y*max_bxsiz]=with_color;
  333. // 6) Note what is above- If it DOESN'T match, set ABOVE_MATCH to 0.
  334. if(y>0) {
  335. if((overlay[x+(y-1)*max_bxsiz]!=fover_id)||
  336. (overlay_color[x+(y-1)*max_bxsiz]!=fover_color))
  337. above_match=0;
  338. }
  339. // 7) Note what is below- If it DOESN'T match, set BELOW_MATCH to 0.
  340. if(y<(board_ysiz-1)) {
  341. if((overlay[x+(y+1)*max_bxsiz]!=fover_id)||
  342. (overlay_color[x+(y+1)*max_bxsiz]!=fover_color))
  343. below_match=0;
  344. }
  345. // 8) If above DOES match and ABOVE_MATCH is 0-
  346. if(y>0) {
  347. if((overlay[x+(y-1)*max_bxsiz]==fover_id)&&
  348. (overlay_color[x+(y-1)*max_bxsiz]==fover_color)&&
  349. (above_match==0)) {
  350. // 1) Push onto stack Id above, going left.
  351. if(stack_pos<STACK_SIZE) {
  352. stack[++stack_pos].x=x;
  353. stack[stack_pos].y=y-1;
  354. stack[stack_pos].dir=-1;
  355. }
  356. // 2) Set ABOVE_MATCH to 1.
  357. above_match=1;
  358. }
  359. }
  360. // 9) If below DOES match and BELOW_MATCH is 0-
  361. if(y<(board_ysiz-1)) {
  362. if((overlay[x+(y+1)*max_bxsiz]==fover_id)&&
  363. (overlay_color[x+(y+1)*max_bxsiz]==fover_color)&&
  364. (below_match==0)) {
  365. // 1) Push onto stack Id below, going left.
  366. if(stack_pos<STACK_SIZE) {
  367. stack[++stack_pos].x=x;
  368. stack[stack_pos].y=y+1;
  369. stack[stack_pos].dir=-1;
  370. }
  371. // 2) Set BELOW_MATCH to 1.
  372. below_match=1;
  373. }
  374. }
  375. // 10) Go one step in direction. (left/right)
  376. x+=dir;
  377. // 11) If position matches, jump to #4.
  378. if((x>=0)&&(x<board_xsiz))
  379. if((overlay[x+y*max_bxsiz]==fover_id)&&
  380. (overlay_color[x+y*max_bxsiz]==fover_color))
  381. goto num_four;
  382. // 12) If any elements remain on stack, loop.
  383. } while(stack_pos>=0);
  384. //4) Done.
  385. }