Advertisement
WarPie90

Solving doors in RS by distance to anchor

Aug 27th, 2023 (edited)
2,289
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 5.33 KB | None | 0 0
  1. program new;
  2. {$DEFINE SRL_USE_REMOTEINPUT}
  3. {$I SRL/osr.simba}
  4.  
  5. (*
  6.   This solution assumes that you have an anchor that is either perpendicular or parallel to the door
  7.   (it's either in the angle of facing the closed door, or it's facing the open door)
  8.  
  9.      //
  10.     //|
  11.    //||
  12.   //_||______
  13.  //|  __  __  |
  14.  ##| |  ||  | |                            
  15.  ##| |  ||  | |                              _
  16.  ##| |__||__| |                             (_)
  17.  ##|  __  __()|     Parallel example      <--|-->
  18.  ##| |  ||  | | <-- Door --- Anchor -->  _   |   _
  19.  ##| |  ||  | |                         `\__/ \__/`
  20.  ##| |  ||  | |                           `-. .-´
  21.  ##| |__||__| |                              '
  22.  ##|__________|                          
  23.  //
  24.  
  25.   Concept:
  26.     Find the door and find some object which we call anchor, in this example I'm using a black ledger.
  27.    
  28.     Now we can use the distance from the ledger to the door to determine if the door is open.
  29.     The door state can be defined as
  30.       If the distance between Door and Anchor is less than a set value, the state of the door is
  31.       > Open if:   The anchor is parallel to the closed door (parallel meaning to the direction you enter)
  32.       > Closed if: The anchor is perpendicular to the closed door (reverse)
  33.    
  34.     Written example, assuming the anchor's location is parallel to the direction you enter through the door.
  35.    
  36.       An open door could have a distance between 18..19,
  37.       while a closed door could have a distance between 21..22.
  38.       We can therefor state the cutoff / middle between the two states as approximately 20.
  39.  
  40.     How you choose to attack it is up to you. So long as you can generate varying distance-value
  41.     between states to something else (an anchor), you can use this concept.
  42. *)
  43. {$DEFINE DOOR_DEBUG_DISTANCE}
  44.  
  45. type
  46.   EDoorState = (dsUndefined, dsOpen, dsClosed);
  47.  
  48. var
  49.   RSW: TRSWalker;
  50.  
  51. (*
  52.   Input:
  53.   Door:   The TPA of the door
  54.   Anchor: The TPA of the Anchor
  55.   Split:  This is the cutoffpoint between a closed and an open door
  56.   Inverse: If the door is not parallel then this should be True (auto False)
  57.   UseMean: Mean may give less accurate distance value, so it may result in (more) false-positives
  58.            But it may be less prone to noisy pixels from color-finding.  
  59.            
  60.   Return `dsOpen` if the door is open based on given input data
  61.   if the method fails it will return `dsUndefined`, otherwise dsFalse; `ds` is short for doorstate
  62. *)
  63. function IsDoorOpen(Door, Anchor: TPointArray; Split: Double; Inverse: Boolean = False; UseMean: Boolean = False): EDoorState;
  64. var
  65.   p,q: Vector3;
  66.   me,ptAnchor,ptDoor: TPoint;
  67.   ATPA: T2DPointArray;
  68. begin
  69.   // ensure no failure
  70.   if (Length(Anchor) = 0) or (length(Door) = 0) then Exit(dsUndefined);
  71.  
  72.   // find the point in the ledger that's closest to the door and vice versa
  73.   // alternatively we could just use the mean and skip this step in many cases.
  74.   if not UseMean then begin
  75.     anchor.Sort(door.Mean());
  76.     ptAnchor := anchor[0];
  77.     door.Sort(ptAnchor);
  78.     ptDoor := door[0];
  79.   end else begin
  80.     ptAnchor := anchor.Mean();
  81.     ptDoor   := door.Mean();
  82.   end;
  83.  
  84.   // convert to minimap to work in 2d space, so distance is always the same no matter position,
  85.   // camera angle and zoom.
  86.   p := MainScreen.PointToMM(ptDoor);
  87.   q := MainScreen.PointToMM(ptAnchor);
  88.  
  89.   {$IFDEF DOOR_DEBUG_DISTANCE}
  90.   // write the distance output for debugging
  91.   // this is to get the distance (number) between the anchor and door (in both states, open and closed)
  92.   WriteLn p.Distance(q);
  93.   {$ENDIF}
  94.  
  95.   if (p.Distance(q) <= Split) xor inverse then
  96.     Exit(dsOpen)
  97.   else
  98.     Exit(dsClosed);
  99. end;
  100.  
  101. (*
  102.   You can use your own methods to find doors and anchors. This is just as an example.
  103. *)
  104. procedure FindDoorAndAnchor(WorldPos: TPoint; out Door, Anchor: TPointArray);
  105. var
  106.   ledger: TPointArray;
  107.   ATPA: T2DPointArray;
  108.   AnchorSearchBox, DoorSearchBox: TBox;
  109. begin
  110.   // rough area of where the anchor and door is (world map coordinates)
  111.   AnchorSearchBox := RSW.GetTileMSEx(WorldPos, [2656, 2734]).Expand(10).Bounds();
  112.   DoorSearchBox   := RSW.GetTileMSEx(WorldPos, [2646, 2754]).Expand(30).Bounds();
  113.  
  114.   DoorSearchBox.LimitTo(MainScreen.Bounds);
  115.   AnchorSearchBox.LimitTo(MainScreen.Bounds);
  116.  
  117.   // find the anchor, and the door tpas (regular color-data from ACA)
  118.   srl.FindColors(anchor, CTS2(1776416, 1,  0.01, 0.01), AnchorSearchBox);
  119.   srl.FindColors(door,   CTS2(1993096, 13, 0.08, 1.02), DoorSearchBox);
  120.  
  121.   // basic noise filtering
  122.   ATPA := door.Erode(1).Grow(1).Cluster(2);
  123.   door := ATPA.Biggest();
  124.  
  125.   // basic noise filtering, small object, so I dont erode noise.
  126.   ATPA := anchor.Cluster(2);
  127.   anchor := ATPA.Biggest();
  128. end;
  129.  
  130. (*
  131.   Test run:
  132. *)
  133. var
  134.   door,anchor: TPointArray;
  135. begin
  136.   RSW.Setup([[2656-500, 2734-500, 2656+500, 2734+500]]);
  137.   RSClient.Image.SetFontSize(15);
  138.   RSClient.Image.SetFontAntialiasing(False);
  139.   WriteLn RSW.GetMyPos();
  140.  
  141.   while True do
  142.   begin
  143.     MM2MS.ZoomLevel := Options.GetZoomLevel();
  144.     FindDoorAndAnchor(RSW.GetMyPos(), door, anchor);
  145.  
  146.     RSClient.Image.Clear();
  147.     case IsDoorOpen(Door, Anchor, 19.4, False, False) of
  148.       dsUndefined: ;
  149.       dsOpen:   RSClient.Image.DrawText('Open', Door.Mean(), 1);
  150.       dsClosed: RSClient.Image.DrawText('Closed', Door.Mean(), 1);
  151.     end;
  152.   end;
  153. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement