The use of database "sets" rather than "functions"
First goal in thinking in SQL (or thinking in sets) is to get rid of IF statements and Loops (or cursors).  So for your 2nd function this is much better:

CREATE FUNCTION dbo.funcSellIdByPropId
(
@PropertyId AS INT
)
RETURNS INT
AS
BEGIN
  DECLARE @ID AS INT

  SELECT @ID = COALESCE(MATRIXAGENCYPROPERTY.AgencyId, PRIVATESELLERS.id, 0)
  FROM  MATRIXAGENCYPROPERTY, PRIVATESELLERS
  WHERE MATRIXAGENCYPROPERTY.PropertyId = @PropertyId AND 
        PRIVATESELLERS.PropertyId = @PropertyId

  RETURN @ID
END


This select can now be implemented as a view and then joined to any other select statement instead of calling a function.



For the 3rd function you could implement a view like this:

SELECT
  PropertyId 
  ROW_NUMBER() OVER (PARTITION BY PropertyId ORDER BY weight DESC) AS [imgnum],
  image
FROM PROPERTYGALLERY


Now you can join on this view by PropertyId and imgnum instead of calling a function



For your first function take a look at this answer I posted on SO.  Using the XML generator like this is considered the fastest way to create a comma separated list in MS SQL.  Like the others examples I've given here, this technique could be used in a view to create a list of comma separated values partitioned by PropertyId



The key to both of these solutions is thinking in sets.  Instead of solving one problem (as the function does) they solve all the problems.  Then when you join to these queries you limit to just the data you need.  

SQL Engines love this -- their optimizers are designed to make this kind of process work really fast.



Detailed Example (see comments)

First create the view:

-- MATRIXAGENCYPROPERTY.AgencyId and PRIVATESELLERS.id are mutually exclusive.  
-- Grab all of them with their PropertyID
CREATE VIEW SellIDByPropertyID(ID, PropertyID) AS
(
  SELECT AgencyId, PropertyID  
  FROM MATRIXAGENCYPROPERTY
  UNION ALL
  SELECT ID, PropertyId
  FROM PRIVATESELLERS
)


Now we can integrate it into your original query:

SELECT 
   ...
   dbo.funcSellIdByPropId(T0.id) as SellerId,  
   ...
FROM T0 
   ...


To

SELECT 
   ...
   S2P.ID,  
   ...
FROM T0 
JOIN SellIDByPropertyID S2P ON T0.id = S2P.PropertyId
   ...


Why this works

Once again the key to understanding is to think in sets.  If you just think about a single record a reaction might be the original SP would be faster because if it is a agency property it will only do one select and the IF statement will stop the 2nd select from being run giving a speed advantage. 


  Side note: often on SQL Engines a select statement will be slower than
  an if statement so even the above assumption is wrong, but I'll ignore
  that for now.


However, this goes out the window as soon as we look at the set.  If the original query is returning more than one record -- say N records then with the original function call we have the overhead of N function calls + N Selects + N/2 Selects (if half are not agencies).  With the view we have just 2 Selects.  Clearly O(3.5N) > O(2)